Skip to content

Commit ccb35fe

Browse files
authored
Merge pull request #63083 from xedin/rdar-104302974
[CSSimplify] Report unresolved base failure if leading-dot syntax bas…
2 parents ac86aed + 7b9cffd commit ccb35fe

File tree

3 files changed

+46
-9
lines changed

3 files changed

+46
-9
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 32 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
@@ -6177,6 +6193,17 @@ bool ConstraintSystem::repairFailures(
61776193
if (rhs->isPlaceholder())
61786194
return true;
61796195

6196+
// The base is a placeholder, let's report an unknown base issue.
6197+
if (lhs->isPlaceholder()) {
6198+
auto *baseExpr =
6199+
castToExpr<UnresolvedMemberChainResultExpr>(anchor)->getChainBase();
6200+
6201+
auto *fix = SpecifyBaseTypeForContextualMember::create(
6202+
*this, baseExpr->getName(), getConstraintLocator(locator));
6203+
conversionsOrFixes.push_back(fix);
6204+
break;
6205+
}
6206+
61806207
if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind, conversionsOrFixes,
61816208
locator))
61826209
break;

test/Constraints/members.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,3 +794,11 @@ func test_diagnose_inaccessible_member_in_ambiguous_context() {
794794

795795
test(\.x) // expected-error {{'x' is inaccessible due to 'private' protection level}}
796796
}
797+
798+
// rdar://104302974
799+
func test_leading_dot_syntax_unknown_base_ambiguity() {
800+
func fn<S: StringProtocol, T: Hashable>(_: S, value: T?) {}
801+
func fn<T: Hashable>(_: String, value: T?) {}
802+
803+
fn("", value: .member) // expected-error {{cannot infer contextual base in reference to member 'member'}}
804+
}

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)