Skip to content

Commit 9a62701

Browse files
committed
[ConstraintSystem] Use new branch element and fix mismatch between ternary branches
1 parent be3f949 commit 9a62701

File tree

4 files changed

+67
-15
lines changed

4 files changed

+67
-15
lines changed

lib/Sema/CSGen.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2616,18 +2616,18 @@ namespace {
26162616
CS.addConstraint(
26172617
ConstraintKind::Conversion, CS.getType(expr->getCondExpr()),
26182618
boolDecl->getDeclaredType(),
2619-
CS.getConstraintLocator(expr, LocatorPathElt::Condition()));
2619+
CS.getConstraintLocator(expr, ConstraintLocator::Condition));
26202620

26212621
// The branches must be convertible to a common type.
2622-
return CS.addJoinConstraint(CS.getConstraintLocator(expr),
2623-
{
2624-
{ CS.getType(expr->getThenExpr()),
2625-
CS.getConstraintLocator(expr->getThenExpr()) },
2626-
{ CS.getType(expr->getElseExpr()),
2627-
CS.getConstraintLocator(expr->getElseExpr()) }
2628-
});
2622+
return CS.addJoinConstraint(
2623+
CS.getConstraintLocator(expr),
2624+
{{CS.getType(expr->getThenExpr()),
2625+
CS.getConstraintLocator(expr, LocatorPathElt::TernaryBranch(true))},
2626+
{CS.getType(expr->getElseExpr()),
2627+
CS.getConstraintLocator(expr,
2628+
LocatorPathElt::TernaryBranch(false))}});
26292629
}
2630-
2630+
26312631
virtual Type visitImplicitConversionExpr(ImplicitConversionExpr *expr) {
26322632
llvm_unreachable("Already type-checked");
26332633
}

lib/Sema/CSSimplify.cpp

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2804,6 +2804,13 @@ bool ConstraintSystem::repairFailures(
28042804
});
28052805
};
28062806

2807+
auto markAnyTypeVarsAsPotentialHoles = [&](Type type) {
2808+
type.visit([&](Type subType) {
2809+
if (auto *typeVar = subType->getAs<TypeVariableType>())
2810+
recordPotentialHole(typeVar);
2811+
});
2812+
};
2813+
28072814
if (path.empty()) {
28082815
if (!anchor)
28092816
return false;
@@ -3663,6 +3670,33 @@ bool ConstraintSystem::repairFailures(
36633670
break;
36643671
}
36653672

3673+
case ConstraintLocator::TernaryBranch: {
3674+
markAnyTypeVarsAsPotentialHoles(lhs);
3675+
markAnyTypeVarsAsPotentialHoles(rhs);
3676+
3677+
// If `if` expression has a contextual type, let's consider it a source of
3678+
// truth and produce a contextual mismatch instead of per-branch failure,
3679+
// because it's a better pointer than potential then-to-else type mismatch.
3680+
if (auto contextualType = getContextualType(anchor)) {
3681+
if (contextualType->isEqual(rhs)) {
3682+
auto *loc =
3683+
getConstraintLocator(anchor, LocatorPathElt::ContextualType());
3684+
if (hasFixFor(loc, FixKind::ContextualMismatch))
3685+
return true;
3686+
3687+
conversionsOrFixes.push_back(
3688+
ContextualMismatch::create(*this, lhs, rhs, loc));
3689+
break;
3690+
}
3691+
}
3692+
3693+
// If there is no contextual type, this is most likely a contextual type
3694+
// mismatch between then/else branches of ternary operator.
3695+
conversionsOrFixes.push_back(ContextualMismatch::create(
3696+
*this, lhs, rhs, getConstraintLocator(locator)));
3697+
break;
3698+
}
3699+
36663700
default:
36673701
break;
36683702
}
@@ -8626,7 +8660,24 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
86268660
}
86278661

86288662
case FixKind::ContextualMismatch: {
8629-
if (recordFix(fix))
8663+
auto impact = 1;
8664+
8665+
auto locator = fix->getLocator();
8666+
if (auto branchElt =
8667+
locator->getLastElementAs<LocatorPathElt::TernaryBranch>()) {
8668+
// If this is `else` branch of a ternary operator, let's
8669+
// increase its impact to eliminate the chance of ambiguity.
8670+
//
8671+
// Branches are connected through two `subtype` constraints
8672+
// to a common type variable with represents their join, which
8673+
// means that result would attempt a type from each side if
8674+
// one is available and that would result in two fixes - one for
8675+
// each mismatched branch.
8676+
if (branchElt->forElse())
8677+
impact = 10;
8678+
}
8679+
8680+
if (recordFix(fix, impact))
86308681
return SolutionKind::Error;
86318682

86328683
if (auto *fnType1 = type1->getAs<FunctionType>()) {

test/Constraints/diagnostics.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,8 @@ func r18800223(_ i : Int) {
289289

290290

291291
var buttonTextColor: String?
292-
_ = (buttonTextColor != nil) ? 42 : {$0}; // expected-error {{unable to infer closure type in the current context}}
292+
_ = (buttonTextColor != nil) ? 42 : {$0}; // expected-error {{result values in '? :' expression have mismatching types 'Int' and '(_) -> _'}}
293+
// expected-error@-1 {{unable to infer closure return type; add explicit type to disambiguate}}
293294
}
294295

295296
// <rdar://problem/21883806> Bogus "'_' can only appear in a pattern or on the left side of an assignment" is back

test/Constraints/one_way_constraints.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ func testTernaryOneWay(b: Bool) {
1010
let _: Float = b ? 3.14159 : 17
1111

1212
// Errors due to one-way inference.
13-
let _: Float = b ? Builtin.one_way(3.14159) // expected-error{{cannot convert value of type 'Double' to specified type 'Float'}}
13+
let _: Float = b ? Builtin.one_way(3.14159) // expected-error{{result values in '? :' expression have mismatching types 'Double' and 'Int'}}
1414
: 17
15-
let _: Float = b ? 3.14159
16-
: Builtin.one_way(17) // expected-error{{cannot convert value of type 'Int' to specified type 'Float'}}
17-
let _: Float = b ? Builtin.one_way(3.14159) // expected-error{{cannot convert value of type 'Double' to specified type 'Float'}}
15+
let _: Float = b ? 3.14159 // expected-error {{cannot convert value of type 'Int' to specified type 'Float'}}
16+
: Builtin.one_way(17)
17+
let _: Float = b ? Builtin.one_way(3.14159) // expected-error {{cannot convert value of type 'Int' to specified type 'Float'}}
1818
: Builtin.one_way(17)
1919

2020
// Okay: default still works.

0 commit comments

Comments
 (0)