Skip to content

Commit e55cfb2

Browse files
authored
Merge pull request #22021 from xedin/rdar-47334176-5.0
[5.0][Sema] Fix `resolveDependentMemberType` to properly handle nested typ…
2 parents 3999fb3 + c609993 commit e55cfb2

File tree

3 files changed

+46
-10
lines changed

3 files changed

+46
-10
lines changed

lib/Sema/TypeCheckType.cpp

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -212,23 +212,36 @@ Type TypeResolution::resolveDependentMemberType(
212212
return DependentMemberType::get(baseTy, assocType);
213213
}
214214

215-
// Otherwise, the nested type comes from a concrete type. Substitute the
216-
// base type into it.
215+
// Otherwise, the nested type comes from a concrete type,
216+
// or it's a typealias declared in protocol or protocol extension.
217+
// Substitute the base type into it.
217218
auto concrete = ref->getBoundDecl();
218219
auto lazyResolver = ctx.getLazyResolver();
219220
if (lazyResolver)
220221
lazyResolver->resolveDeclSignature(concrete);
221222
if (!concrete->hasInterfaceType())
222223
return ErrorType::get(ctx);
223224

224-
if (concrete->getDeclContext()->getSelfClassDecl()) {
225-
// We found a member of a class from a protocol or protocol
226-
// extension.
227-
//
228-
// Get the superclass of the 'Self' type parameter.
229-
baseTy = (baseEquivClass->concreteType
230-
? baseEquivClass->concreteType
231-
: baseEquivClass->superclass);
225+
// Make sure that base type didn't get replaced along the way.
226+
assert(baseTy->isTypeParameter());
227+
228+
// There are two situations possible here:
229+
//
230+
// 1. Member comes from the protocol, which means that it has been
231+
// found through a conformance constraint placed on base e.g. `T: P`.
232+
// In this case member is a `typealias` declaration located in
233+
// protocol or protocol extension.
234+
//
235+
// 2. Member comes from struct/enum/class type, which means that it
236+
// has been found through same-type constraint on base e.g. `T == Q`.
237+
//
238+
// If this is situation #2 we need to make sure to switch base to
239+
// a concrete type (according to equivalence class) otherwise we'd
240+
// end up using incorrect generic signature while attempting to form
241+
// a substituted type for the member we found.
242+
if (!concrete->getDeclContext()->getSelfProtocolDecl()) {
243+
baseTy = baseEquivClass->concreteType ? baseEquivClass->concreteType
244+
: baseEquivClass->superclass;
232245
assert(baseTy);
233246
}
234247

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
public protocol P : class {
2+
associatedtype V
3+
}
4+
5+
public protocol R {
6+
associatedtype V
7+
}
8+
9+
public enum E<V> : R {}
10+
public class C<V> : R {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module -o %t/rdar47334176_types.swiftmodule %S/Inputs/rdar47334176_types.swift
3+
// RUN: %target-swift-frontend -I %t -typecheck %s
4+
5+
import rdar47334176_types
6+
7+
// To test all possibilities let's declare one of the types
8+
// in the same module as function declaration which uses it.
9+
struct S<V> : R {}
10+
11+
func foo<T : P, U>(_: T?, _: (T.V.V) -> Void) where T.V == E<U> {} // Ok
12+
func bar<T : P, U>(_: T?, _: (T.V.V) -> Void) where T.V == S<U> {} // Ok
13+
func baz<T : P, U>(_: T?, _: (T.V.V) -> Void) where T.V == C<U> {} // Ok

0 commit comments

Comments
 (0)