Skip to content

Commit 7a4e67e

Browse files
authored
Merge pull request #21825 from slavapestov/solve-bind-constraint-5.0
Sema: Solve Bind constraints involving to two variables of different lvalue-ness [5.0]
2 parents 5a827a9 + 19914ce commit 7a4e67e

File tree

6 files changed

+40
-46
lines changed

6 files changed

+40
-46
lines changed

lib/Sema/CSGen.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1605,6 +1605,7 @@ namespace {
16051605
CS.getConstraintLocator(expr,
16061606
ConstraintLocator::ApplyArgument),
16071607
(TVO_CanBindToLValue |
1608+
TVO_CanBindToInOut |
16081609
TVO_PrefersSubtypeBinding));
16091610
CS.addConstraint(
16101611
ConstraintKind::FunctionInput, methodTy, argTy,

lib/Sema/CSSimplify.cpp

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1579,6 +1579,12 @@ ConstraintSystem::matchTypesBindTypeVar(
15791579
// If the left-hand type variable cannot bind to an lvalue,
15801580
// but we still have an lvalue, fail.
15811581
if (!typeVar->getImpl().canBindToLValue() && type->hasLValueType()) {
1582+
return getTypeMatchFailure(locator);
1583+
}
1584+
1585+
// If the left-hand type variable cannot bind to an inout,
1586+
// but we still have an inout, fail.
1587+
if (!typeVar->getImpl().canBindToInOut() && type->is<InOutType>()) {
15821588
return getTypeMatchFailure(locator);
15831589
}
15841590

@@ -1600,15 +1606,6 @@ ConstraintSystem::matchTypesBindTypeVar(
16001606
}
16011607
}
16021608

1603-
// Check whether the type variable must be bound to a materializable
1604-
// type.
1605-
if (typeVar->getImpl().mustBeMaterializable()) {
1606-
if (!type->isMaterializable())
1607-
return getTypeMatchFailure(locator);
1608-
1609-
setMustBeMaterializableRecursive(type);
1610-
}
1611-
16121609
// Okay. Bind below.
16131610

16141611
// A constraint that binds any pointer to a void pointer is
@@ -1620,6 +1617,16 @@ ConstraintSystem::matchTypesBindTypeVar(
16201617
return getTypeMatchSuccess();
16211618
}
16221619

1620+
if (!typeVar->getImpl().canBindToLValue()) {
1621+
// When binding a fixed type to a type variable that cannot contain
1622+
// lvalues, any type variables within the fixed type cannot contain
1623+
// lvalues either.
1624+
type.visit([&](Type t) {
1625+
if (auto *tvt = dyn_cast<TypeVariableType>(t.getPointer()))
1626+
typeVar->getImpl().setCannotBindToLValue(getSavedBindings());
1627+
});
1628+
}
1629+
16231630
assignFixedType(typeVar, type);
16241631

16251632
return getTypeMatchSuccess();
@@ -1755,7 +1762,8 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
17551762

17561763
// If exactly one of the type variables can bind to an lvalue, we
17571764
// can't merge these two type variables.
1758-
if (rep1->getImpl().canBindToLValue()
1765+
if (kind == ConstraintKind::Equal &&
1766+
rep1->getImpl().canBindToLValue()
17591767
!= rep2->getImpl().canBindToLValue())
17601768
return formUnsolvedResult();
17611769

@@ -2660,6 +2668,7 @@ ConstraintSystem::simplifyConstructionConstraint(
26602668
auto argType = createTypeVariable(
26612669
getConstraintLocator(locator, ConstraintLocator::ApplyArgument),
26622670
(TVO_CanBindToLValue |
2671+
TVO_CanBindToInOut |
26632672
TVO_PrefersSubtypeBinding));
26642673
addConstraint(ConstraintKind::FunctionInput, memberType, argType, locator);
26652674
}

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

@@ -2083,11 +2082,6 @@ class ConstraintSystem {
20832082
void assignFixedType(TypeVariableType *typeVar, Type type,
20842083
bool updateState = true);
20852084

2086-
/// \brief Set the TVO_MustBeMaterializable bit on all type variables
2087-
/// necessary to ensure that the type in question is materializable in a
2088-
/// viable solution.
2089-
void setMustBeMaterializableRecursive(Type type);
2090-
20912085
/// Determine if the type in question is an Array<T> and, if so, provide the
20922086
/// element type of the array.
20932087
static Optional<Type> isArrayType(Type type);

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)