Skip to content

Commit aab54a1

Browse files
committed
Sema: Tighten up getReferencedAssociatedTypes()
If a protocol requirement has a type that's a nested member type of another member type, eg, protocol P { associatedtype A : Q func f(_: A.B) } Then we don't actually want to use 'f()' to infer the witness for 'A'. By avoiding doing so, we eliminate some cycles which can allow some programs to type check that didn't before.
1 parent a20a92d commit aab54a1

File tree

3 files changed

+55
-8
lines changed

3 files changed

+55
-8
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2219,16 +2219,39 @@ ConformanceChecker::getReferencedAssociatedTypes(ValueDecl *req) {
22192219
return known->second;
22202220

22212221
// Collect the set of associated types rooted on Self in the
2222-
// signature.
2222+
// signature. Note that for references to nested types, we only
2223+
// want to consider the outermost dependent member type.
2224+
//
2225+
// For example, a requirement typed '(Iterator.Element) -> ()'
2226+
// is not considered to reference the associated type 'Iterator'.
22232227
auto &assocTypes = ReferencedAssociatedTypes[req];
2224-
llvm::SmallPtrSet<AssociatedTypeDecl *, 4> knownAssocTypes;
2225-
req->getInterfaceType()->getCanonicalType().visit([&](CanType type) {
2226-
if (auto assocType = getReferencedAssocTypeOfProtocol(type, Proto)) {
2227-
if (knownAssocTypes.insert(assocType).second) {
2228-
assocTypes.push_back(assocType);
2228+
2229+
class Walker : public TypeWalker {
2230+
ProtocolDecl *Proto;
2231+
llvm::SmallVectorImpl<AssociatedTypeDecl *> &assocTypes;
2232+
llvm::SmallPtrSet<AssociatedTypeDecl *, 4> knownAssocTypes;
2233+
2234+
public:
2235+
Walker(ProtocolDecl *Proto,
2236+
llvm::SmallVectorImpl<AssociatedTypeDecl *> &assocTypes)
2237+
: Proto(Proto), assocTypes(assocTypes) {}
2238+
2239+
Action walkToTypePre(Type type) override {
2240+
if (type->is<DependentMemberType>()) {
2241+
if (auto assocType = getReferencedAssocTypeOfProtocol(type, Proto)) {
2242+
if (knownAssocTypes.insert(assocType).second)
2243+
assocTypes.push_back(assocType);
22292244
}
2245+
2246+
return Action::SkipChildren;
22302247
}
2231-
});
2248+
2249+
return Action::Continue;
2250+
}
2251+
};
2252+
2253+
Walker walker(Proto, assocTypes);
2254+
req->getInterfaceType()->getCanonicalType().walk(walker);
22322255

22332256
return assocTypes;
22342257
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// RUN: %target-swift-frontend -emit-silgen %s
2+
3+
// This is a SILGen test to ensure we can completely check these conformances
4+
// and build valid AST.
5+
6+
protocol P {
7+
associatedtype T : Q = S
8+
typealias Y = T.X
9+
10+
func foo(_: T.X)
11+
}
12+
13+
protocol Q {
14+
associatedtype X
15+
}
16+
17+
struct S : Q {
18+
typealias X = ()
19+
}
20+
21+
struct R : P {
22+
let x: Y? = nil
23+
func foo(_: Y) {}
24+
}

validation-test/compiler_crashers_2_fixed/sr11052-typealias.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ struct Concrete<AType2: ProtoA>: ProtoB {
1919
fatalError()
2020
}
2121

22-
func protoFunc() -> Alias { // expected-error{{unsupported recursion for reference to type alias 'Alias' of type 'Concrete<AType2>'}}
22+
func protoFunc() -> Alias {
2323
fatalError()
2424
}
2525
}

0 commit comments

Comments
 (0)