Skip to content

Commit 692bf6f

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. (cherry picked from commit 9ec3b00)
1 parent 02d76b5 commit 692bf6f

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
@@ -898,6 +898,12 @@ NOTE(unwrap_with_default_value,none,
898898
NOTE(unwrap_with_force_value,none,
899899
"force-unwrap using '!' to abort execution if the optional value contains "
900900
"'nil'", ())
901+
ERROR(optional_base_not_unwrapped,none,
902+
"value of optional type %0 must be unwrapped to refer to member %1 of "
903+
"wrapped base type %2", (Type, DeclName, Type))
904+
NOTE(optional_base_chain,none,
905+
"chain the optional using '?' to access member %0 only for non-'nil' "
906+
"base values", (DeclName))
901907
ERROR(missing_unwrap_optional_try,none,
902908
"value of optional type %0 not unwrapped; did you mean to use 'try!' "
903909
"or chain with '?'?",

lib/Sema/CSDiag.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7751,14 +7751,14 @@ bool FailureDiagnosis::diagnoseMemberFailures(
77517751
}
77527752

77537753
if (!optionalResult.ViableCandidates.empty()) {
7754-
// By default we assume that the LHS type is not optional.
7755-
StringRef fixIt = "!";
7756-
auto contextualType = CS.getContextualType();
7757-
if (contextualType && isa<OptionalType>(contextualType.getPointer()))
7758-
fixIt = "?";
7759-
7760-
diagnose(BaseLoc, diag::missing_unwrap_optional, baseObjTy)
7761-
.fixItInsertAfter(baseExpr->getEndLoc(), fixIt);
7754+
diagnose(BaseLoc, diag::optional_base_not_unwrapped,
7755+
baseObjTy, memberName, OT->getOptionalObjectType())
7756+
.highlight(memberRange);
7757+
7758+
diagnose(BaseLoc, diag::optional_base_chain, memberName)
7759+
.fixItInsertAfter(baseExpr->getEndLoc(), "?");
7760+
diagnose(BaseLoc, diag::unwrap_with_force_value)
7761+
.fixItInsertAfter(baseExpr->getEndLoc(), "!");
77627762
return true;
77637763
}
77647764
}

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)