@@ -161,6 +161,127 @@ static bool associatedTypesAreSameEquivalenceClass(AssociatedTypeDecl *a,
161
161
return false ;
162
162
}
163
163
164
+ namespace {
165
+
166
+ // / Try to avoid situations where resolving the type of a witness calls back
167
+ // / into associated type inference.
168
+ struct TypeReprCycleCheckWalker : ASTWalker {
169
+ llvm::SmallDenseSet<Identifier, 2 > circularNames;
170
+ ValueDecl *witness;
171
+ bool found;
172
+
173
+ TypeReprCycleCheckWalker (
174
+ const llvm::SetVector<AssociatedTypeDecl *> &allUnresolved)
175
+ : witness(nullptr ), found(false ) {
176
+ for (auto *assocType : allUnresolved) {
177
+ circularNames.insert (assocType->getName ());
178
+ }
179
+ }
180
+
181
+ 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
+ }
188
+
189
+ if (auto *identTyR = dyn_cast<SimpleIdentTypeRepr>(T)) {
190
+ if (circularNames.count (identTyR->getNameRef ().getBaseIdentifier ()) > 0 ) {
191
+ // If unqualified lookup can find a type with this name without looking
192
+ // into protocol members, don't skip the witness, since this type might
193
+ // be a candidate witness.
194
+ auto desc = UnqualifiedLookupDescriptor (
195
+ identTyR->getNameRef (), witness->getDeclContext (),
196
+ identTyR->getLoc (), UnqualifiedLookupOptions ());
197
+
198
+ auto &ctx = witness->getASTContext ();
199
+ auto results =
200
+ evaluateOrDefault (ctx.evaluator , UnqualifiedLookupRequest{desc}, {});
201
+
202
+ // Ok, resolving this name would trigger associated type inference
203
+ // recursively. We're going to skip this witness.
204
+ if (results.allResults ().empty ()) {
205
+ found = true ;
206
+ return Action::Stop ();
207
+ }
208
+ }
209
+ }
210
+
211
+ return Action::Continue ();
212
+ }
213
+
214
+ bool checkForPotentialCycle (ValueDecl *witness) {
215
+ // Don't do this for protocol extension members, because we have a
216
+ // mini "solver" that avoids similar issues instead.
217
+ if (witness->getDeclContext ()->getSelfProtocolDecl () != nullptr )
218
+ return false ;
219
+
220
+ // If we already have an interface type, don't bother trying to
221
+ // avoid a cycle.
222
+ if (witness->hasInterfaceType ())
223
+ return false ;
224
+
225
+ // We call checkForPotentailCycle() multiple times with
226
+ // different witnesses.
227
+ found = false ;
228
+ this ->witness = witness;
229
+
230
+ auto walkInto = [&](TypeRepr *tyR) {
231
+ if (tyR)
232
+ tyR->walk (*this );
233
+ return found;
234
+ };
235
+
236
+ if (auto *AFD = dyn_cast<AbstractFunctionDecl>(witness)) {
237
+ for (auto *param : *AFD->getParameters ()) {
238
+ if (walkInto (param->getTypeRepr ()))
239
+ return true ;
240
+ }
241
+
242
+ if (auto *FD = dyn_cast<FuncDecl>(witness)) {
243
+ if (walkInto (FD->getResultTypeRepr ()))
244
+ return true ;
245
+ }
246
+
247
+ return false ;
248
+ }
249
+
250
+ if (auto *SD = dyn_cast<SubscriptDecl>(witness)) {
251
+ for (auto *param : *SD->getIndices ()) {
252
+ if (walkInto (param->getTypeRepr ()))
253
+ return true ;
254
+ }
255
+
256
+ if (walkInto (SD->getElementTypeRepr ()))
257
+ return true ;
258
+
259
+ return false ;
260
+ }
261
+
262
+ if (auto *VD = dyn_cast<VarDecl>(witness)) {
263
+ if (walkInto (VD->getTypeReprOrParentPatternTypeRepr ()))
264
+ return true ;
265
+
266
+ return false ;
267
+ }
268
+
269
+ if (auto *EED = dyn_cast<EnumElementDecl>(witness)) {
270
+ for (auto *param : *EED->getParameterList ()) {
271
+ if (walkInto (param->getTypeRepr ()))
272
+ return true ;
273
+ }
274
+
275
+ return false ;
276
+ }
277
+
278
+ assert (false && " Should be exhaustive" );
279
+ return false ;
280
+ }
281
+ };
282
+
283
+ }
284
+
164
285
InferredAssociatedTypesByWitnesses
165
286
AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses (
166
287
ConformanceChecker &checker,
@@ -176,11 +297,13 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses(
176
297
abort ();
177
298
}
178
299
300
+ TypeReprCycleCheckWalker cycleCheck (allUnresolved);
301
+
179
302
InferredAssociatedTypesByWitnesses result;
180
303
181
304
auto isExtensionUsableForInference = [&](const ExtensionDecl *extension) {
182
305
// The context the conformance being checked is declared on.
183
- const auto conformanceCtx = checker. Conformance ->getDeclContext ();
306
+ const auto conformanceCtx = conformance ->getDeclContext ();
184
307
if (extension == conformanceCtx)
185
308
return true ;
186
309
@@ -250,11 +373,17 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses(
250
373
// If the potential witness came from an extension, and our `Self`
251
374
// type can't use it regardless of what associated types we end up
252
375
// inferring, skip the witness.
253
- if (auto extension = dyn_cast<ExtensionDecl>(witness->getDeclContext ()))
376
+ if (auto extension = dyn_cast<ExtensionDecl>(witness->getDeclContext ())) {
254
377
if (!isExtensionUsableForInference (extension)) {
255
378
LLVM_DEBUG (llvm::dbgs () << " Extension not usable for inference\n " );
256
379
continue ;
257
380
}
381
+ }
382
+
383
+ if (cycleCheck.checkForPotentialCycle (witness)) {
384
+ LLVM_DEBUG (llvm::dbgs () << " Skipping witness to avoid request cycle\n " );
385
+ continue ;
386
+ }
258
387
259
388
// Try to resolve the type witness via this value witness.
260
389
auto witnessResult = inferTypeWitnessesViaValueWitness (req, witness);
0 commit comments