Skip to content

Commit 8a51175

Browse files
committed
[Diagnostics] Don't attempt to force unwrap invalid optional chaining in the argument position
If the argument has an extra `?` or `!`, let's not attempt to force optional (because it's use is already invalid) and re-introduce the constraint with unwrapped type instead. This would help to diagnose the invalid chaining as well as any argument to parameter mismatches. Resolves: rdar://126080504 (cherry picked from commit ef2fa4a)
1 parent d220be4 commit 8a51175

File tree

2 files changed

+31
-1
lines changed

2 files changed

+31
-1
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5883,6 +5883,24 @@ bool ConstraintSystem::repairFailures(
58835883
if (hasConversionOrRestriction(ConversionRestrictionKind::Existential))
58845884
break;
58855885

5886+
if (auto *typeVar =
5887+
lhs->getOptionalObjectType()->getAs<TypeVariableType>()) {
5888+
auto *argLoc = typeVar->getImpl().getLocator();
5889+
if (argLoc->directlyAt<OptionalEvaluationExpr>()) {
5890+
auto OEE = castToExpr<OptionalEvaluationExpr>(argLoc->getAnchor());
5891+
// If the optional chain in the argument position is invalid
5892+
// let's unwrap optional and re-introduce the constraint to
5893+
// be solved later once both sides are sufficiently resolved,
5894+
// this would allow to diagnose not only the invalid unwrap
5895+
// but an invalid conversion (if any) as well.
5896+
if (hasFixFor(getConstraintLocator(OEE->getSubExpr()),
5897+
FixKind::RemoveUnwrap)) {
5898+
addConstraint(matchKind, typeVar, rhs, loc);
5899+
return true;
5900+
}
5901+
}
5902+
}
5903+
58865904
auto result = matchTypes(lhs->getOptionalObjectType(), rhs, matchKind,
58875905
TMF_ApplyingFix, locator);
58885906

test/Constraints/optional.swift

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ func test_force_unwrap_not_being_too_eager() {
435435
// rdar://problem/57097401
436436
func invalidOptionalChaining(a: Any) {
437437
a == "="? // expected-error {{cannot use optional chaining on non-optional value of type 'String'}}
438-
// expected-error@-1 {{binary operator '==' cannot be applied to operands of type 'Any' and 'String?'}}
438+
// expected-error@-1 {{cannot convert value of type 'Any' to expected argument type 'String'}}
439439
}
440440

441441
/// https://github.com/apple/swift/issues/54739
@@ -595,3 +595,15 @@ do {
595595
test(x!) // expected-error {{no exact matches in call to local function 'test'}}
596596
// expected-error@-1 {{cannot force unwrap value of non-optional type 'Double'}}
597597
}
598+
599+
func testExtraQuestionMark(action: () -> Void, v: Int) {
600+
struct Test {
601+
init(action: () -> Void) {}
602+
}
603+
604+
Test(action: action?)
605+
// expected-error@-1 {{cannot use optional chaining on non-optional value of type '() -> Void'}}
606+
Test(action: v?)
607+
// expected-error@-1 {{cannot convert value of type 'Int' to expected argument type '() -> Void'}}
608+
// expected-error@-2 {{cannot use optional chaining on non-optional value of type 'Int'}}
609+
}

0 commit comments

Comments
 (0)