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