Skip to content

Commit 0f71674

Browse files
authored
Merge pull request #70378 from slavapestov/a-major-category-of-problem
Sema: Teach TypeReprCycleCheckWalker to avoid more cycles
2 parents ec87fbc + 7e39fdb commit 0f71674

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
@@ -166,27 +166,25 @@ namespace {
166166
/// Try to avoid situations where resolving the type of a witness calls back
167167
/// into associated type inference.
168168
struct TypeReprCycleCheckWalker : ASTWalker {
169+
ASTContext &ctx;
169170
llvm::SmallDenseSet<Identifier, 2> circularNames;
170171
ValueDecl *witness;
171172
bool found;
172173

173174
TypeReprCycleCheckWalker(
175+
ASTContext &ctx,
174176
const llvm::SetVector<AssociatedTypeDecl *> &allUnresolved)
175-
: witness(nullptr), found(false) {
177+
: ctx(ctx), witness(nullptr), found(false) {
176178
for (auto *assocType : allUnresolved) {
177179
circularNames.insert(assocType->getName());
178180
}
179181
}
180182

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

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

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

@@ -208,6 +205,34 @@ struct TypeReprCycleCheckWalker : ASTWalker {
208205
}
209206
}
210207

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

@@ -362,7 +387,7 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses(
362387
abort();
363388
}
364389

365-
TypeReprCycleCheckWalker cycleCheck(allUnresolved);
390+
TypeReprCycleCheckWalker cycleCheck(dc->getASTContext(), allUnresolved);
366391

367392
InferredAssociatedTypesByWitnesses result;
368393

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)