Skip to content

Commit 7b9cffd

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.
1 parent 9308796 commit 7b9cffd

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
@@ -4544,14 +4544,30 @@ repairViaOptionalUnwrap(ConstraintSystem &cs, Type fromType, Type toType,
45444544
if (!anchor)
45454545
return false;
45464546

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

45564572
// `OptionalEvaluationExpr` doesn't add a new level of
45574573
// 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)