Skip to content

Commit 686ddd7

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 07d87a1 commit 686ddd7

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
@@ -2215,16 +2215,39 @@ ConformanceChecker::getReferencedAssociatedTypes(ValueDecl *req) {
22152215
return known->second;
22162216

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

22292252
return assocTypes;
22302253
}
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)