Skip to content

Commit 8d3f361

Browse files
committed
[CSSimplify] Fix should propagate contextual type into optional chain with leading-dot syntax
Member chains with leading-dot syntax can infer the base type only from context, so optionality mismatch with the contextual type should propagate object type down the chain. (cherry picked from commit 7b9cffd)
1 parent 61f3542 commit 8d3f361

File tree

2 files changed

+27
-9
lines changed

2 files changed

+27
-9
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4542,14 +4542,30 @@ repairViaOptionalUnwrap(ConstraintSystem &cs, Type fromType, Type toType,
45424542
if (!anchor)
45434543
return false;
45444544

4545-
bool possibleContextualMismatch = false;
45464545
// If this is a conversion to a non-optional contextual type e.g.
45474546
// `let _: Bool = try? foo()` and `foo()` produces `Int`
45484547
// we should diagnose it as type mismatch instead of missing unwrap.
4549-
if (auto last = locator.last()) {
4550-
possibleContextualMismatch = last->is<LocatorPathElt::ContextualType>() &&
4551-
!toType->getOptionalObjectType();
4552-
}
4548+
bool possibleContextualMismatch = [&]() {
4549+
auto last = locator.last();
4550+
if (!(last && last->is<LocatorPathElt::ContextualType>()))
4551+
return false;
4552+
4553+
// If the contextual type is optional as well, it's definitely a
4554+
// missing unwrap.
4555+
if (toType->getOptionalObjectType())
4556+
return false;
4557+
4558+
// If this is a leading-dot syntax member chain with `?.`
4559+
// notation, it wouldn't be possible to infer the base type
4560+
// without the contextual type, so we have to treat it as
4561+
// a missing unwrap.
4562+
if (auto *OEE = getAsExpr<OptionalEvaluationExpr>(anchor)) {
4563+
if (isExpr<UnresolvedMemberChainResultExpr>(OEE->getSubExpr()))
4564+
return false;
4565+
}
4566+
4567+
return true;
4568+
}();
45534569

45544570
// `OptionalEvaluationExpr` doesn't add a new level of
45554571
// optionality but it could be hiding concrete types

test/expr/delayed-ident/member_chains.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,12 @@ let _: ImplicitMembers = .implicit.getAnotherOptional() // expected-error {{valu
148148
let _: ImplicitMembers = .implicit[optional: ()] // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{49-49= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{49-49=!}}
149149
let _: ImplicitMembers = .implicit[funcOptional: ()]() // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{55-55= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{55-55=!}}
150150

151-
// FIXME: Improve these diagnostics (should probably offer unwrapping, as above)
152-
let _: ImplicitMembers = .implicit.anotherOptional?.another // expected-error{{cannot convert value of type 'Optional<_>' to specified type 'ImplicitMembers'}}
153-
let _: ImplicitMembers = .implicit[optionalFunc: ()]?() // expected-error{{cannot convert value of type 'Optional<_>' to specified type 'ImplicitMembers'}}
154-
151+
let _: ImplicitMembers = .implicit.anotherOptional?.another // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}}
152+
// expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{60-60= ?? <#default value#>}}
153+
// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{26-26=(}} {{60-60=)!}}
154+
let _: ImplicitMembers = .implicit[optionalFunc: ()]?() // expected-error{{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}}
155+
// expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{56-56= ?? <#default value#>}}
156+
// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{26-26=(}} {{56-56=)!}}
155157

156158
let _: ImplicitMembers = .other.implicit
157159
let _: ImplicitMembers = .implicit.anotherOther.implicit

0 commit comments

Comments
 (0)