Skip to content

Commit b633ef2

Browse files
authored
Merge pull request swiftlang#29208 from xedin/dont-attempt-duplicate-supertypes
[CSBindings] Avoid inferring duplicate bindings from supertypes
2 parents f980105 + 97d7470 commit b633ef2

File tree

2 files changed

+77
-39
lines changed

2 files changed

+77
-39
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 61 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,66 @@
2121
using namespace swift;
2222
using namespace constraints;
2323

24+
void ConstraintSystem::inferTransitiveSupertypeBindings(
25+
const llvm::SmallDenseMap<TypeVariableType *, PotentialBindings>
26+
&inferredBindings,
27+
PotentialBindings &bindings) {
28+
auto *typeVar = bindings.TypeVar;
29+
30+
llvm::SmallVector<Constraint *, 4> subtypeOf;
31+
// First, let's collect all of the `subtype` constraints associated
32+
// with this type variable.
33+
llvm::copy_if(bindings.Sources, std::back_inserter(subtypeOf),
34+
[&](const Constraint *constraint) -> bool {
35+
if (constraint->getKind() != ConstraintKind::Subtype)
36+
return false;
37+
38+
auto rhs = simplifyType(constraint->getSecondType());
39+
return rhs->getAs<TypeVariableType>() == typeVar;
40+
});
41+
42+
if (subtypeOf.empty())
43+
return;
44+
45+
// We need to make sure that there are no duplicate bindings in the
46+
// set, other we'll produce multiple identical solutions.
47+
llvm::SmallPtrSet<CanType, 4> existingTypes;
48+
for (const auto &binding : bindings.Bindings)
49+
existingTypes.insert(binding.BindingType->getCanonicalType());
50+
51+
for (auto *constraint : subtypeOf) {
52+
auto *tv =
53+
simplifyType(constraint->getFirstType())->getAs<TypeVariableType>();
54+
if (!tv)
55+
continue;
56+
57+
auto relatedBindings = inferredBindings.find(tv);
58+
if (relatedBindings == inferredBindings.end())
59+
continue;
60+
61+
for (auto &binding : relatedBindings->getSecond().Bindings) {
62+
// We need the binding kind for the potential binding to
63+
// either be Exact or Supertypes in order for it to make sense
64+
// to add Supertype bindings based on the relationship between
65+
// our type variables.
66+
if (binding.Kind != AllowedBindingKind::Exact &&
67+
binding.Kind != AllowedBindingKind::Supertypes)
68+
continue;
69+
70+
auto type = binding.BindingType;
71+
72+
if (!existingTypes.insert(type->getCanonicalType()).second)
73+
continue;
74+
75+
if (ConstraintSystem::typeVarOccursInType(typeVar, type))
76+
continue;
77+
78+
bindings.addPotentialBinding(
79+
binding.withSameSource(type, AllowedBindingKind::Supertypes));
80+
}
81+
}
82+
}
83+
2484
Optional<ConstraintSystem::PotentialBindings>
2585
ConstraintSystem::determineBestBindings() {
2686
// Look for potential type variable bindings.
@@ -44,46 +104,8 @@ ConstraintSystem::determineBestBindings() {
44104
continue;
45105

46106
auto &bindings = cachedBindings->getSecond();
47-
// All of the relevant relational constraints associated with
48-
// current type variable should be recored by its potential bindings.
49-
for (auto *constraint : bindings.Sources) {
50-
if (constraint->getKind() != ConstraintKind::Subtype)
51-
continue;
52-
53-
auto lhs = simplifyType(constraint->getFirstType());
54-
auto rhs = simplifyType(constraint->getSecondType());
55-
56-
// We are only interested in 'subtype' constraints which have
57-
// type variable on the left-hand side.
58-
if (rhs->getAs<TypeVariableType>() != typeVar)
59-
continue;
60-
61-
auto *tv = lhs->getAs<TypeVariableType>();
62-
if (!tv)
63-
continue;
64-
65-
auto relatedBindings = cache.find(tv);
66-
if (relatedBindings == cache.end())
67-
continue;
68-
69-
for (auto &binding : relatedBindings->getSecond().Bindings) {
70-
// We need the binding kind for the potential binding to
71-
// either be Exact or Supertypes in order for it to make sense
72-
// to add Supertype bindings based on the relationship between
73-
// our type variables.
74-
if (binding.Kind != AllowedBindingKind::Exact &&
75-
binding.Kind != AllowedBindingKind::Supertypes)
76-
continue;
77-
78-
auto type = binding.BindingType;
79107

80-
if (ConstraintSystem::typeVarOccursInType(typeVar, type))
81-
continue;
82-
83-
bindings.addPotentialBinding(
84-
binding.withSameSource(type, AllowedBindingKind::Supertypes));
85-
}
86-
}
108+
inferTransitiveSupertypeBindings(cache, bindings);
87109

88110
if (getASTContext().TypeCheckerOpts.DebugConstraintSolver) {
89111
auto &log = getASTContext().TypeCheckerDebug->getStream();

lib/Sema/ConstraintSystem.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3761,6 +3761,22 @@ class ConstraintSystem {
37613761
bool &addOptionalSupertypeBindings) const;
37623762
PotentialBindings getPotentialBindings(TypeVariableType *typeVar) const;
37633763

3764+
/// Detect `subtype` relationship between two type variables and
3765+
/// attempt to infer supertype bindings transitively e.g.
3766+
///
3767+
/// Given A <: T1 <: T2 transitively A <: T2
3768+
///
3769+
/// Which gives us a new (superclass A) binding for T2 as well as T1.
3770+
///
3771+
/// \param inferredBindings The set of all bindings inferred for type
3772+
/// variables in the workset.
3773+
/// \param bindings The type variable we aim to infer new supertype
3774+
/// bindings for.
3775+
void inferTransitiveSupertypeBindings(
3776+
const llvm::SmallDenseMap<TypeVariableType *, PotentialBindings>
3777+
&inferredBindings,
3778+
PotentialBindings &bindings);
3779+
37643780
private:
37653781
/// Add a constraint to the constraint system.
37663782
SolutionKind addConstraintImpl(ConstraintKind kind, Type first, Type second,

0 commit comments

Comments
 (0)