Skip to content

Commit 9ec3b00

Browse files
committed
[Type Checker] Improve diagnostic when referencing a member of an optional base.
Improve diagnostics when referencing a member of an optional base, where the Optional type does not have the member but the wrapped type does. Specifically, suggest both the chaining ‘?’ and the force-unwrapping ‘!’ Fix-Its via explanatory notes, e.g.: error: value of optional type '[Int]?' must be unwrapped to refer to member 'subscript' of wrapped base type '[Int]' return foo.array[0] ^ note: chain the optional using '?' to access member 'subscript' only for non-'nil' base values return foo.array[0] ^ ? note: force-unwrap using '!' to abort execution if the optional value contains 'nil' return foo.array[0] ^ ! More of rdar://problem/42081852.
1 parent 945c09b commit 9ec3b00

File tree

4 files changed

+26
-12
lines changed

4 files changed

+26
-12
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -915,6 +915,12 @@ NOTE(unwrap_with_default_value,none,
915915
NOTE(unwrap_with_force_value,none,
916916
"force-unwrap using '!' to abort execution if the optional value contains "
917917
"'nil'", ())
918+
ERROR(optional_base_not_unwrapped,none,
919+
"value of optional type %0 must be unwrapped to refer to member %1 of "
920+
"wrapped base type %2", (Type, DeclName, Type))
921+
NOTE(optional_base_chain,none,
922+
"chain the optional using '?' to access member %0 only for non-'nil' "
923+
"base values", (DeclName))
918924
ERROR(missing_unwrap_optional_try,none,
919925
"value of optional type %0 not unwrapped; did you mean to use 'try!' "
920926
"or chain with '?'?",

lib/Sema/CSDiag.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8067,14 +8067,14 @@ bool FailureDiagnosis::diagnoseMemberFailures(
80678067
}
80688068

80698069
if (!optionalResult.ViableCandidates.empty()) {
8070-
// By default we assume that the LHS type is not optional.
8071-
StringRef fixIt = "!";
8072-
auto contextualType = CS.getContextualType();
8073-
if (contextualType && isa<OptionalType>(contextualType.getPointer()))
8074-
fixIt = "?";
8075-
8076-
diagnose(BaseLoc, diag::missing_unwrap_optional, baseObjTy)
8077-
.fixItInsertAfter(baseExpr->getEndLoc(), fixIt);
8070+
diagnose(BaseLoc, diag::optional_base_not_unwrapped,
8071+
baseObjTy, memberName, OT->getOptionalObjectType())
8072+
.highlight(memberRange);
8073+
8074+
diagnose(BaseLoc, diag::optional_base_chain, memberName)
8075+
.fixItInsertAfter(baseExpr->getEndLoc(), "?");
8076+
diagnose(BaseLoc, diag::unwrap_with_force_value)
8077+
.fixItInsertAfter(baseExpr->getEndLoc(), "!");
80788078
return true;
80798079
}
80808080
}

test/Constraints/diagnostics.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,9 @@ struct StructWithOptionalArray {
221221
}
222222

223223
func testStructWithOptionalArray(_ foo: StructWithOptionalArray) -> Int {
224-
return foo.array[0] // expected-error {{value of optional type '[Int]?' not unwrapped; did you mean to use '!' or '?'?}} {{19-19=!}}
224+
return foo.array[0] // expected-error {{value of optional type '[Int]?' must be unwrapped to refer to member 'subscript' of wrapped base type '[Int]'}}
225+
// expected-note@-1{{chain the optional using '?' to access member 'subscript' only for non-'nil' base values}}{{19-19=?}}
226+
// expected-note@-2{{force-unwrap using '!' to abort execution if the optional value contains 'nil'}}{{19-19=!}}
225227
}
226228

227229

test/Constraints/fixes.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,15 @@ struct Q {
148148
let s: String?
149149
}
150150
let q = Q(s: nil)
151-
let a: Int? = q.s.utf8 // expected-error{{value of optional type 'String?' not unwrapped; did you mean to use '!' or '?'?}} {{18-18=?}}
152-
let b: Int = q.s.utf8 // expected-error{{value of optional type 'String?' not unwrapped; did you mean to use '!' or '?'?}} {{17-17=!}}
153-
let d: Int! = q.s.utf8 // expected-error{{value of optional type 'String?' not unwrapped; did you mean to use '!' or '?'?}} {{18-18=?}}
151+
let a: Int? = q.s.utf8 // expected-error{{value of optional type 'String?' must be unwrapped to refer to member 'utf8' of wrapped base type 'String'}}
152+
// expected-note@-1{{chain the optional using '?'}}{{18-18=?}}
153+
// expected-note@-2{{force-unwrap using '!'}}{{18-18=!}}
154+
let b: Int = q.s.utf8 // expected-error{{value of optional type 'String?' must be unwrapped to refer to member 'utf8' of wrapped base type 'String'}}
155+
// expected-note@-1{{chain the optional using '?'}}{{17-17=?}}
156+
// expected-note@-2{{force-unwrap using '!'}}{{17-17=!}}
157+
let d: Int! = q.s.utf8 // expected-error{{value of optional type 'String?' must be unwrapped to refer to member 'utf8' of wrapped base type 'String'}}
158+
// expected-note@-1{{chain the optional using '?'}}{{18-18=?}}
159+
// expected-note@-2{{force-unwrap using '!'}}{{18-18=!}}
154160
let c = q.s.utf8 // expected-error{{value of optional type 'String?' not unwrapped; did you mean to use '!' or '?'?}} {{12-12=?}}
155161

156162
// SR-1116

0 commit comments

Comments
 (0)