Merge pull request #22008 from xedin/rdar-47334176

[Sema] Fix `resolveDependentMemberType` to properly handle nested typ…
diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp
index 7053be5..2572480 100644
--- a/lib/Sema/TypeCheckType.cpp
+++ b/lib/Sema/TypeCheckType.cpp
@@ -216,8 +216,9 @@
     return DependentMemberType::get(baseTy, assocType);
   }
 
-  // Otherwise, the nested type comes from a concrete type. Substitute the
-  // base type into it.
+  // Otherwise, the nested type comes from a concrete type,
+  // or it's a typealias declared in protocol or protocol extension.
+  // Substitute the base type into it.
   auto concrete = ref->getBoundDecl();
   auto lazyResolver = ctx.getLazyResolver();
   if (lazyResolver)
@@ -225,14 +226,26 @@
   if (!concrete->hasInterfaceType())
     return ErrorType::get(ctx);
 
-  if (concrete->getDeclContext()->getSelfClassDecl()) {
-    // We found a member of a class from a protocol or protocol
-    // extension.
-    //
-    // Get the superclass of the 'Self' type parameter.
-    baseTy = (baseEquivClass->concreteType
-              ? baseEquivClass->concreteType
-              : baseEquivClass->superclass);
+  // Make sure that base type didn't get replaced along the way.
+  assert(baseTy->isTypeParameter());
+
+  // There are two situations possible here:
+  //
+  // 1. Member comes from the protocol, which means that it has been
+  //    found through a conformance constraint placed on base e.g. `T: P`.
+  //    In this case member is a `typealias` declaration located in
+  //    protocol or protocol extension.
+  //
+  // 2. Member comes from struct/enum/class type, which means that it
+  //    has been found through same-type constraint on base e.g. `T == Q`.
+  //
+  // If this is situation #2 we need to make sure to switch base to
+  // a concrete type (according to equivalence class) otherwise we'd
+  // end up using incorrect generic signature while attempting to form
+  // a substituted type for the member we found.
+  if (!concrete->getDeclContext()->getSelfProtocolDecl()) {
+    baseTy = baseEquivClass->concreteType ? baseEquivClass->concreteType
+                                          : baseEquivClass->superclass;
     assert(baseTy);
   }
 
diff --git a/validation-test/Sema/Inputs/rdar47334176_types.swift b/validation-test/Sema/Inputs/rdar47334176_types.swift
new file mode 100644
index 0000000..f5266f1
--- /dev/null
+++ b/validation-test/Sema/Inputs/rdar47334176_types.swift
@@ -0,0 +1,10 @@
+public protocol P : class {
+  associatedtype V
+}
+
+public protocol R {
+  associatedtype V
+}
+
+public enum E<V> : R {}
+public class C<V> : R {}
diff --git a/validation-test/Sema/rdar47334176.swift b/validation-test/Sema/rdar47334176.swift
new file mode 100644
index 0000000..cca1c66
--- /dev/null
+++ b/validation-test/Sema/rdar47334176.swift
@@ -0,0 +1,13 @@
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module -o %t/rdar47334176_types.swiftmodule %S/Inputs/rdar47334176_types.swift
+// RUN: %target-swift-frontend -I %t -typecheck %s
+
+import rdar47334176_types
+
+// To test all possibilities let's declare one of the types
+// in the same module as function declaration which uses it.
+struct S<V> : R {}
+
+func foo<T : P, U>(_: T?, _: (T.V.V) -> Void) where T.V == E<U> {} // Ok
+func bar<T : P, U>(_: T?, _: (T.V.V) -> Void) where T.V == S<U> {} // Ok
+func baz<T : P, U>(_: T?, _: (T.V.V) -> Void) where T.V == C<U> {} // Ok