Skip to content

Commit 4b921c3

Browse files
[Sema] Improve diagnostics for key path root type inferred as option accessing wrapped member
1 parent 148ba9d commit 4b921c3

File tree

4 files changed

+37
-6
lines changed

4 files changed

+37
-6
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,13 +1082,22 @@ NOTE(unwrap_with_guard,none,
10821082
ERROR(optional_base_not_unwrapped,none,
10831083
"value of optional type %0 must be unwrapped to refer to member %1 of "
10841084
"wrapped base type %2", (Type, DeclNameRef, Type))
1085+
ERROR(invalid_optional_infered_keypath_root, none,
1086+
"key path root inferred as optional type %0 must be unwrapped to refer to member %1 "
1087+
"of unwrapped type %2", (Type, DeclNameRef, Type))
10851088
NOTE(optional_base_chain,none,
10861089
"chain the optional using '?' to access member %0 only for non-'nil' "
10871090
"base values", (DeclNameRef))
10881091
NOTE(optional_base_remove_optional_for_keypath_root, none,
10891092
"use unwrapped type %0 as key path root", (Type))
10901093
NOTE(optional_keypath_application_base, none,
10911094
"use '?' to access key path subscript only for non-'nil' base values", ())
1095+
NOTE(optional_key_path_root_base_chain, none,
1096+
"chain the optional using '?.' to access unwrapped type member %0",
1097+
(DeclNameRef))
1098+
NOTE(optional_key_path_root_base_unwrap, none,
1099+
"unwrap the optional using '!.' to access unwrapped type member %0",
1100+
(DeclNameRef))
10921101

10931102
ERROR(missing_unwrap_optional_try,none,
10941103
"value of optional type %0 not unwrapped; did you mean to use 'try!' "

lib/Sema/CSDiagnostics.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,9 +1071,6 @@ bool MemberAccessOnOptionalBaseFailure::diagnoseAsError() {
10711071
return false;
10721072

10731073
auto sourceRange = getSourceRange();
1074-
1075-
emitDiagnostic(diag::optional_base_not_unwrapped,
1076-
baseType, Member, unwrappedBaseType);
10771074

10781075
auto componentPathElt =
10791076
locator->getLastElementAs<LocatorPathElt::KeyPathComponent>();
@@ -1082,12 +1079,25 @@ bool MemberAccessOnOptionalBaseFailure::diagnoseAsError() {
10821079
// let's emit a tailored note suggesting to use its unwrapped type.
10831080
auto *keyPathExpr = castToExpr<KeyPathExpr>(getAnchor());
10841081
if (auto rootType = keyPathExpr->getRootType()) {
1082+
emitDiagnostic(diag::optional_base_not_unwrapped, baseType, Member,
1083+
unwrappedBaseType);
1084+
10851085
emitDiagnostic(diag::optional_base_remove_optional_for_keypath_root,
10861086
unwrappedBaseType)
10871087
.fixItReplace(rootType->getSourceRange(),
10881088
unwrappedBaseType.getString());
1089+
} else {
1090+
emitDiagnostic(diag::invalid_optional_infered_keypath_root, baseType,
1091+
Member, unwrappedBaseType);
1092+
emitDiagnostic(diag::optional_key_path_root_base_chain, Member)
1093+
.fixItInsert(sourceRange.End, "?.");
1094+
emitDiagnostic(diag::optional_key_path_root_base_unwrap, Member)
1095+
.fixItInsert(sourceRange.End, "!.");
10891096
}
10901097
} else {
1098+
emitDiagnostic(diag::optional_base_not_unwrapped, baseType, Member,
1099+
unwrappedBaseType);
1100+
10911101
// FIXME: It would be nice to immediately offer "base?.member ?? defaultValue"
10921102
// for non-optional results where that would be appropriate. For the moment
10931103
// always offering "?" means that if the user chooses chaining, we'll end up

localization/diagnostics/en.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3136,6 +3136,9 @@
31363136
- id: optional_base_not_unwrapped
31373137
msg: "value of optional type %0 must be unwrapped to refer to member %1 of wrapped base type %2"
31383138

3139+
- id: invalid_optional_infered_keypath_root
3140+
msg: "key path root inferred as optional type %0 must be unwrapped to refer to member %1 of unwrapped type %2"
3141+
31393142
- id: optional_base_chain
31403143
msg: "chain the optional using '?' to access member %0 only for non-'nil' base values"
31413144

@@ -3145,6 +3148,12 @@
31453148
- id: optional_keypath_application_base
31463149
msg: "use '?' to access key path subscript only for non-'nil' base values"
31473150

3151+
- id: optional_key_path_root_base_chain
3152+
msg: "chain the optional using '?.' to access unwrapped type member %0"
3153+
3154+
- id: optional_key_path_root_base_unwrap
3155+
msg: "unwrap the optional using '!.' to access unwrapped type member %0"
3156+
31483157
- id: missing_unwrap_optional_try
31493158
msg: "value of optional type %0 not unwrapped; did you mean to use 'try!' or chain with '?'?"
31503159

test/expr/unary/keypath/keypath.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,9 +1006,12 @@ func testMemberAccessOnOptionalKeyPathComponent() {
10061006
// expected-error@-1 {{value of optional type '(Int, Int)?' must be unwrapped to refer to member '0' of wrapped base type '(Int, Int)'}}
10071007
// expected-note@-2 {{use unwrapped type '(Int, Int)' as key path root}}{{4-15=(Int, Int)}}
10081008

1009-
// TODO(diagnostics) Improve diagnostics refering to key path root not able to be infered as an optional type.
1010-
SR5688_KP(\.count)
1011-
// expected-error@-1 {{value of optional type 'String?' must be unwrapped to refer to member 'count' of wrapped base type 'String'}}
1009+
SR5688_KP(\.count) // expected-error {{key path root inferred as optional type 'String?' must be unwrapped to refer to member 'count' of unwrapped type 'String'}}
1010+
// expected-note@-1 {{chain the optional using '?.' to access unwrapped type member 'count'}} {{15-15=?.}}
1011+
// expected-note@-2 {{unwrap the optional using '!.' to access unwrapped type member 'count'}} {{15-15=!.}}
1012+
let _ : KeyPath<String?, Int> = \.count // expected-error {{key path root inferred as optional type 'String?' must be unwrapped to refer to member 'count' of unwrapped type 'String'}}
1013+
// expected-note@-1 {{chain the optional using '?.' to access unwrapped type member 'count'}} {{37-37=?.}}
1014+
// expected-note@-2 {{unwrap the optional using '!.' to access unwrapped type member 'count'}} {{37-37=!.}}
10121015
}
10131016

10141017
func testSyntaxErrors() {

0 commit comments

Comments
 (0)