Skip to content

Commit fb6ce64

Browse files
authored
Merge pull request #27842 from xedin/if-ternary-diags
[Diagnostics] Improve if/ternary condition expression diagnostics
2 parents 637af2f + 51a0296 commit fb6ce64

10 files changed

+48
-23
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1916,6 +1916,16 @@ bool ContextualFailure::diagnoseAsError() {
19161916
break;
19171917
}
19181918

1919+
case ConstraintLocator::Condition: {
1920+
// Tailored diagnostics for optional or assignment use
1921+
// in condition expression.
1922+
if (diagnoseConversionToBool())
1923+
return true;
1924+
1925+
diagnostic = diag::cannot_convert_condition_value;
1926+
break;
1927+
}
1928+
19191929
case ConstraintLocator::ContextualType: {
19201930
if (diagnoseConversionToBool())
19211931
return true;

lib/Sema/CSGen.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2578,10 +2578,10 @@ namespace {
25782578
if (!boolDecl)
25792579
return Type();
25802580

2581-
CS.addConstraint(ConstraintKind::Conversion,
2582-
CS.getType(expr->getCondExpr()),
2583-
boolDecl->getDeclaredType(),
2584-
CS.getConstraintLocator(expr->getCondExpr()));
2581+
CS.addConstraint(
2582+
ConstraintKind::Conversion, CS.getType(expr->getCondExpr()),
2583+
boolDecl->getDeclaredType(),
2584+
CS.getConstraintLocator(expr, LocatorPathElt::Condition()));
25852585

25862586
// The branches must be convertible to a common type.
25872587
return CS.addJoinConstraint(CS.getConstraintLocator(expr),

lib/Sema/CSSimplify.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3186,6 +3186,12 @@ bool ConstraintSystem::repairFailures(
31863186
break;
31873187
}
31883188

3189+
case ConstraintLocator::Condition: {
3190+
conversionsOrFixes.push_back(IgnoreContextualType::create(
3191+
*this, lhs, rhs, getConstraintLocator(locator)));
3192+
break;
3193+
}
3194+
31893195
default:
31903196
break;
31913197
}

lib/Sema/ConstraintLocator.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ void ConstraintLocator::Profile(llvm::FoldingSetNodeID &id, Expr *anchor,
8686
case KeyPathRoot:
8787
case KeyPathValue:
8888
case KeyPathComponentResult:
89+
case Condition:
8990
auto numValues = numNumericValuesInPathElement(elt.getKind());
9091
for (unsigned i = 0; i < numValues; ++i)
9192
id.AddInteger(elt.getValue(i));
@@ -132,6 +133,7 @@ unsigned LocatorPathElt::getNewSummaryFlags() const {
132133
case ConstraintLocator::KeyPathRoot:
133134
case ConstraintLocator::KeyPathValue:
134135
case ConstraintLocator::KeyPathComponentResult:
136+
case ConstraintLocator::Condition:
135137
return 0;
136138

137139
case ConstraintLocator::FunctionArgument:
@@ -456,6 +458,10 @@ void ConstraintLocator::dump(SourceManager *sm, raw_ostream &out) {
456458
case KeyPathComponentResult:
457459
out << "key path component result";
458460
break;
461+
462+
case Condition:
463+
out << "condition expression";
464+
break;
459465
}
460466
}
461467
out << ']';

lib/Sema/ConstraintLocator.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ class ConstraintLocator : public llvm::FoldingSetNode {
8989
case KeyPathRoot:
9090
case KeyPathValue:
9191
case KeyPathComponentResult:
92+
case Condition:
9293
return 0;
9394

9495
case ContextualType:

lib/Sema/ConstraintLocatorPathElts.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,9 @@ SIMPLE_LOCATOR_PATH_ELT(UnresolvedMember)
164164
/// The candidate witness during protocol conformance checking.
165165
CUSTOM_LOCATOR_PATH_ELT(Witness)
166166

167+
/// The condition associated with 'if' expression or ternary operator.
168+
SIMPLE_LOCATOR_PATH_ELT(Condition)
169+
167170
#undef LOCATOR_PATH_ELT
168171
#undef CUSTOM_LOCATOR_PATH_ELT
169172
#undef SIMPLE_LOCATOR_PATH_ELT

lib/Sema/ConstraintSystem.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2992,6 +2992,12 @@ void constraints::simplifyLocator(Expr *&anchor,
29922992
break;
29932993
}
29942994

2995+
case ConstraintLocator::Condition: {
2996+
anchor = cast<IfExpr>(anchor)->getCondExpr();
2997+
path = path.slice(1);
2998+
continue;
2999+
}
3000+
29953001
default:
29963002
// FIXME: Lots of other cases to handle.
29973003
break;

test/Constraints/diagnostics.swift

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1260,22 +1260,15 @@ func rdar17170728() {
12601260
var j: Int?
12611261
var k: Int? = 2
12621262

1263-
let _ = [i, j, k].reduce(0 as Int?) { // expected-error 3 {{cannot convert value of type 'Int?' to expected element type 'Bool'}}
1264-
// expected-error@-1 {{optional type 'Int?' cannot be used as a boolean; test for '!= nil' instead}}
1263+
let _ = [i, j, k].reduce(0 as Int?) {
12651264
$0 && $1 ? $0! + $1! : ($0 ? $0! : ($1 ? $1! : nil))
1266-
// expected-error@-1 {{binary operator '+' cannot be applied to two 'Bool' operands}}
1267-
// expected-error@-2 4 {{cannot force unwrap value of non-optional type 'Bool'}}
1268-
// expected-error@-3 {{value of optional type 'Bool?' must be unwrapped to a value of type 'Bool'}}
1269-
// expected-note@-4 {{coalesce using '??' to provide a default when the optional value contains 'nil'}}
1270-
// expected-note@-5 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}}
1265+
// expected-error@-1 4 {{optional type 'Int?' cannot be used as a boolean; test for '!= nil' instead}}
12711266
}
12721267

1273-
let _ = [i, j, k].reduce(0 as Int?) { // expected-error 3 {{cannot convert value of type 'Int?' to expected element type 'Bool'}}
1274-
// expected-error@-1 {{missing argument label 'into:' in call}}
1275-
// expected-error@-2 {{optional type 'Int?' cannot be used as a boolean; test for '!= nil' instead}}
1268+
let _ = [i, j, k].reduce(0 as Int?) {
12761269
$0 && $1 ? $0 + $1 : ($0 ? $0 : ($1 ? $1 : nil))
1277-
// expected-error@-1 {{binary operator '+' cannot be applied to two 'Bool' operands}}
1278-
// expected-error@-2 {{'nil' cannot be used in context expecting type 'Bool'}}
1270+
// expected-error@-1 {{binary operator '+' cannot be applied to two 'Int?' operands}}
1271+
// expected-error@-2 4 {{optional type 'Int?' cannot be used as a boolean; test for '!= nil' instead}}
12791272
}
12801273
}
12811274

test/Constraints/if_expr.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ useDouble(c)
2828
useDouble(d)
2929

3030
var z = true ? a : b // expected-error{{result values in '? :' expression have mismatching types 'Int' and 'Double'}}
31-
var _ = a ? b : b // expected-error{{'Int' is not convertible to 'Bool'}}
31+
var _ = a ? b : b // expected-error{{cannot convert value of type 'Int' to expected condition type 'Bool'}}
3232

3333

3434

@@ -51,13 +51,13 @@ useD1(i) // expected-error{{cannot convert value of type 'B' to expected argumen
5151
useD2(i) // expected-error{{cannot convert value of type 'B' to expected argument type 'D2'}}
5252

5353
var x = true ? 1 : 0
54-
var y = 22 ? 1 : 0 // expected-error{{'Int' is not convertible to 'Bool'}}
54+
var y = 22 ? 1 : 0 // expected-error{{cannot convert value of type 'Int' to expected condition type 'Bool'}}
5555

56-
_ = x ? x : x // expected-error {{'Int' is not convertible to 'Bool'}}
56+
_ = x ? x : x // expected-error {{cannot convert value of type 'Int' to expected condition type 'Bool'}}
5757
_ = true ? x : 1.2 // expected-error {{result values in '? :' expression have mismatching types 'Int' and 'Double'}}
5858

59-
_ = (x: true) ? true : false // expected-error {{'(x: Bool)' is not convertible to 'Bool'}}
60-
_ = (x: 1) ? true : false // expected-error {{'(x: Int)' is not convertible to 'Bool'}}
59+
_ = (x: true) ? true : false // expected-error {{cannot convert value of type '(x: Bool)' to expected condition type 'Bool'}}
60+
_ = (x: 1) ? true : false // expected-error {{cannot convert value of type '(x: Int)' to expected condition type 'Bool'}}
6161

6262
let ib: Bool! = false
6363
let eb: Bool? = .some(false)

test/Sema/diag_erroneous_iuo.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,6 @@ struct T {
219219
}
220220

221221
func select(i: Int!, m: Int, t: T) {
222-
let _ = i ? i : m // expected-error {{result values in '? :' expression have mismatching types 'Int?' and 'Int'}}
223-
let _ = t.i ? t.j : t.k // expected-error {{result values in '? :' expression have mismatching types 'Int?' and 'Int'}}
222+
let _ = i ? i : m // expected-error {{optional type 'Int?' cannot be used as a boolean; test for '!= nil' instead}} {{11-11=(}} {{12-12= != nil)}}
223+
let _ = t.i ? t.j : t.k // expected-error {{optional type 'Int?' cannot be used as a boolean; test for '!= nil' instead}} {{11-11=(}} {{14-14= != nil)}}
224224
}

0 commit comments

Comments
 (0)