Skip to content

Commit fb0a484

Browse files
committed
[ConstraintSystem] Let try? infer type from sub-expression even with contextual mismatch
This helps to diagnose contextual mismatches like `Int? vs. Bool` instead of suggesting to unwrap the optional which would still produce an incorrect type.
1 parent 0103041 commit fb0a484

File tree

3 files changed

+20
-4
lines changed

3 files changed

+20
-4
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1958,6 +1958,17 @@ bool ContextualFailure::diagnoseAsError() {
19581958
if (diagnoseYieldByReferenceMismatch())
19591959
return true;
19601960

1961+
if (auto *OTE = dyn_cast<OptionalTryExpr>(anchor)) {
1962+
auto tryType = fromType->getOptionalObjectType();
1963+
if (tryType->isEqual(toType)) {
1964+
auto &cs = getConstraintSystem();
1965+
MissingOptionalUnwrapFailure failure(cs, getType(OTE), toType,
1966+
cs.getConstraintLocator(OTE));
1967+
if (failure.diagnoseAsError())
1968+
return true;
1969+
}
1970+
}
1971+
19611972
if (CTP == CTP_ForEachStmt) {
19621973
if (fromType->isAnyExistentialType()) {
19631974
emitDiagnostic(anchor->getLoc(), diag::type_cannot_conform,

lib/Sema/CSSimplify.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2644,7 +2644,13 @@ repairViaOptionalUnwrap(ConstraintSystem &cs, Type fromType, Type toType,
26442644
// language mode, so we can safely try to bind its
26452645
// object type to contextual type without risk of
26462646
// causing more optionality mismatches down the road.
2647-
matchKind = ConstraintKind::Bind;
2647+
auto last = locator.last();
2648+
// For contextual conversions let's give `try?` a chance to
2649+
// infer inner type which, if incorrect, should result in
2650+
// contextual conversion failure instead of optional unwrap.
2651+
matchKind = last && last->is<LocatorPathElt::ContextualType>()
2652+
? ConstraintKind::Conversion
2653+
: ConstraintKind::Bind;
26482654
}
26492655
}
26502656

test/Parse/try.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -236,13 +236,12 @@ struct ThingProducer {
236236
}
237237

238238
let optProducer: ThingProducer? = ThingProducer()
239-
// In Swift 4 mode try? always adds a new level of optionality so suggesting `try!` doesn't really help in these examples.
240-
let _: Int? = try? optProducer?.produceInt() // expected-error {{cannot convert value of type 'Int??' to specified type 'Int?'}}
239+
let _: Int? = try? optProducer?.produceInt() // expected-error {{value of optional type 'Int??' not unwrapped; did you mean to use 'try!' or chain with '?'?}}
241240
let _: Int = try? optProducer?.produceInt() // expected-error {{cannot convert value of type 'Int??' to specified type 'Int'}}
242241
let _: String = try? optProducer?.produceInt() // expected-error {{cannot convert value of type 'Int??' to specified type 'String'}}
243242
let _: Int?? = try? optProducer?.produceInt() // good
244243

245-
let _: Int? = try? optProducer?.produceIntNoThrowing() // expected-error {{cannot convert value of type 'Int??' to specified type 'Int?'}}
244+
let _: Int? = try? optProducer?.produceIntNoThrowing() // expected-error {{value of optional type 'Int??' not unwrapped; did you mean to use 'try!' or chain with '?'?}}
246245
let _: Int?? = try? optProducer?.produceIntNoThrowing() // expected-warning {{no calls to throwing functions occur within 'try' expression}}
247246

248247
let _: Int? = (try? optProducer?.produceAny()) as? Int // good

0 commit comments

Comments
 (0)