Skip to content

Commit 07b1905

Browse files
authored
Merge pull request #22008 from xedin/rdar-47334176
[Sema] Fix `resolveDependentMemberType` to properly handle nested typ…
2 parents 1d2290c + 33cff97 commit 07b1905

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
@@ -216,23 +216,36 @@ Type TypeResolution::resolveDependentMemberType(
216216
return DependentMemberType::get(baseTy, assocType);
217217
}
218218

219-
// Otherwise, the nested type comes from a concrete type. Substitute the
220-
// base type into it.
219+
// Otherwise, the nested type comes from a concrete type,
220+
// or it's a typealias declared in protocol or protocol extension.
221+
// Substitute the base type into it.
221222
auto concrete = ref->getBoundDecl();
222223
auto lazyResolver = ctx.getLazyResolver();
223224
if (lazyResolver)
224225
lazyResolver->resolveDeclSignature(concrete);
225226
if (!concrete->hasInterfaceType())
226227
return ErrorType::get(ctx);
227228

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

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)