Skip to content

Commit 374efd1

Browse files
authored
Merge pull request swiftlang#21818 from slavapestov/constraint-solver-cleanups
Constraint simplification cleanups
2 parents 734e92c + 52c1c8c commit 374efd1

File tree

6 files changed

+62
-70
lines changed

6 files changed

+62
-70
lines changed

lib/Sema/CSGen.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1610,6 +1610,7 @@ namespace {
16101610
CS.getConstraintLocator(expr,
16111611
ConstraintLocator::ApplyArgument),
16121612
(TVO_CanBindToLValue |
1613+
TVO_CanBindToInOut |
16131614
TVO_PrefersSubtypeBinding));
16141615
CS.addConstraint(
16151616
ConstraintKind::FunctionInput, methodTy, argTy,

lib/Sema/CSSimplify.cpp

Lines changed: 41 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1547,6 +1547,12 @@ ConstraintSystem::matchTypesBindTypeVar(
15471547
// If the left-hand type variable cannot bind to an lvalue,
15481548
// but we still have an lvalue, fail.
15491549
if (!typeVar->getImpl().canBindToLValue() && type->hasLValueType()) {
1550+
return getTypeMatchFailure(locator);
1551+
}
1552+
1553+
// If the left-hand type variable cannot bind to an inout,
1554+
// but we still have an inout, fail.
1555+
if (!typeVar->getImpl().canBindToInOut() && type->is<InOutType>()) {
15501556
return getTypeMatchFailure(locator);
15511557
}
15521558

@@ -1568,15 +1574,6 @@ ConstraintSystem::matchTypesBindTypeVar(
15681574
}
15691575
}
15701576

1571-
// Check whether the type variable must be bound to a materializable
1572-
// type.
1573-
if (typeVar->getImpl().mustBeMaterializable()) {
1574-
if (!type->isMaterializable())
1575-
return getTypeMatchFailure(locator);
1576-
1577-
setMustBeMaterializableRecursive(type);
1578-
}
1579-
15801577
// Okay. Bind below.
15811578

15821579
// A constraint that binds any pointer to a void pointer is
@@ -1588,6 +1585,16 @@ ConstraintSystem::matchTypesBindTypeVar(
15881585
return getTypeMatchSuccess();
15891586
}
15901587

1588+
if (!typeVar->getImpl().canBindToLValue()) {
1589+
// When binding a fixed type to a type variable that cannot contain
1590+
// lvalues, any type variables within the fixed type cannot contain
1591+
// lvalues either.
1592+
type.visit([&](Type t) {
1593+
if (auto *tvt = dyn_cast<TypeVariableType>(t.getPointer()))
1594+
typeVar->getImpl().setCannotBindToLValue(getSavedBindings());
1595+
});
1596+
}
1597+
15911598
assignFixedType(typeVar, type);
15921599

15931600
return getTypeMatchSuccess();
@@ -1723,7 +1730,8 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
17231730

17241731
// If exactly one of the type variables can bind to an lvalue, we
17251732
// can't merge these two type variables.
1726-
if (rep1->getImpl().canBindToLValue()
1733+
if (kind == ConstraintKind::Equal &&
1734+
rep1->getImpl().canBindToLValue()
17271735
!= rep2->getImpl().canBindToLValue())
17281736
return formUnsolvedResult();
17291737

@@ -1751,46 +1759,44 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
17511759
case ConstraintKind::BindParam: {
17521760
if (typeVar2 && !typeVar1) {
17531761
// Simplify the left-hand type and perform the "occurs" check.
1754-
typeVar2 = getRepresentative(typeVar2);
1762+
auto rep2 = getRepresentative(typeVar2);
17551763
type1 = simplifyType(type1, flags);
17561764
if (!isBindable(typeVar2, type1))
17571765
return formUnsolvedResult();
17581766

17591767
if (auto *iot = type1->getAs<InOutType>()) {
1760-
assignFixedType(typeVar2, LValueType::get(iot->getObjectType()));
1768+
if (!rep2->getImpl().canBindToLValue())
1769+
return getTypeMatchFailure(locator);
1770+
assignFixedType(rep2, LValueType::get(iot->getObjectType()));
17611771
} else {
1762-
assignFixedType(typeVar2, type1);
1772+
assignFixedType(rep2, type1);
17631773
}
17641774
return getTypeMatchSuccess();
17651775
} else if (typeVar1 && !typeVar2) {
17661776
// Simplify the right-hand type and perform the "occurs" check.
1767-
typeVar1 = getRepresentative(typeVar1);
1777+
auto rep1 = getRepresentative(typeVar1);
17681778
type2 = simplifyType(type2, flags);
1769-
if (!isBindable(typeVar1, type2))
1779+
if (!isBindable(rep1, type2))
17701780
return formUnsolvedResult();
17711781

1772-
// If the right-hand side of the BindParam constraint
1773-
// is `lvalue` type, we'll have to make sure that
1774-
// left-hand side is bound to type variable which
1775-
// is wrapped in `inout` type to preserve inout/lvalue pairing.
17761782
if (auto *lvt = type2->getAs<LValueType>()) {
1777-
auto *tv = createTypeVariable(typeVar1->getImpl().getLocator());
1778-
assignFixedType(typeVar1, InOutType::get(tv));
1779-
1780-
typeVar1 = tv;
1781-
type2 = lvt->getObjectType();
1783+
if (!rep1->getImpl().canBindToInOut())
1784+
return getTypeMatchFailure(locator);
1785+
assignFixedType(rep1, InOutType::get(lvt->getObjectType()));
1786+
} else {
1787+
assignFixedType(rep1, type2);
17821788
}
1783-
1784-
// If we have a binding for the right-hand side
1785-
// (argument type used in the body) don't try
1786-
// to bind it to the left-hand side (parameter type)
1787-
// directly, because there could be an implicit
1788-
// conversion between them, and actual binding
1789-
// can only come from the left-hand side.
1790-
addUnsolvedConstraint(
1791-
Constraint::create(*this, ConstraintKind::Equal, typeVar1, type2,
1792-
getConstraintLocator(locator)));
17931789
return getTypeMatchSuccess();
1790+
} if (typeVar1 && typeVar2) {
1791+
auto rep1 = getRepresentative(typeVar1);
1792+
auto rep2 = getRepresentative(typeVar2);
1793+
1794+
if (!rep1->getImpl().canBindToInOut() ||
1795+
!rep2->getImpl().canBindToLValue()) {
1796+
// Merge the equivalence classes corresponding to these two variables.
1797+
mergeEquivalenceClasses(rep1, rep2);
1798+
return getTypeMatchSuccess();
1799+
}
17941800
}
17951801

17961802
return formUnsolvedResult();
@@ -2623,6 +2629,7 @@ ConstraintSystem::simplifyConstructionConstraint(
26232629
auto argType = createTypeVariable(
26242630
getConstraintLocator(locator, ConstraintLocator::ApplyArgument),
26252631
(TVO_CanBindToLValue |
2632+
TVO_CanBindToInOut |
26262633
TVO_PrefersSubtypeBinding));
26272634
addConstraint(ConstraintKind::FunctionInput, memberType, argType, locator);
26282635
}

lib/Sema/ConstraintGraph.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,7 @@ bool ConstraintGraph::contractEdges() {
698698
auto type = binding.BindingType;
699699
isNotContractable = type.findIf([&](Type nestedType) -> bool {
700700
if (auto tv = nestedType->getAs<TypeVariableType>()) {
701-
if (!tv->getImpl().mustBeMaterializable())
701+
if (tv->getImpl().canBindToInOut())
702702
return true;
703703
}
704704

lib/Sema/ConstraintSystem.cpp

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -201,23 +201,6 @@ void ConstraintSystem::assignFixedType(TypeVariableType *typeVar, Type type,
201201
addTypeVariableConstraintsToWorkList(typeVar);
202202
}
203203

204-
void ConstraintSystem::setMustBeMaterializableRecursive(Type type)
205-
{
206-
assert(type->isMaterializable() &&
207-
"argument to setMustBeMaterializableRecursive may not be inherently "
208-
"non-materializable");
209-
type = getFixedTypeRecursive(type, /*wantRValue=*/false);
210-
type = type->lookThroughAllOptionalTypes();
211-
212-
if (auto typeVar = type->getAs<TypeVariableType>()) {
213-
typeVar->getImpl().setMustBeMaterializable(getSavedBindings());
214-
} else if (auto *tupleTy = type->getAs<TupleType>()) {
215-
for (auto elt : tupleTy->getElementTypes()) {
216-
setMustBeMaterializableRecursive(elt);
217-
}
218-
}
219-
}
220-
221204
void ConstraintSystem::addTypeVariableConstraintsToWorkList(
222205
TypeVariableType *typeVar) {
223206
// Gather the constraints affected by a change to this type variable.

lib/Sema/ConstraintSystem.h

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -232,11 +232,6 @@ class TypeVariableType::Implementation {
232232
return getRawOptions() & TVO_PrefersSubtypeBinding;
233233
}
234234

235-
bool mustBeMaterializable() const {
236-
return !(getRawOptions() & TVO_CanBindToInOut) &&
237-
!(getRawOptions() & TVO_CanBindToLValue);
238-
}
239-
240235
/// Retrieve the corresponding node in the constraint graph.
241236
constraints::ConstraintGraphNode *getGraphNode() const { return GraphNode; }
242237

@@ -343,10 +338,16 @@ class TypeVariableType::Implementation {
343338
if (record)
344339
otherRep->getImpl().recordBinding(*record);
345340
otherRep->getImpl().ParentOrFixed = getTypeVariable();
346-
if (!mustBeMaterializable() && otherRep->getImpl().mustBeMaterializable()) {
341+
342+
if (canBindToLValue() && !otherRep->getImpl().canBindToLValue()) {
347343
if (record)
348344
recordBinding(*record);
349345
getTypeVariable()->Bits.TypeVariableType.Options &= ~TVO_CanBindToLValue;
346+
}
347+
348+
if (canBindToInOut() && !otherRep->getImpl().canBindToInOut()) {
349+
if (record)
350+
recordBinding(*record);
350351
getTypeVariable()->Bits.TypeVariableType.Options &= ~TVO_CanBindToInOut;
351352
}
352353
}
@@ -380,15 +381,13 @@ class TypeVariableType::Implementation {
380381
rep->getImpl().ParentOrFixed = type.getPointer();
381382
}
382383

383-
void setMustBeMaterializable(constraints::SavedTypeVariableBindings *record) {
384+
void setCannotBindToLValue(constraints::SavedTypeVariableBindings *record) {
384385
auto rep = getRepresentative(record);
385-
if (!rep->getImpl().mustBeMaterializable()) {
386+
if (rep->getImpl().canBindToLValue()) {
386387
if (record)
387388
rep->getImpl().recordBinding(*record);
388389
rep->getImpl().getTypeVariable()->Bits.TypeVariableType.Options
389390
&= ~TVO_CanBindToLValue;
390-
rep->getImpl().getTypeVariable()->Bits.TypeVariableType.Options
391-
&= ~TVO_CanBindToInOut;
392391
}
393392
}
394393

@@ -2114,11 +2113,6 @@ class ConstraintSystem {
21142113
/// a complete solution from partial solutions.
21152114
void assignFixedType(TypeVariableType *typeVar, Type type,
21162115
bool updateState = true);
2117-
2118-
/// Set the TVO_MustBeMaterializable bit on all type variables
2119-
/// necessary to ensure that the type in question is materializable in a
2120-
/// viable solution.
2121-
void setMustBeMaterializableRecursive(Type type);
21222116

21232117
/// Determine if the type in question is an Array<T> and, if so, provide the
21242118
/// element type of the array.

test/Constraints/generics.swift

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func generic_metatypes<T : SomeProtocol>(_ x: T)
5252
}
5353

5454
// Inferring a variable's type from a call to a generic.
55-
struct Pair<T, U> { } // expected-note 4 {{'T' declared as parameter to type 'Pair'}} expected-note {{'U' declared as parameter to type 'Pair'}}
55+
struct Pair<T, U> { } // expected-note 3 {{'T' declared as parameter to type 'Pair'}} expected-note 2 {{'U' declared as parameter to type 'Pair'}}
5656

5757
func pair<T, U>(_ x: T, _ y: U) -> Pair<T, U> { }
5858

@@ -364,7 +364,7 @@ func testFixItCasting(x: Any) {
364364

365365
func testFixItContextualKnowledge() {
366366
// FIXME: These could propagate backwards.
367-
let _: Int = Pair().first // expected-error {{generic parameter 'T' could not be inferred}} expected-note {{explicitly specify the generic arguments to fix this issue}} {{20-20=<Any, Any>}}
367+
let _: Int = Pair().first // expected-error {{generic parameter 'U' could not be inferred}} expected-note {{explicitly specify the generic arguments to fix this issue}} {{20-20=<Any, Any>}}
368368
let _: Int = Pair().second // expected-error {{generic parameter 'T' could not be inferred}} expected-note {{explicitly specify the generic arguments to fix this issue}} {{20-20=<Any, Any>}}
369369
}
370370

@@ -622,7 +622,7 @@ func rdar40537858() {
622622
let _: E = .bar([s]) // expected-error {{enum case 'bar' requires that 'S' conform to 'P'}}
623623
}
624624

625-
// SR-8934
625+
// https://bugs.swift.org/browse/SR-8934
626626
struct BottleLayout {
627627
let count : Int
628628
}
@@ -631,3 +631,10 @@ let layout = BottleLayout(count:1)
631631
let ix = arr.firstIndex(of:layout) // expected-error {{argument type 'BottleLayout' does not conform to expected type 'Equatable'}}
632632

633633
let _: () -> UInt8 = { .init("a" as Unicode.Scalar) } // expected-error {{initializer 'init(_:)' requires that 'Unicode.Scalar' conform to 'BinaryInteger'}}
634+
635+
// https://bugs.swift.org/browse/SR-9068
636+
func compare<C: Collection, Key: Hashable, Value: Equatable>(c: C)
637+
-> Bool where C.Element == (key: Key, value: Value)
638+
{
639+
_ = Dictionary(uniqueKeysWithValues: Array(c))
640+
}

0 commit comments

Comments
 (0)