Merge pull request #17280 from xedin/rdar-41141944-4.2

[4.2][TypeChecker] When formatting witness type for diagnostics don't assu…
diff --git a/include/swift/IDE/DigesterEnums.def b/include/swift/IDE/DigesterEnums.def
index 26fb0cb..bb0cfc9 100644
--- a/include/swift/IDE/DigesterEnums.def
+++ b/include/swift/IDE/DigesterEnums.def
@@ -80,6 +80,7 @@
 NODE_ANNOTATION_CHANGE_KIND(SimpleStringRepresentableUpdate)
 NODE_ANNOTATION_CHANGE_KIND(SimpleOptionalStringRepresentableUpdate)
 NODE_ANNOTATION_CHANGE_KIND(TypeAliasDeclToRawRepresentable)
+NODE_ANNOTATION_CHANGE_KIND(RevertTypeAliasDeclToRawRepresentable)
 
 NODE_ANNOTATION_CHANGE_KIND(RevertDictionaryKeyUpdate)
 NODE_ANNOTATION_CHANGE_KIND(RevertOptionalDictionaryKeyUpdate)
diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp
index fc58c94..315e401 100644
--- a/lib/ClangImporter/ImportType.cpp
+++ b/lib/ClangImporter/ImportType.cpp
@@ -974,8 +974,8 @@
           // Convert the type arguments.
           for (auto typeArg : typeArgs) {
             Type importedTypeArg = Impl.importTypeIgnoreIUO(
-                typeArg, ImportTypeKind::BridgedValue, AllowNSUIntegerAsInt,
-                Bridging, OTK_None);
+                typeArg, ImportTypeKind::ObjCCollectionElement,
+                AllowNSUIntegerAsInt, Bridging, OTK_None);
             if (!importedTypeArg) {
               importedTypeArgs.clear();
               break;
@@ -1102,7 +1102,7 @@
   case ImportTypeKind::CFUnretainedOutParameter:
   case ImportTypeKind::Property:
   case ImportTypeKind::PropertyWithReferenceSemantics:
-  case ImportTypeKind::BridgedValue:
+  case ImportTypeKind::ObjCCollectionElement:
   case ImportTypeKind::Typedef:
     return true;
   }
@@ -1116,7 +1116,7 @@
   case ImportTypeKind::Abstract:
   case ImportTypeKind::Typedef:
   case ImportTypeKind::Value:
-  case ImportTypeKind::BridgedValue:
+  case ImportTypeKind::ObjCCollectionElement:
   case ImportTypeKind::Variable:
   case ImportTypeKind::Result:
   case ImportTypeKind::Pointee:
@@ -1283,14 +1283,29 @@
   }
 
   // SwiftTypeConverter turns block pointers into @convention(block) types.
