@@ -290,25 +290,51 @@ void BindingSet::inferTransitiveProtocolRequirements(
290
290
// If current type variable is part of an equivalence
291
291
// class, make it a "representative" and let it infer
292
292
// supertypes and direct protocol requirements from
293
- // other members.
294
- for (const auto &entry : bindings.Info .EquivalentTo ) {
295
- auto eqBindings = inferredBindings.find (entry.first );
296
- if (eqBindings != inferredBindings.end ()) {
297
- const auto &bindings = eqBindings->getSecond ();
298
-
299
- llvm::SmallPtrSet<Constraint *, 2 > placeholder;
300
- // Add any direct protocols from members of the
301
- // equivalence class, so they could be propagated
302
- // to all of the members.
303
- propagateProtocolsTo (currentVar, bindings.getConformanceRequirements (),
304
- placeholder);
305
-
306
- // Since type variables are equal, current type variable
307
- // becomes a subtype to any supertype found in the current
308
- // equivalence class.
309
- for (const auto &eqEntry : bindings.Info .SubtypeOf )
310
- addToWorkList (currentVar, eqEntry.first );
311
- }
293
+ // other members and their equivalence classes.
294
+ SmallSetVector<TypeVariableType *, 4 > equivalenceClass;
295
+ {
296
+ SmallVector<TypeVariableType *, 4 > workList;
297
+ workList.push_back (currentVar);
298
+
299
+ do {
300
+ auto *typeVar = workList.pop_back_val ();
301
+
302
+ if (!equivalenceClass.insert (typeVar))
303
+ continue ;
304
+
305
+ auto bindingSet = inferredBindings.find (typeVar);
306
+ if (bindingSet == inferredBindings.end ())
307
+ continue ;
308
+
309
+ auto &equivalences = bindingSet->getSecond ().Info .EquivalentTo ;
310
+ for (const auto &eqVar : equivalences) {
311
+ workList.push_back (eqVar.first );
312
+ }
313
+ } while (!workList.empty ());
314
+ }
315
+
316
+ for (const auto &memberVar : equivalenceClass) {
317
+ if (memberVar == currentVar)
318
+ continue ;
319
+
320
+ auto eqBindings = inferredBindings.find (memberVar);
321
+ if (eqBindings == inferredBindings.end ())
322
+ continue ;
323
+
324
+ const auto &bindings = eqBindings->getSecond ();
325
+
326
+ llvm::SmallPtrSet<Constraint *, 2 > placeholder;
327
+ // Add any direct protocols from members of the
328
+ // equivalence class, so they could be propagated
329
+ // to all of the members.
330
+ propagateProtocolsTo (currentVar, bindings.getConformanceRequirements (),
331
+ placeholder);
332
+
333
+ // Since type variables are equal, current type variable
334
+ // becomes a subtype to any supertype found in the current
335
+ // equivalence class.
336
+ for (const auto &eqEntry : bindings.Info .SubtypeOf )
337
+ addToWorkList (currentVar, eqEntry.first );
312
338
}
313
339
314
340
// More subtype/equivalences relations have been added.
@@ -435,7 +461,6 @@ void BindingSet::inferTransitiveBindings(
435
461
436
462
void BindingSet::finalize (
437
463
llvm::SmallDenseMap<TypeVariableType *, BindingSet> &inferredBindings) {
438
- inferTransitiveProtocolRequirements (inferredBindings);
439
464
inferTransitiveBindings (inferredBindings);
440
465
441
466
determineLiteralCoverage ();
@@ -452,11 +477,14 @@ void BindingSet::finalize(
452
477
// func foo<T: P>(_: T) {}
453
478
// foo(.bar) <- `.bar` should be a static member of `P`.
454
479
// \endcode
455
- if (!hasViableBindings () && TransitiveProtocols.hasValue ()) {
456
- for (auto *constraint : *TransitiveProtocols) {
457
- auto protocolTy = constraint->getSecondType ();
458
- addBinding (
459
- {protocolTy, AllowedBindingKind::Exact, constraint});
480
+ if (!hasViableBindings ()) {
481
+ inferTransitiveProtocolRequirements (inferredBindings);
482
+
483
+ if (TransitiveProtocols.hasValue ()) {
484
+ for (auto *constraint : *TransitiveProtocols) {
485
+ auto protocolTy = constraint->getSecondType ();
486
+ addBinding ({protocolTy, AllowedBindingKind::Exact, constraint});
487
+ }
460
488
}
461
489
}
462
490
}
0 commit comments