|
22 | 22 | using namespace swift;
|
23 | 23 | using namespace constraints;
|
24 | 24 |
|
| 25 | +void ConstraintSystem::PotentialBindings::inferTransitiveProtocolRequirements( |
| 26 | + const ConstraintSystem &cs, |
| 27 | + llvm::SmallDenseMap<TypeVariableType *, ConstraintSystem::PotentialBindings> |
| 28 | + &inferredBindings) { |
| 29 | + if (TransitiveProtocols) |
| 30 | + return; |
| 31 | + |
| 32 | + llvm::SmallVector<std::pair<TypeVariableType *, TypeVariableType *>, 4> |
| 33 | + workList; |
| 34 | + llvm::SmallPtrSet<TypeVariableType *, 4> visitedRelations; |
| 35 | + |
| 36 | + llvm::SmallDenseMap<TypeVariableType *, SmallPtrSet<Constraint *, 4>, 4> |
| 37 | + protocols; |
| 38 | + |
| 39 | + auto addToWorkList = [&](TypeVariableType *parent, |
| 40 | + TypeVariableType *typeVar) { |
| 41 | + if (visitedRelations.insert(typeVar).second) |
| 42 | + workList.push_back({parent, typeVar}); |
| 43 | + }; |
| 44 | + |
| 45 | + auto propagateProtocolsTo = |
| 46 | + [&protocols](TypeVariableType *dstVar, |
| 47 | + const SmallVectorImpl<Constraint *> &direct, |
| 48 | + const SmallPtrSetImpl<Constraint *> &transitive) { |
| 49 | + auto &destination = protocols[dstVar]; |
| 50 | + |
| 51 | + for (auto *protocol : direct) |
| 52 | + destination.insert(protocol); |
| 53 | + |
| 54 | + for (auto *protocol : transitive) |
| 55 | + destination.insert(protocol); |
| 56 | + }; |
| 57 | + |
| 58 | + addToWorkList(nullptr, TypeVar); |
| 59 | + |
| 60 | + do { |
| 61 | + auto *currentVar = workList.back().second; |
| 62 | + |
| 63 | + auto cachedBindings = inferredBindings.find(currentVar); |
| 64 | + if (cachedBindings == inferredBindings.end()) { |
| 65 | + workList.pop_back(); |
| 66 | + continue; |
| 67 | + } |
| 68 | + |
| 69 | + auto &bindings = cachedBindings->getSecond(); |
| 70 | + |
| 71 | + // If current variable already has transitive protocol |
| 72 | + // conformances inferred, there is no need to look deeper |
| 73 | + // into subtype/equivalence chain. |
| 74 | + if (bindings.TransitiveProtocols) { |
| 75 | + TypeVariableType *parent = nullptr; |
| 76 | + std::tie(parent, currentVar) = workList.pop_back_val(); |
| 77 | + assert(parent); |
| 78 | + propagateProtocolsTo(parent, bindings.Protocols, |
| 79 | + *bindings.TransitiveProtocols); |
| 80 | + continue; |
| 81 | + } |
| 82 | + |
| 83 | + for (const auto &entry : bindings.SubtypeOf) |
| 84 | + addToWorkList(currentVar, entry.first); |
| 85 | + |
| 86 | + for (const auto &entry : bindings.EquivalentTo) |
| 87 | + addToWorkList(currentVar, entry.first); |
| 88 | + |
| 89 | + // More subtype/equivalences relations have been added. |
| 90 | + if (workList.back().second != currentVar) |
| 91 | + continue; |
| 92 | + |
| 93 | + TypeVariableType *parent = nullptr; |
| 94 | + std::tie(parent, currentVar) = workList.pop_back_val(); |
| 95 | + |
| 96 | + // At all of the protocols associated with current type variable |
| 97 | + // are transitive to its parent, propogate them down the subtype/equivalence |
| 98 | + // chain. |
| 99 | + if (parent) { |
| 100 | + propagateProtocolsTo(parent, bindings.Protocols, protocols[currentVar]); |
| 101 | + } |
| 102 | + |
| 103 | + // Update the bindings associated with current type variable, |
| 104 | + // to avoid repeating this inference process. |
| 105 | + bindings.TransitiveProtocols.emplace(std::move(protocols[currentVar])); |
| 106 | + } while (!workList.empty()); |
| 107 | +} |
| 108 | + |
25 | 109 | void ConstraintSystem::PotentialBindings::inferTransitiveBindings(
|
26 | 110 | ConstraintSystem &cs, llvm::SmallPtrSetImpl<CanType> &existingTypes,
|
27 | 111 | const llvm::SmallDenseMap<TypeVariableType *,
|
@@ -281,17 +365,16 @@ void ConstraintSystem::PotentialBindings::inferDefaultTypes(
|
281 | 365 |
|
282 | 366 | void ConstraintSystem::PotentialBindings::finalize(
|
283 | 367 | ConstraintSystem &cs,
|
284 |
| - const llvm::SmallDenseMap<TypeVariableType *, |
285 |
| - ConstraintSystem::PotentialBindings> |
| 368 | + llvm::SmallDenseMap<TypeVariableType *, ConstraintSystem::PotentialBindings> |
286 | 369 | &inferredBindings) {
|
287 | 370 | // We need to make sure that there are no duplicate bindings in the
|
288 | 371 | // set, otherwise solver would produce multiple identical solutions.
|
289 | 372 | llvm::SmallPtrSet<CanType, 4> existingTypes;
|
290 | 373 | for (const auto &binding : Bindings)
|
291 | 374 | existingTypes.insert(binding.BindingType->getCanonicalType());
|
292 | 375 |
|
| 376 | + inferTransitiveProtocolRequirements(cs, inferredBindings); |
293 | 377 | inferTransitiveBindings(cs, existingTypes, inferredBindings);
|
294 |
| - |
295 | 378 | inferDefaultTypes(cs, existingTypes);
|
296 | 379 |
|
297 | 380 | // Adjust optionality of existing bindings based on presence of
|
|
0 commit comments