-  // In a bridgeable context, or in the direct structure of a typedef,
-  // we would prefer to instead use the default Swift convention.
+  // In some contexts, we bridge them to use the Swift function type
+  // representation. This includes typedefs of block types, which use the
+  // Swift function type representation.
   if (hint == ImportHint::Block) {
     if (canBridgeTypes(importKind)) {
+      // Determine the function type representation we need.
+      //
+      // For Objective-C collection arguments, we cannot bridge from a block
+      // to a Swift function type, so force the block representation. Normally
+      // the mapped type will have a block representation (making this a no-op),
+      // but in cases where the Clang type was written as a typedef of a
+      // block type, that typedef will have a Swift function type
+      // representation. This code will then break down the imported type
+      // alias and produce a function type with block representation.
+      auto requiredFunctionTypeRepr = FunctionTypeRepresentation::Swift;
+      if (importKind == ImportTypeKind::ObjCCollectionElement) {
+        requiredFunctionTypeRepr = FunctionTypeRepresentation::Block;
+      }
+
       auto fTy = importedType->castTo<FunctionType>();
       FunctionType::ExtInfo einfo = fTy->getExtInfo();
-      if (einfo.getRepresentation() != FunctionTypeRepresentation::Swift) {
-        einfo = einfo.withRepresentation(FunctionTypeRepresentation::Swift);
+      if (einfo.getRepresentation() != requiredFunctionTypeRepr) {
+        einfo = einfo.withRepresentation(requiredFunctionTypeRepr);
         importedType = fTy->withExtInfo(einfo);
       }
     }
diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h
index 6855643..324fb81 100644
--- a/lib/ClangImporter/ImporterImpl.h
+++ b/lib/ClangImporter/ImporterImpl.h
@@ -108,8 +108,8 @@
   /// \brief Import the type of a literal value.
   Value,
 
-  /// \brief Import the type of a literal value that can be bridged.
-  BridgedValue,
+  /// \brief Import the type of an Objective-C generic argument.
+  ObjCCollectionElement,
 
   /// \brief Import the declared type of a variable.
   Variable,
diff --git a/lib/Migrator/APIDiffMigratorPass.cpp b/lib/Migrator/APIDiffMigratorPass.cpp
index 4189e66..18c1fe7 100644
--- a/lib/Migrator/APIDiffMigratorPass.cpp
+++ b/lib/Migrator/APIDiffMigratorPass.cpp
@@ -275,6 +275,8 @@
 
   std::vector<APIDiffItem*> getRelatedDiffItems(ValueDecl *VD) {
     std::vector<APIDiffItem*> results;
+    if (!VD)
+      return results;
     auto addDiffItems = [&](ValueDecl *VD) {
       llvm::SmallString<64> Buffer;
       llvm::raw_svector_ostream OS(Buffer);
@@ -921,9 +923,66 @@
     insertHelperFunction(Kind, RawType, NewAttributeType, FromString, WrapTarget);
   }
 
+  bool hasRevertRawRepresentableChange(ValueDecl *VD) {
+    for (auto Item: getRelatedDiffItems(VD)) {
+      if (auto *CI = dyn_cast<CommonDiffItem>(Item)) {
+        if (CI->DiffKind ==
+              NodeAnnotation::RevertTypeAliasDeclToRawRepresentable)
+          return true;
+      }
+    }
+    return false;
+  }
+
+  bool handleRevertRawRepresentable(Expr *E) {
+    // Change attribute.rawValue to attribute
+    if (auto *MRE = dyn_cast<MemberRefExpr>(E)) {
+      auto Found = false;
+      if (auto *Base = MRE->getBase()) {
+        if (hasRevertRawRepresentableChange(Base->getType()->getAnyNominal())) {
+          Found = true;
+        }
+      }
+      if (!Found)
+        return false;
+      auto NL = MRE->getNameLoc().getStartLoc();
+      auto DL = MRE->getDotLoc();
+      if (NL.isInvalid() || DL.isInvalid())
+        return false;
+      CharSourceRange Range = Lexer::getCharSourceRangeFromSourceRange(SM, {DL, NL});
+      if (Range.str() == ".rawValue") {
+        Editor.remove(Range);
+        return true;
+      }
+    }
+
+    // Change attribute(rawValue: "value") to "value"
+    if (auto *CE = dyn_cast<CallExpr>(E)) {
+      auto Found = false;
+      if (auto *CRC = dyn_cast<ConstructorRefCallExpr>(CE->getFn())) {
+        if (auto *TE = dyn_cast<TypeExpr>(CRC->getBase())) {
+          if (hasRevertRawRepresentableChange(TE->getInstanceType()->getAnyNominal()))
+            Found = true;
+        }
+      }
+      if (!Found)
+        return false;
+      std::vector<CallArgInfo> AllArgs =
+        getCallArgInfo(SM, CE->getArg(), LabelRangeEndAt::LabelNameOnly);
+      if (AllArgs.size() == 1 && AllArgs.front().LabelRange.str() == "rawValue") {
+        Editor.replace(CE->getSourceRange(), Lexer::getCharSourceRangeFromSourceRange(SM,
+          AllArgs.front().ArgExp->getSourceRange()).str());
+        return true;
+      }
+    }
+    return false;
+  }
+
   bool walkToExprPre(Expr *E) override {
     if (E->getSourceRange().isInvalid())
       return false;
+    if (handleRevertRawRepresentable(E))
+      return false;
     if (handleQualifiedReplacement(E))
       return false;
     if (handleAssignDestMigration(E))
diff --git a/stdlib/public/core/Bool.swift b/stdlib/public/core/Bool.swift
index 9b7719e..155cba3 100644
--- a/stdlib/public/core/Bool.swift
+++ b/stdlib/public/core/Bool.swift
@@ -43,6 +43,7 @@
 ///         print(i)
 ///         i -= 1
 ///     }
+///     // error: 'Int' is not convertible to 'Bool'
 ///
 /// The correct approach in Swift is to compare the `i` value with zero in the
 /// `while` statement.
diff --git a/stdlib/public/core/Dictionary.swift b/stdlib/public/core/Dictionary.swift
index 197dd8e..d9d9428 100644
--- a/stdlib/public/core/Dictionary.swift
+++ b/stdlib/public/core/Dictionary.swift
@@ -294,7 +294,7 @@
 /// dictionary called `interestingNumbers` with string keys and values that
 /// are integer arrays, then sorts each array in-place in descending order.
 ///
-///     var interestingNumbers = ["primes": [2, 3, 5, 7, 11, 13, 15],
+///     var interestingNumbers = ["primes": [2, 3, 5, 7, 11, 13, 17],
 ///                               "triangular": [1, 3, 6, 10, 15, 21, 28],
 ///                               "hexagonal": [1, 6, 15, 28, 45, 66, 91]]
 ///     for key in interestingNumbers.keys {
@@ -302,7 +302,7 @@
 ///     }
 ///
 ///     print(interestingNumbers["primes"]!)
-///     // Prints "[15, 13, 11, 7, 5, 3, 2]"
+///     // Prints "[17, 13, 11, 7, 5, 3, 2]"
 ///
 /// Iterating Over the Contents of a Dictionary
 /// ===========================================
@@ -408,7 +408,7 @@
   ///
   /// - Parameter minimumCapacity: The minimum number of key-value pairs that
   ///   the newly created dictionary should be able to store without
-  //    reallocating its storage buffer.
+  ///   reallocating its storage buffer.
   @inlinable // FIXME(sil-serialize-all)
   public init(minimumCapacity: Int) {
     _variantBuffer = .native(_NativeBuffer(minimumCapacity: minimumCapacity))
@@ -805,8 +805,56 @@
 }
 
 extension Dictionary {
-  /// Accesses the element with the given key, or the specified default value,
-  /// if the dictionary doesn't contain the given key.
+  /// Accesses the value with the given key. If the dictionary doesn't contain
+  /// the given key, accesses the provided default value as if the key and
+  /// default value existed in the dictionary.
+  ///
+  /// Use this subscript when you want either the value for a particular key
+  /// or, when that key is not present in the dictionary, a default value. This
+  /// example uses the subscript with a message to use in case an HTTP response
+  /// code isn't recognized:
+  ///
+  ///     var responseMessages = [200: "OK",
+  ///                             403: "Access forbidden",
+  ///                             404: "File not found",
+  ///                             500: "Internal server error"]
+  ///
+  ///     let httpResponseCodes = [200, 403, 301]
+  ///     for code in httpResponseCodes {
+  ///         let message = responseMessages[code, default: "Unknown response"]
+  ///         print("Response \(code): \(message)")
+  ///     }
+  ///     // Prints "Response 200: OK"
+  ///     // Prints "Response 403: Access Forbidden"
+  ///     // Prints "Response 301: Unknown response"
+  ///
+  /// When a dictionary's `Value` type has value semantics, you can use this
+  /// subscript to perform in-place operations on values in the dictionary.
+  /// The following example uses this subscript while counting the occurences
+  /// of each letter in a string:
+  ///
+  ///     let message = "Hello, Elle!"
+  ///     var letterCounts: [Character: Int] = [:]
+  ///     for letter in message {
+  ///         letterCounts[letter, defaultValue: 0] += 1
+  ///     }
+  ///     // letterCounts == ["H": 1, "e": 2, "l": 4, "o": 1, ...]
+  ///
+  /// When `letterCounts[letter, defaultValue: 0] += 1` is executed with a
+  /// value of `letter` that isn't already a key in `letterCounts`, the
+  /// specified default value (`0`) is returned from the subscript,
+  /// incremented, and then added to the dictionary under that key.
+  ///
+  /// - Note: Do not use this subscript to modify dictionary values if the
+  ///   dictionary's `Value` type is a class. In that case, the default value
+  ///   and key are not written back to the dictionary after an operation.
+  ///
+  /// - Parameters:
+  ///   - key: The key the look up in the dictionary.
+  ///   - defaultValue: The default value to use if `key` doesn't exist in the
+  ///     dictionary.
+  /// - Returns: The value associated with `key` in the dictionary`; otherwise,
+  ///   `defaultValue`.
   @inlinable // FIXME(sil-serialize-all)
   public subscript(
     key: Key, default defaultValue: @autoclosure () -> Value
diff --git a/stdlib/public/core/Equatable.swift b/stdlib/public/core/Equatable.swift
index f9751ba..75c49f2 100644
--- a/stdlib/public/core/Equatable.swift
+++ b/stdlib/public/core/Equatable.swift
@@ -29,15 +29,15 @@
 /// example shows how the `contains(_:)` method can be used with an array of
 /// strings.
 ///
-///     let students = ["Nora", "Fern", "Ryan", "Rainer"]
+///     let students = ["Kofi", "Abena", "Efua", "Kweku", "Akosua"]
 ///
-///     let nameToCheck = "Ryan"
+///     let nameToCheck = "Kofi"
 ///     if students.contains(nameToCheck) {
 ///         print("\(nameToCheck) is signed up!")
 ///     } else {
 ///         print("No record of \(nameToCheck).")
 ///     }
-///     // Prints "Ryan is signed up!"
+///     // Prints "Kofi is signed up!"
 ///
 /// Conforming to the Equatable Protocol
 /// ====================================
diff --git a/stdlib/public/core/InputStream.swift b/stdlib/public/core/InputStream.swift
index 6c145c8..2eecdd7 100644
--- a/stdlib/public/core/InputStream.swift
+++ b/stdlib/public/core/InputStream.swift
@@ -19,7 +19,7 @@
 /// Unicode [replacement characters][rc].
 ///
 /// [rc]:
-/// http://en.wikipedia.org/wiki/Specials_(Unicode_block)#Replacement_character
+/// https://unicode.org/glossary/#replacement_character
 ///
 /// - Parameter strippingNewline: If `true`, newline characters and character
 ///   combinations are stripped from the result; otherwise, newline characters
diff --git a/stdlib/public/core/Integers.swift.gyb b/stdlib/public/core/Integers.swift.gyb
index 38e6d57..0627f64 100644
--- a/stdlib/public/core/Integers.swift.gyb
+++ b/stdlib/public/core/Integers.swift.gyb
@@ -977,6 +977,10 @@
   /// In debug builds (`-Onone`) a runtime error is still triggered if the
   /// operation overflows.
   ///
+  /// This method is not a synonym for the masking addition operator (`&+`).
+  /// Use that operator instead of this method when you want to discard any
+  /// overflow that results from an addition operation.
+  ///
   /// - Parameter rhs: The value to add to this value.
   /// - Returns: The sum of this value and `rhs`.
 """,
@@ -993,6 +997,10 @@
   /// In debug builds (`-Onone`) a runtime error is still triggered if the
   /// operation overflows.
   ///
+  /// This method is not a synonym for the masking subtraction operator (`&-`).
+  /// Use that operator instead of this method when you want to discard any
+  /// overflow that results from a subtraction operation.
+  ///
   /// - Parameter rhs: The value to subtract from this value.
   /// - Returns: The result of subtracting `rhs` from this value.
 """,
@@ -1009,6 +1017,10 @@
   /// In debug builds (`-Onone`) a runtime error is still triggered if the
   /// operation overflows.
   ///
+  /// This method is not a synonym for the masking multiplication operator
+  /// (`&*`). Use that operator instead of this method when you want to discard
+  /// any overflow that results from an addition operation.
+  ///
   /// - Parameter rhs: The value to multiply by this value.
   /// - Returns: The product of this value and `rhs`.
 """,
@@ -2417,22 +2429,6 @@
 
 extension FixedWidthInteger {
   /// The empty bitset.
-  ///
-  /// The `allZeros` static property is the [identity element][] for bitwise OR
-  /// and XOR operations and the [fixed point][] for bitwise AND operations.
-  /// For example:
-  ///
-  ///     let x: UInt8 = 5        // 0b00000101
-  ///
-  ///     // Identity
-  ///     x | .allZeros           // 0b00000101
-  ///     x ^ .allZeros           // 0b00000101
-  ///
-  ///     // Fixed point
-  ///     x & .allZeros           // 0b00000000
-  ///
-  /// [identity element]:http://en.wikipedia.org/wiki/Identity_element
-  /// [fixed point]:http://en.wikipedia.org/wiki/Fixed_point_(mathematics)
   @inlinable // FIXME(sil-serialize-all)
   @available(swift, deprecated: 3.1, obsoleted: 4.0, message: "Use 0")
   public static var allZeros: Self { return 0 }
diff --git a/stdlib/public/core/OptionSet.swift b/stdlib/public/core/OptionSet.swift
index d6a24df..c551fce 100644
--- a/stdlib/public/core/OptionSet.swift
+++ b/stdlib/public/core/OptionSet.swift
@@ -20,10 +20,11 @@
 /// requires no extra work on your part.
 ///
 /// When creating an option set, include a `rawValue` property in your type
-/// declaration. The `rawValue` property must be of a type that conforms to
-/// the `FixedWidthInteger` protocol, such as `Int` or `UInt8`. Next, create
-/// unique options as static properties of your custom type using unique
-/// powers of two (1, 2, 4, 8, 16, and so forth) for each individual
+/// declaration. For your type to automatically receive default implementations
+/// for set-related operations, the `rawValue` property must be of a type that
+/// conforms to the `FixedWidthInteger` protocol, such as `Int` or `UInt8`.
+/// Next, create unique options as static properties of your custom type using
+/// unique powers of two (1, 2, 4, 8, 16, and so forth) for each individual
 /// property's raw value so that each property can be represented by a single
 /// bit of the type's raw value.
 ///
diff --git a/stdlib/public/core/Policy.swift b/stdlib/public/core/Policy.swift
index 10e7c26..327cdde 100644
--- a/stdlib/public/core/Policy.swift
+++ b/stdlib/public/core/Policy.swift
@@ -454,22 +454,6 @@
   static prefix func ~ (x: Self) -> Self
 
   /// The empty bitset.
-  ///
-  /// The `allZeros` static property is the [identity element][] for bitwise OR
-  /// and XOR operations and the [fixed point][] for bitwise AND operations.
-  /// For example:
-  ///
-  ///     let x: UInt8 = 5        // 0b00000101
-  ///
-  ///     // Identity
-  ///     x | .allZeros           // 0b00000101
-  ///     x ^ .allZeros           // 0b00000101
-  ///
-  ///     // Fixed point
-  ///     x & .allZeros           // 0b00000000
-  ///
-  /// [identity element]:http://en.wikipedia.org/wiki/Identity_element
-  /// [fixed point]:http://en.wikipedia.org/wiki/Fixed_point_(mathematics)
   @available(swift, deprecated: 3.1, obsoleted: 4.0, message: "Use 0 or init() of a type conforming to FixedWidthInteger")
   static var allZeros: Self { get }
 }
diff --git a/test/ClangImporter/objc_bridging_generics.swift b/test/ClangImporter/objc_bridging_generics.swift
index 8ac6c6c..4ff8cb2 100644
--- a/test/ClangImporter/objc_bridging_generics.swift
+++ b/test/ClangImporter/objc_bridging_generics.swift
@@ -414,3 +414,7 @@
   let _: Int = insufficient.foo // expected-error{{cannot convert value of type 'Set<AnyHashable>' to specified type 'Int'}}
   let _: Int = extra.foo // expected-error{{cannot convert value of type 'Set<ElementConcrete>' to specified type 'Int'}}
 }
+
+func testGenericsWithTypedefBlocks(hba: HasBlockArray) {
+  let _: Int = hba.blockArray() // expected-error{{type '[@convention(block) () -> Void]'}}
+}
diff --git a/test/ClangImporter/objc_ir.swift b/test/ClangImporter/objc_ir.swift
index ab8f375..ca3a76e 100644
--- a/test/ClangImporter/objc_ir.swift
+++ b/test/ClangImporter/objc_ir.swift
@@ -13,6 +13,7 @@
 import objc_ext
 import TestProtocols
 import ObjCIRExtras
+import objc_generics
 
 // CHECK: @"\01L_selector_data(method:withFloat:)" = private global [18 x i8] c"method:withFloat:\00"
 // CHECK: @"\01L_selector_data(method:withDouble:)" = private global [19 x i8] c"method:withDouble:\00"
@@ -344,6 +345,13 @@
   // CHECK: call void @llvm.dbg.declare(metadata %TSo26SwiftConstrGenericNameTestCySo8NSNumberCG** {{%.+}}, metadata ![[SWIFT_CONSTR_GENERIC_NAME_ALIAS_VAR:[0-9]+]], metadata !DIExpression())
 }
 
+// CHECK-LABEL: S7objc_ir22testBlocksWithGenerics3hbaypSo13HasBlockArrayC_tF
+func testBlocksWithGenerics(hba: HasBlockArray) -> Any {
+  // CHECK: {{call swiftcc.*SSo13HasBlockArrayC05blockC0SayyyXBGyFTcTO}}
+  let _ = hba.blockPointerType()
+  return hba.blockArray
+}
+
 // CHECK: linkonce_odr hidden {{.*}} @"$SSo1BC3intABSgs5Int32V_tcfcTO"
 // CHECK: load i8*, i8** @"\01L_selector(initWithInt:)"
 // CHECK: call [[OPAQUE:%.*]]* bitcast (void ()* @objc_msgSend
diff --git a/test/Inputs/clang-importer-sdk/usr/include/objc_generics.h b/test/Inputs/clang-importer-sdk/usr/include/objc_generics.h
index b08c045..f9e1a15 100644
--- a/test/Inputs/clang-importer-sdk/usr/include/objc_generics.h
+++ b/test/Inputs/clang-importer-sdk/usr/include/objc_generics.h
@@ -112,3 +112,10 @@
 
 @interface Third : Second<Third *>
 @end
+
+typedef void (^ _Nonnull BlockPointerType)(void);
+
+@interface HasBlockArray : NSObject
+- (NSArray<BlockPointerType> * _Nonnull)blockArray;
+- (BlockPointerType)blockPointerType;
+@end
diff --git a/test/Migrator/Inputs/Cities.swift b/test/Migrator/Inputs/Cities.swift
index 3f324ed..22d1694 100644
--- a/test/Migrator/Inputs/Cities.swift
+++ b/test/Migrator/Inputs/Cities.swift
@@ -74,3 +74,17 @@
   case Regular
   case Bold
 }
+
+public struct AwesomeCityAttribute: RawRepresentable {
+  public init?(rawValue: String) { self.rawValue = rawValue }
+  public var rawValue: String
+  public typealias RawValue = String
+}
+
+public class Wrapper {
+  public struct Attribute: RawRepresentable {
+    public init?(rawValue: String) { self.rawValue = rawValue }
+    public var rawValue: String
+    public typealias RawValue = String
+  }
+}
\ No newline at end of file
diff --git a/test/Migrator/Inputs/string-representable.json b/test/Migrator/Inputs/string-representable.json
index e35ed0f..b23f4d7 100644
--- a/test/Migrator/Inputs/string-representable.json
+++ b/test/Migrator/Inputs/string-representable.json
@@ -227,4 +227,26 @@
     "RightComment": "AwesomeIntWrapper",
     "ModuleName": "bar"
   },
+  {
+    "DiffItemKind": "CommonDiffItem",
+    "NodeKind": "TypeDecl",
+    "NodeAnnotation": "RevertTypeAliasDeclToRawRepresentable",
+    "ChildIndex": "0",
+    "LeftUsr": "s:6Cities20AwesomeCityAttributeV",
+    "LeftComment": "String",
+    "RightUsr": "",
+    "RightComment": "String",
+    "ModuleName": "Cities"
+  },
+  {
+    "DiffItemKind": "CommonDiffItem",
+    "NodeKind": "TypeDecl",
+    "NodeAnnotation": "RevertTypeAliasDeclToRawRepresentable",
+    "ChildIndex": "0",
+    "LeftUsr": "s:6Cities7WrapperC9AttributeV",
+    "LeftComment": "String",
+    "RightUsr": "",
+    "RightComment": "String",
+    "ModuleName": "Cities"
+  },
 ]
diff --git a/test/Migrator/string-representable.swift b/test/Migrator/string-representable.swift
index 33394ee..e1eafb1 100644
--- a/test/Migrator/string-representable.swift
+++ b/test/Migrator/string-representable.swift
@@ -45,3 +45,12 @@
 }
 
 class C: BarForwardDeclaredClass {}
+
+func revert(_ a: AwesomeCityAttribute, b: Wrapper.Attribute) {
+  _ = AwesomeCityAttribute(rawValue: "somevalue")
+  _ = AwesomeCityAttribute.init(rawValue: "somevalue")
+  _ = a.rawValue
+  _ = Wrapper.Attribute(rawValue: "somevalue")
+  _ = Wrapper.Attribute.init(rawValue: "somevalue")
+  _ = b.rawValue
+}
diff --git a/test/Migrator/string-representable.swift.expected b/test/Migrator/string-representable.swift.expected
index 1a60198..e1e78cc 100644
--- a/test/Migrator/string-representable.swift.expected
+++ b/test/Migrator/string-representable.swift.expected
@@ -46,6 +46,15 @@
 
 class C: BarForwardDeclaredClass {}
 
+func revert(_ a: AwesomeCityAttribute, b: Wrapper.Attribute) {
+  _ = "somevalue"
+  _ = "somevalue"
+  _ = a
+  _ = "somevalue"
+  _ = "somevalue"
+  _ = b
+}
+
 // Helper function inserted by Swift 4.2 migrator.
 fileprivate func convertToNewAttribute(_ input: String) -> NewAttribute {
 	return NewAttribute(rawValue: input)
diff --git a/test/api-digester/Outputs/apinotes-migrator-gen-revert.json b/test/api-digester/Outputs/apinotes-migrator-gen-revert.json
index 6025fa4..97e354e 100644
--- a/test/api-digester/Outputs/apinotes-migrator-gen-revert.json
+++ b/test/api-digester/Outputs/apinotes-migrator-gen-revert.json
@@ -1,6 +1,17 @@
 [
   {
     "DiffItemKind": "CommonDiffItem",
+    "NodeKind": "TypeDecl",
+    "NodeAnnotation": "RevertTypeAliasDeclToRawRepresentable",
+    "ChildIndex": "0",
+    "LeftUsr": "c:APINotesTest.h@T@CatAttributeName",
+    "LeftComment": "String",
+    "RightUsr": "",
+    "RightComment": "NSString",
+    "ModuleName": "APINotesTest"
+  },
+  {
+    "DiffItemKind": "CommonDiffItem",
     "NodeKind": "Function",
     "NodeAnnotation": "RevertSimpleStringRepresentableUpdate",
     "ChildIndex": "1",
diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp
index 30d95a5..ab8ffcd 100644
--- a/tools/swift-api-digester/swift-api-digester.cpp
+++ b/tools/swift-api-digester/swift-api-digester.cpp
@@ -252,6 +252,7 @@
   llvm::BumpPtrAllocator Allocator;
   UpdatedNodesMap UpdateMap;
   NodeMap TypeAliasUpdateMap;
+  NodeMap RevertTypeAliasUpdateMap;
   TypeMemberDiffVector TypeMemberDiffs;
 public:
   llvm::BumpPtrAllocator &allocator() {
@@ -266,6 +267,9 @@
   NodeMap &getTypeAliasUpdateMap() {
     return TypeAliasUpdateMap;
   }
+  NodeMap &getRevertTypeAliasUpdateMap() {
+    return RevertTypeAliasUpdateMap;
+  }
   TypeMemberDiffVector &getTypeMemberDiffs() {
     return TypeMemberDiffs;
   }
@@ -3793,6 +3797,27 @@
   return 0;
 }
 
+static void populateAliasChanges(NodeMap &AliasMap, DiffVector &AllItems,
+    const bool isRevert) {
+  for (auto Pair: AliasMap) {
+    auto UnderlyingType = Pair.first->getAs<SDKNodeDeclTypeAlias>()->
+      getUnderlyingType()->getPrintedName();
+    auto RawType = AliasMap[(SDKNode*)Pair.first]->getAs<SDKNodeDeclType>()->
+      getRawValueType()->getPrintedName();
+    if (isRevert) {
+      auto *D = Pair.second->getAs<SDKNodeDecl>();
+      AllItems.emplace_back(SDKNodeKind::DeclType,
+        NodeAnnotation::RevertTypeAliasDeclToRawRepresentable, "0",
+        D->getUsr(), "", RawType, UnderlyingType, D->getModuleName());
+    } else {
+      auto *D = Pair.first->getAs<SDKNodeDecl>();
+      AllItems.emplace_back(SDKNodeKind::DeclTypeAlias,
+        NodeAnnotation::TypeAliasDeclToRawRepresentable, "0",
+        D->getUsr(), "", UnderlyingType, RawType, D->getModuleName());
+    }
+  }
+}
+
 static int compareSDKs(StringRef LeftPath, StringRef RightPath,
                        StringRef DiffPath,
                        llvm::StringSet<> &IgnoredRemoveUsrs) {
@@ -3827,20 +3852,15 @@
   DiffVector AllItems;
   DiffItemEmitter::collectDiffItems(LeftModule, AllItems);
 
-  auto &AliasMap = Ctx.getTypeAliasUpdateMap();
   // Find type alias change first.
+  auto &AliasMap = Ctx.getTypeAliasUpdateMap();
   TypeAliasDiffFinder(LeftModule, RightModule, AliasMap).search();
+  populateAliasChanges(AliasMap, AllItems, /*IsRevert*/false);
 
-  for (auto Pair: AliasMap) {
-    auto Left = Pair.first->getAs<SDKNodeDeclTypeAlias>()->getUnderlyingType()->
-      getPrintedName();
-    auto Right = AliasMap[(SDKNode*)Pair.first]->getAs<SDKNodeDeclType>()->
-      getRawValueType()->getPrintedName();
-    auto *D = Pair.first->getAs<SDKNodeDecl>();
-    AllItems.emplace_back(SDKNodeKind::DeclTypeAlias,
-      NodeAnnotation::TypeAliasDeclToRawRepresentable, "0",
-      D->getUsr(), "", Left, Right, D->getModuleName());
-  }
+  // Find type alias revert change.
+  auto &RevertAliasMap = Ctx.getRevertTypeAliasUpdateMap();
+  TypeAliasDiffFinder(RightModule, LeftModule, RevertAliasMap).search();
+  populateAliasChanges(RevertAliasMap, AllItems, /*IsRevert*/true);
 
   AllItems.erase(std::remove_if(AllItems.begin(), AllItems.end(),
                                 [&](CommonDiffItem &Item) {