Skip to content

Commit 15fb957

Browse files
committed
Fix some LValue type checking issues exposed by key paths.
We had an inconsistency in the handling of ConstraintKind::Equal in that we would take $T1 Equal $T2 where $T2 was previously bound to a type, and bind the RValue type of $T2's type to $T1. That does not allow for us to later attempt to bind the LValue type of that type to $T1 (as might happen in simplifying an OptionalObject constraint). Instead, if $T1 can be bound to an LValue and $T2 is not an LValue, we'll defer simplifying the Equal constraint until after $T1 is bound through some other type variable binding or constraint simplification. Fixes rdar://problem/31724272.
1 parent 03b3853 commit 15fb957

File tree

2 files changed

+36
-10
lines changed

2 files changed

+36
-10
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1418,17 +1418,30 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
14181418
}
14191419

14201420
// Provide a fixed type for the type variable.
1421-
bool wantRvalue = kind == ConstraintKind::Equal;
14221421
if (typeVar1) {
14231422
// Simplify the right-hand type and perform the "occurs" check.
14241423
typeVar1 = getRepresentative(typeVar1);
14251424
type2 = simplifyType(type2, flags);
14261425
if (typeVarOccursInType(typeVar1, type2))
14271426
return formUnsolvedResult();
14281427

1429-
// If we want an rvalue, get the rvalue.
1430-
if (wantRvalue)
1431-
type2 = type2->getRValueType();
1428+
// Equal constraints allow mixed LValue/RValue bindings.
1429+
if (kind == ConstraintKind::Equal) {
1430+
// If we could bind an LValue to the type variable, but the
1431+
// type that is already bound is not an LValue, defer
1432+
// simplifying the constraint since we may come along at a
1433+
// later time and attempt to bind the LValue type to this
1434+
// type variable.
1435+
if (typeVar1->getImpl().canBindToLValue()) {
1436+
if (!type2->isLValueType()) {
1437+
return formUnsolvedResult();
1438+
}
1439+
} else {
1440+
// If the type variable does not allow LValue bindings,
1441+
// get the RValue type.
1442+
type2 = type2->getRValueType();
1443+
}
1444+
}
14321445

14331446
// If the left-hand type variable cannot bind to an lvalue,
14341447
// but we still have an lvalue, fail.
@@ -1467,9 +1480,23 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
14671480
if (typeVarOccursInType(typeVar2, type1))
14681481
return formUnsolvedResult();
14691482

1470-
// If we want an rvalue, get the rvalue.
1471-
if (wantRvalue)
1472-
type1 = type1->getRValueType();
1483+
// Equal constraints allow mixed LValue/RValue bindings.
1484+
if (kind == ConstraintKind::Equal) {
1485+
// If we could bind an LValue to the type variable, but the
1486+
// type that is already bound is not an LValue, defer
1487+
// simplifying the constraint since we may come along at a
1488+
// later time and attempt to bind the LValue type to this
1489+
// type variable.
1490+
if (typeVar2->getImpl().canBindToLValue()) {
1491+
if (!type1->isLValueType()) {
1492+
return formUnsolvedResult();
1493+
}
1494+
} else {
1495+
// If the type variable does not allow LValue bindings,
1496+
// get the RValue type.
1497+
type1 = type1->getRValueType();
1498+
}
1499+
}
14731500

14741501
if (!typeVar2->getImpl().canBindToLValue() &&
14751502
type1->isLValueType()) {

test/expr/unary/keypath/keypath.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ struct A: Hashable {
1717

1818
var property: Prop
1919
var optProperty: Prop?
20+
let optLetProperty: Prop?
2021

2122
subscript(sub: Sub) -> A { get { return self } set { } }
2223

@@ -88,9 +89,7 @@ func testKeyPath(sub: Sub, optSub: OptSub, x: Int) {
8889
let _: ReferenceWritableKeyPath<A, Prop> = \.property
8990

9091
// FIXME crash let _: PartialKeyPath<A> = \[sub]
91-
// FIXME should resolve: expected-error@+1{{}}
9292
let _: KeyPath<A, A> = \.[sub]
93-
// FIXME should resolve: expected-error@+1{{}}
9493
let _: WritableKeyPath<A, A> = \.[sub]
9594
// expected-error@+1{{ambiguous}} (need to improve diagnostic)
9695
let _: ReferenceWritableKeyPath<A, A> = \.[sub]
@@ -109,8 +108,8 @@ func testKeyPath(sub: Sub, optSub: OptSub, x: Int) {
109108
// expected-error@+1{{cannot convert}}
110109
let _: ReferenceWritableKeyPath<A, A?> = \.optProperty?[sub]
111110

112-
// FIXME should resolve: expected-error@+1{{}}
113111
let _: KeyPath<A, Prop> = \.optProperty!
112+
let _: KeyPath<A, Prop> = \.optLetProperty!
114113
let _: KeyPath<A, Prop?> = \.property[optSub]?.optProperty!
115114
let _: KeyPath<A, A?> = \.property[optSub]?.optProperty![sub]
116115

0 commit comments

Comments
 (0)