Skip to content

Commit 978a227

Browse files
authored
Merge pull request #69292 from xedin/delay-inference-from-OptionalObject
[CSBindings] Delay inference through OptionalObject if "object" is l-…
2 parents cc830e6 + 6b287bf commit 978a227

File tree

3 files changed

+44
-7
lines changed

3 files changed

+44
-7
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1433,6 +1433,26 @@ PotentialBindings::inferFromRelational(Constraint *constraint) {
14331433
/// those types should be opened.
14341434
void PotentialBindings::infer(Constraint *constraint) {
14351435
switch (constraint->getKind()) {
1436+
case ConstraintKind::OptionalObject: {
1437+
// Inference through optional object is allowed if
1438+
// one of the types is resolved or "optional" type variable
1439+
// cannot be bound to l-value, otherwise there is a
1440+
// risk of binding "optional" to an optional type (inferred from
1441+
// the "object") and discovering an l-value binding for it later.
1442+
auto optionalType = constraint->getFirstType();
1443+
1444+
if (auto *optionalVar = optionalType->getAs<TypeVariableType>()) {
1445+
if (optionalVar->getImpl().canBindToLValue()) {
1446+
auto objectType =
1447+
constraint->getSecondType()->lookThroughAllOptionalTypes();
1448+
if (objectType->isTypeVariableOrMember())
1449+
return;
1450+
}
1451+
}
1452+
1453+
LLVM_FALLTHROUGH;
1454+
}
1455+
14361456
case ConstraintKind::Bind:
14371457
case ConstraintKind::Equal:
14381458
case ConstraintKind::BindParam:
@@ -1442,7 +1462,6 @@ void PotentialBindings::infer(Constraint *constraint) {
14421462
case ConstraintKind::Conversion:
14431463
case ConstraintKind::ArgumentConversion:
14441464
case ConstraintKind::OperatorArgumentConversion:
1445-
case ConstraintKind::OptionalObject:
14461465
case ConstraintKind::UnresolvedMemberChainBase: {
14471466
auto binding = inferFromRelational(constraint);
14481467
if (!binding)

test/Constraints/diagnostics.swift

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,9 +1121,11 @@ func rdar17170728() {
11211121
var j: Int?
11221122
var k: Int? = 2
11231123

1124-
let _ = [i, j, k].reduce(0 as Int?) {
1124+
let _ = [i, j, k].reduce(0 as Int?) { // expected-error {{missing argument label 'into:' in call}}
1125+
// expected-error@-1 {{cannot convert value of type 'Int?' to expected argument type '(inout @escaping (Bool, Bool) -> Bool?, Int?) throws -> ()'}}
11251126
$0 && $1 ? $0! + $1! : ($0 ? $0! : ($1 ? $1! : nil))
1126-
// expected-error@-1 4 {{optional type 'Int?' cannot be used as a boolean; test for '!= nil' instead}}
1127+
// expected-error@-1 {{binary operator '+' cannot be applied to two 'Bool' operands}}
1128+
// expected-error@-2 4 {{cannot force unwrap value of non-optional type 'Bool'}}
11271129
}
11281130

11291131
let _ = [i, j, k].reduce(0 as Int?) { // expected-error {{missing argument label 'into:' in call}}
@@ -1553,18 +1555,18 @@ func testNilCoalescingOperatorRemoveFix() {
15531555
let _ = "" /* This is a comment */ ?? "" // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{13-43=}}
15541556

15551557
let _ = "" // This is a comment
1556-
?? "" // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{1555:13-1556:10=}}
1558+
?? "" // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{1557:13-1558:10=}}
15571559

15581560
let _ = "" // This is a comment
15591561
/*
15601562
* The blank line below is part of the test case, do not delete it
15611563
*/
15621564

1563-
?? "" // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{1558:13-1563:10=}}
1565+
?? "" // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{1560:13-1565:10=}}
15641566

1565-
if ("" ?? // This is a comment // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{9-1566:9=}}
1567+
if ("" ?? // This is a comment // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{9-1568:9=}}
15661568
"").isEmpty {}
15671569

15681570
if ("" // This is a comment
1569-
?? "").isEmpty {} // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{1568:9-1569:12=}}
1571+
?? "").isEmpty {} // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{1570:9-1571:12=}}
15701572
}

test/Constraints/optional.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,3 +598,19 @@ do {
598598
test(x!) // expected-error {{no exact matches in call to local function 'test'}}
599599
// expected-error@-1 {{cannot force unwrap value of non-optional type 'Double'}}
600600
}
601+
602+
// Diagnose cases of invalid chaining when parameter is not optional based on context.
603+
do {
604+
class Test {
605+
var value: Int = 42
606+
}
607+
608+
class Container {
609+
let test: Test = Test()
610+
611+
func loop() {
612+
[test].forEach { $0?.value = 42 }
613+
// expected-error@-1 {{cannot use optional chaining on non-optional value of type 'Test'}}
614+
}
615+
}
616+
}

0 commit comments

Comments
 (0)