Skip to content

Commit a576984

Browse files
committed
Sema: Teach TypeReprCycleCheckWalker to avoid more cycles
More declaration order issues uncovered by lazy type checking. Fixes rdar://119499800.
1 parent a8675de commit a576984

File tree

2 files changed

+70
-9
lines changed

2 files changed

+70
-9
lines changed

lib/Sema/TypeCheckProtocolInference.cpp

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -165,27 +165,25 @@ namespace {
165165
/// Try to avoid situations where resolving the type of a witness calls back
166166
/// into associated type inference.
167167
struct TypeReprCycleCheckWalker : ASTWalker {
168+
ASTContext &ctx;
168169
llvm::SmallDenseSet<Identifier, 2> circularNames;
169170
ValueDecl *witness;
170171
bool found;
171172

172173
TypeReprCycleCheckWalker(
174+
ASTContext &ctx,
173175
const llvm::SetVector<AssociatedTypeDecl *> &allUnresolved)
174-
: witness(nullptr), found(false) {
176+
: ctx(ctx), witness(nullptr), found(false) {
175177
for (auto *assocType : allUnresolved) {
176178
circularNames.insert(assocType->getName());
177179
}
178180
}
179181

180182
PreWalkAction walkToTypeReprPre(TypeRepr *T) override {
181-
// FIXME: We should still visit any generic arguments of this member type.
182-
// However, we want to skip 'Foo.Element' because the 'Element' reference is
183-
// not unqualified.
184-
if (auto *memberTyR = dyn_cast<MemberTypeRepr>(T)) {
185-
return Action::SkipChildren();
186-
}
183+
// FIXME: Visit generic arguments.
187184

188185
if (auto *identTyR = dyn_cast<SimpleIdentTypeRepr>(T)) {
186+
// If we're inferring `Foo`, don't look at a witness mentioning `Foo`.
189187
if (circularNames.count(identTyR->getNameRef().getBaseIdentifier()) > 0) {
190188
// If unqualified lookup can find a type with this name without looking
191189
// into protocol members, don't skip the witness, since this type might
@@ -194,7 +192,6 @@ struct TypeReprCycleCheckWalker : ASTWalker {
194192
identTyR->getNameRef(), witness->getDeclContext(),
195193
identTyR->getLoc(), UnqualifiedLookupOptions());
196194

197-
auto &ctx = witness->getASTContext();
198195
auto results =
199196
evaluateOrDefault(ctx.evaluator, UnqualifiedLookupRequest{desc}, {});
200197

@@ -207,6 +204,34 @@ struct TypeReprCycleCheckWalker : ASTWalker {
207204
}
208205
}
209206

207+
if (auto *memberTyR = dyn_cast<MemberTypeRepr>(T)) {
208+
// If we're looking at a member type`Foo.Bar`, check `Foo` recursively.
209+
auto *baseTyR = memberTyR->getBaseComponent();
210+
baseTyR->walk(*this);
211+
212+
// If we're inferring `Foo`, don't look at a witness mentioning `Self.Foo`.
213+
if (auto *identTyR = dyn_cast<SimpleIdentTypeRepr>(baseTyR)) {
214+
if (identTyR->getNameRef().getBaseIdentifier() == ctx.Id_Self) {
215+
// But if qualified lookup can find a type with this name without
216+
// looking into protocol members, don't skip the witness, since this
217+
// type might be a candidate witness.
218+
SmallVector<ValueDecl *, 2> results;
219+
witness->getInnermostDeclContext()->lookupQualified(
220+
witness->getDeclContext()->getSelfTypeInContext(),
221+
identTyR->getNameRef(), SourceLoc(), NLOptions(), results);
222+
223+
// Ok, resolving this member type would trigger associated type
224+
// inference recursively. We're going to skip this witness.
225+
if (results.empty()) {
226+
found = true;
227+
return Action::Stop();
228+
}
229+
}
230+
}
231+
232+
return Action::SkipChildren();
233+
}
234+
210235
return Action::Continue();
211236
}
212237

@@ -296,7 +321,7 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses(
296321
abort();
297322
}
298323

299-
TypeReprCycleCheckWalker cycleCheck(allUnresolved);
324+
TypeReprCycleCheckWalker cycleCheck(dc->getASTContext(), allUnresolved);
300325

301326
InferredAssociatedTypesByWitnesses result;
302327

test/decl/protocol/req/assoc_type_inference_cycle.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,39 @@ public enum CaseWitness: CaseProtocol {
9595
case b(_: A)
9696
case c(_: A)
9797
}
98+
99+
// rdar://119499800 #1
100+
public typealias A8 = Batch.Iterator
101+
102+
public struct Batch: Collection {
103+
public typealias Element = Int
104+
public typealias Index = Array<Element>.Index
105+
106+
var elements: [Element]
107+
108+
init(_ elements: some Collection<Element>) {
109+
self.elements = Array(elements)
110+
}
111+
112+
public var startIndex: Index { return elements.startIndex }
113+
public var endIndex: Index { return elements.endIndex }
114+
115+
public subscript(index: Index) -> Iterator.Element {
116+
return elements[index]
117+
}
118+
119+
public func index(after i: Index) -> Index {
120+
return elements.index(after: i)
121+
}
122+
}
123+
124+
// rdar://119499800 #2
125+
public typealias A9 = LogTypes.RawValue
126+
127+
public struct LogTypes: OptionSet {
128+
public init(rawValue: Self.RawValue) {
129+
self.rawValue = rawValue
130+
}
131+
132+
public let rawValue: Int
133+
}

0 commit comments

Comments
 (0)