Merge pull request #7361 from jckarter/raw-rep-synthesized-conformance-3.1

[3.1] Sema: Treat the implicit RawRepresentable conformance for enums as `Synthesized` again.
diff --git a/lib/AST/ConformanceLookupTable.cpp b/lib/AST/ConformanceLookupTable.cpp
index fdf0b67..7e393dd 100644
--- a/lib/AST/ConformanceLookupTable.cpp
+++ b/lib/AST/ConformanceLookupTable.cpp
@@ -858,7 +858,8 @@
 }
 
 void ConformanceLookupTable::registerProtocolConformance(
-       ProtocolConformance *conformance) {
+       ProtocolConformance *conformance,
+       bool synthesized) {
   auto protocol = conformance->getProtocol();
   auto dc = conformance->getDeclContext();
   auto nominal = dc->getAsNominalTypeOrNominalTypeExtensionContext();
@@ -878,8 +879,9 @@
   // Otherwise, add a new entry.
   auto inherited = dyn_cast<InheritedProtocolConformance>(conformance);
   ConformanceSource source
-    = inherited ? ConformanceSource::forInherited(cast<ClassDecl>(nominal))
-                : ConformanceSource::forExplicit(dc);
+    = inherited   ? ConformanceSource::forInherited(cast<ClassDecl>(nominal)) :
+      synthesized ? ConformanceSource::forSynthesized(nominal) :
+                    ConformanceSource::forExplicit(dc);
 
   ASTContext &ctx = nominal->getASTContext();
   ConformanceEntry *entry = new (ctx) ConformanceEntry(SourceLoc(),
diff --git a/lib/AST/ConformanceLookupTable.h b/lib/AST/ConformanceLookupTable.h
index e9a8bb2..cb58319 100644
--- a/lib/AST/ConformanceLookupTable.h
+++ b/lib/AST/ConformanceLookupTable.h
@@ -439,7 +439,8 @@
                                  ProtocolDecl *protocol);
 
   /// Register an externally-supplied protocol conformance.
-  void registerProtocolConformance(ProtocolConformance *conformance);
+  void registerProtocolConformance(ProtocolConformance *conformance,
+                                   bool synthesized = false);
 
   /// Look for conformances to the given protocol.
   ///
diff --git a/lib/AST/ProtocolConformance.cpp b/lib/AST/ProtocolConformance.cpp
index a2fd35f..3bb2ffb 100644
--- a/lib/AST/ProtocolConformance.cpp
+++ b/lib/AST/ProtocolConformance.cpp
@@ -628,14 +628,10 @@
     if (resolver)
       resolver->resolveRawType(theEnum);
     if (theEnum->hasRawType()) {
-      if (auto rawRepresentable = ctx.getProtocol(KnownProtocolKind::RawRepresentable)) {
-
-        // The presence of a raw type is an explicit declaration that
-        // the compiler should derive a RawRepresentable conformance.
-        auto conformance = ctx.getConformance(mutableThis->getDeclaredTypeInContext(), rawRepresentable,
-                                              mutableThis->getNameLoc(), mutableThis->getInnermostDeclContext(),
-                                              ProtocolConformanceState::Incomplete);
-        ConformanceTable->registerProtocolConformance(conformance);
+      if (auto rawRepresentable =
+            ctx.getProtocol(KnownProtocolKind::RawRepresentable)) {
+        ConformanceTable->addSynthesizedConformance(mutableThis,
+                                                    rawRepresentable);
       }
     }
   }
diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp
index 7937dec..8acfaad 100644
--- a/lib/Sema/TypeCheckDecl.cpp
+++ b/lib/Sema/TypeCheckDecl.cpp
@@ -2789,6 +2789,10 @@
   llvm::SmallDenseMap<RawValueKey, RawValueSource, 8> uniqueRawValues;
 
   for (auto elt : ED->getAllElements()) {
+    // Skip if the raw value expr has already been checked.
+    if (elt->getTypeCheckedRawValueExpr())
+      continue;
+
     // Make sure the element is checked out before we poke at it.
     TC.validateDecl(elt);
     
@@ -6298,6 +6302,12 @@
       if (auto extendedTy = ED->getExtendedType()) {
         if (auto nominal = extendedTy->getAnyNominal()) {
           TC.validateDecl(nominal);
+          // Check the raw values of an enum, since we might synthesize
+          // RawRepresentable while checking conformances on this extension.
+          if (auto enumDecl = dyn_cast<EnumDecl>(nominal)) {
+            if (enumDecl->hasRawType())
+              checkEnumRawValues(TC, enumDecl);
+          }
         }
       }
 
@@ -7454,7 +7464,7 @@
     ext->setGenericEnvironment(env);
     return;
   }
-
+  
   // If we're extending a protocol, check the generic parameters.
   //
   // Canonicalize the type to work around the fact that getAs<> cannot
diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp
index 35c2a21..c40f584 100644
--- a/lib/Sema/TypeCheckProtocol.cpp
+++ b/lib/Sema/TypeCheckProtocol.cpp
@@ -5491,9 +5491,10 @@
     // Special case: explain that 'RawRepresentable' conformance
     // is implied for enums which already declare a raw type.
     if (auto enumDecl = dyn_cast<EnumDecl>(existingDecl)) {
-      if (diag.Protocol->isSpecificProtocol(KnownProtocolKind::RawRepresentable) &&
-          enumDecl->derivesProtocolConformance(diag.Protocol) &&
-          enumDecl->hasRawType()) {
+      if (diag.Protocol->isSpecificProtocol(KnownProtocolKind::RawRepresentable)
+          && enumDecl->derivesProtocolConformance(diag.Protocol)
+          && enumDecl->hasRawType()
+          && enumDecl->getInherited()[0].getSourceRange().isValid()) {
         diagnose(enumDecl->getInherited()[0].getSourceRange().Start,
                  diag::enum_declares_rawrep_with_raw_type,
                  dc->getDeclaredInterfaceType(), enumDecl->getRawType());
diff --git a/test/Sema/Inputs/enum_raw_representable_explicit_multi_file_2.swift b/test/Sema/Inputs/enum_raw_representable_explicit_multi_file_2.swift
new file mode 100644
index 0000000..6ff4164
--- /dev/null
+++ b/test/Sema/Inputs/enum_raw_representable_explicit_multi_file_2.swift
@@ -0,0 +1,8 @@
+
+extension Foo: RawRepresentable {}
+
+enum Bar: Int { case A }
+
+// expected-error@+1{{redundant conformance of 'Bas' to protocol 'RawRepresentable'}}
+extension Bas: RawRepresentable {}
+
diff --git a/test/Sema/Inputs/enum_with_raw_type.swift b/test/Sema/Inputs/enum_with_raw_type.swift
new file mode 100644
index 0000000..9ad55e1
--- /dev/null
+++ b/test/Sema/Inputs/enum_with_raw_type.swift
@@ -0,0 +1 @@
+public enum Foo: Int { case A }
diff --git a/test/Sema/enum_post_hoc_raw_representable_with_raw_type.swift b/test/Sema/enum_post_hoc_raw_representable_with_raw_type.swift
new file mode 100644
index 0000000..9d8f407
--- /dev/null
+++ b/test/Sema/enum_post_hoc_raw_representable_with_raw_type.swift
@@ -0,0 +1,9 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: %target-swift-frontend -emit-module -o %t/enum_with_raw_type.swiftmodule %S/Inputs/enum_with_raw_type.swift
+// RUN: %target-swift-frontend -I %t -typecheck -verify %s
+
+import enum_with_raw_type
+
+// expected-error@+1{{redundant conformance of 'Foo' to protocol 'RawRepresentable'}}
+extension Foo: RawRepresentable {}
diff --git a/test/Sema/enum_raw_representable_explicit.swift b/test/Sema/enum_raw_representable_explicit.swift
new file mode 100644
index 0000000..d06108e
--- /dev/null
+++ b/test/Sema/enum_raw_representable_explicit.swift
@@ -0,0 +1,15 @@
+// RUN: %target-swift-frontend -typecheck -verify %s
+
+enum Foo: Int, RawRepresentable { case A }
+
+enum Bar: Int { case A }
+
+extension Bar: RawRepresentable {}
+
+enum Bas: Int { case A }
+
+// expected-note@+1{{'Bas' declares conformance to protocol 'RawRepresentable' here}}
+extension Bas: RawRepresentable {}
+
+// expected-error@+1{{redundant conformance of 'Bas' to protocol 'RawRepresentable'}}
+extension Bas: RawRepresentable {}
diff --git a/test/Sema/enum_raw_representable_explicit_cart_before_horse.swift b/test/Sema/enum_raw_representable_explicit_cart_before_horse.swift
new file mode 100644
index 0000000..09d6ed5
--- /dev/null
+++ b/test/Sema/enum_raw_representable_explicit_cart_before_horse.swift
@@ -0,0 +1,4 @@
+// RUN: %target-swift-frontend -typecheck -verify %s
+
+enum Foo: Int { case A }
+extension Foo: RawRepresentable {}
diff --git a/test/Sema/enum_raw_representable_explicit_multi_file.swift b/test/Sema/enum_raw_representable_explicit_multi_file.swift
new file mode 100644
index 0000000..c16a4f4
--- /dev/null
+++ b/test/Sema/enum_raw_representable_explicit_multi_file.swift
@@ -0,0 +1,10 @@
+// RUN: %target-swift-frontend -typecheck -primary-file %s %S/Inputs/enum_raw_representable_explicit_multi_file_2.swift
+// RUN: %target-swift-frontend -typecheck -verify %s -primary-file %S/Inputs/enum_raw_representable_explicit_multi_file_2.swift
+
+enum Foo: Int { case A }
+
+extension Bar: RawRepresentable {}
+
+enum Bas: Int { case A }
+// expected-note@+1 {{'Bas' declares conformance to protocol 'RawRepresentable' here}}
+extension Bas: RawRepresentable {}
diff --git a/test/decl/protocol/conforms/Inputs/placement_2.swift b/test/decl/protocol/conforms/Inputs/placement_2.swift
index 7c201f1..0e02c9e 100644
--- a/test/decl/protocol/conforms/Inputs/placement_2.swift
+++ b/test/decl/protocol/conforms/Inputs/placement_2.swift
@@ -39,6 +39,6 @@
 
 extension MFSynthesizedSubClass4 : AnyObjectRefinement { }
 
-enum MFSynthesizedEnum1 : Int { case a } // expected-note {{'MFSynthesizedEnum1' declares raw type 'Int', which implies RawRepresentable}}
+enum MFSynthesizedEnum1 : Int { case a }
 extension MFSynthesizedEnum2 : RawRepresentable { }
 
diff --git a/test/decl/protocol/conforms/placement.swift b/test/decl/protocol/conforms/placement.swift
index bd749ca..bf5434e 100644
--- a/test/decl/protocol/conforms/placement.swift
+++ b/test/decl/protocol/conforms/placement.swift
@@ -127,10 +127,10 @@
 class SynthesizedSubClass4 : SynthesizedClass2 { }
 extension SynthesizedSubClass4 : AnyObjectRefinement { }
 
-enum SynthesizedEnum1 : Int, RawRepresentable { case none = 0 } // expected-error{{redundant conformance of 'SynthesizedEnum1' to protocol 'RawRepresentable'}} expected-note{{'SynthesizedEnum1' declares raw type 'Int', which implies RawRepresentable}}
+enum SynthesizedEnum1 : Int, RawRepresentable { case none = 0 }
 
-enum SynthesizedEnum2 : Int { case none = 0 } // expected-note {{'SynthesizedEnum2' declares raw type 'Int', which implies RawRepresentable}}
-extension SynthesizedEnum2 : RawRepresentable { } // expected-error{{redundant conformance of 'SynthesizedEnum2' to protocol 'RawRepresentable'}}
+enum SynthesizedEnum2 : Int { case none = 0 }
+extension SynthesizedEnum2 : RawRepresentable { }
 
 
 // ===========================================================================
@@ -182,7 +182,7 @@
 
 class MFSynthesizedSubClass4 : MFSynthesizedClass2 { }
 
-extension MFSynthesizedEnum1 : RawRepresentable { } // expected-error{{redundant conformance of 'MFSynthesizedEnum1' to protocol 'RawRepresentable'}}
+extension MFSynthesizedEnum1 : RawRepresentable { }
 
 enum MFSynthesizedEnum2 : Int { case none = 0 }