Skip to content

Commit a58db50

Browse files
theblixguyxedin
authored andcommitted
[Diagnostics] Update diagnostics for T! to Any (#23617)
Add a tailored diagnostic for the case where implicitly unwrapped optional is coerced to `Any`
1 parent 2033d4e commit a58db50

File tree

3 files changed

+92
-55
lines changed

3 files changed

+92
-55
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3022,6 +3022,15 @@ WARNING(optional_pattern_match_promotion,none,
30223022
(Type, Type))
30233023
WARNING(optional_to_any_coercion,none,
30243024
"expression implicitly coerced from %0 to %1", (Type, Type))
3025+
WARNING(iuo_to_any_coercion,none,
3026+
"coercion of implicitly unwrappable value of type %0 to %1 does not "
3027+
"unwrap optional", (Type, Type))
3028+
NOTE(iuo_to_any_coercion_note,none,
3029+
"implicitly unwrapped %0 %1 declared here",
3030+
(DescriptiveDeclKind, DeclName))
3031+
NOTE(iuo_to_any_coercion_note_func_result,none,
3032+
"%0 %1 with implicitly unwrapped result type is declared here",
3033+
(DescriptiveDeclKind, DeclName))
30253034
NOTE(default_optional_to_any,none,
30263035
"provide a default value to avoid this warning", ())
30273036
NOTE(force_optional_to_any,none,

lib/Sema/MiscDiagnostics.cpp

Lines changed: 49 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3508,36 +3508,39 @@ static void diagnoseUnintendedOptionalBehavior(TypeChecker &TC, const Expr *E,
35083508
}
35093509

35103510
static bool hasImplicitlyUnwrappedResult(Expr *E) {
3511-
auto getDeclForExpr = [&](Expr *E) -> ValueDecl * {
3512-
if (auto *call = dyn_cast<CallExpr>(E))
3513-
E = call->getDirectCallee();
3511+
auto *decl = getDeclForImplicitlyUnwrappedExpr(E);
35143512

3515-
if (auto *subscript = dyn_cast<SubscriptExpr>(E)) {
3516-
if (subscript->hasDecl())
3517-
return subscript->getDecl().getDecl();
3518-
3519-
return nullptr;
3520-
}
3521-
3522-
if (auto *memberRef = dyn_cast<MemberRefExpr>(E))
3523-
return memberRef->getMember().getDecl();
3524-
if (auto *declRef = dyn_cast<DeclRefExpr>(E))
3525-
return declRef->getDecl();
3526-
if (auto *apply = dyn_cast<ApplyExpr>(E))
3527-
return apply->getCalledValue();
3513+
return decl
3514+
&& decl->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
3515+
}
35283516

3529-
return nullptr;
3530-
};
3517+
static ValueDecl *getDeclForImplicitlyUnwrappedExpr(Expr *E) {
3518+
E = E->getValueProvidingExpr();
35313519

35323520
// Look through implicit conversions like loads, derived-to-base
35333521
// conversion, etc.
3534-
if (auto *ICE = dyn_cast<ImplicitConversionExpr>(E))
3522+
if (auto *ICE = dyn_cast<ImplicitConversionExpr>(E)) {
35353523
E = ICE->getSubExpr();
3524+
}
35363525

3537-
auto *decl = getDeclForExpr(E);
3526+
if (auto *subscript = dyn_cast<SubscriptExpr>(E)) {
3527+
if (subscript->hasDecl())
3528+
return subscript->getDecl().getDecl();
3529+
return nullptr;
3530+
}
35383531

3539-
return decl
3540-
&& decl->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
3532+
if (auto *memberRef = dyn_cast<MemberRefExpr>(E))
3533+
return memberRef->getMember().getDecl();
3534+
3535+
if (auto *declRef = dyn_cast<DeclRefExpr>(E))
3536+
return declRef->getDecl();
3537+
3538+
if (auto *apply = dyn_cast<ApplyExpr>(E)) {
3539+
auto *decl = apply->getCalledValue();
3540+
if (decl && isa<AbstractFunctionDecl>(decl))
3541+
return decl;
3542+
}
3543+
return nullptr;
35413544
}
35423545

35433546
void visitErasureExpr(ErasureExpr *E, OptionalToAnyCoercion coercion) {
@@ -3568,15 +3571,32 @@ static void diagnoseUnintendedOptionalBehavior(TypeChecker &TC, const Expr *E,
35683571
size_t optionalityDifference = 0;
35693572
if (!isOptionalToAnyCoercion(srcType, destType, optionalityDifference))
35703573
return;
3571-
3572-
TC.diagnose(subExpr->getStartLoc(), diag::optional_to_any_coercion,
3573-
/* from */ srcType, /* to */ destType)
3574-
.highlight(subExpr->getSourceRange());
3575-
3574+
3575+
// If we're implicitly unwrapping from IUO to Any then emit a custom
3576+
// diagnostic
3577+
if (hasImplicitlyUnwrappedResult(subExpr)) {
3578+
if (auto decl = getDeclForImplicitlyUnwrappedExpr(subExpr)) {
3579+
TC.diagnose(subExpr->getStartLoc(), diag::iuo_to_any_coercion,
3580+
/* from */ srcType, /* to */ destType)
3581+
.highlight(subExpr->getSourceRange());
3582+
3583+
auto noteDiag = isa<FuncDecl>(decl)
3584+
? diag::iuo_to_any_coercion_note_func_result
3585+
: diag::iuo_to_any_coercion_note;
3586+
3587+
TC.diagnose(decl->getLoc(), noteDiag, decl->getDescriptiveKind(),
3588+
decl->getFullName());
3589+
}
3590+
} else {
3591+
TC.diagnose(subExpr->getStartLoc(), diag::optional_to_any_coercion,
3592+
/* from */ srcType, /* to */ destType)
3593+
.highlight(subExpr->getSourceRange());
3594+
}
3595+
35763596
if (optionalityDifference == 1) {
35773597
TC.diagnose(subExpr->getLoc(), diag::default_optional_to_any)
3578-
.highlight(subExpr->getSourceRange())
3579-
.fixItInsertAfter(subExpr->getEndLoc(), " ?? <#default value#>");
3598+
.highlight(subExpr->getSourceRange())
3599+
.fixItInsertAfter(subExpr->getEndLoc(), " ?? <#default value#>");
35803600
}
35813601

35823602
SmallString<4> forceUnwrapString;

test/Sema/diag_unintended_optional_behavior_swift_5.swift

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,69 +9,69 @@ func takeAny(_ left: Any, _ right: Any) -> Int? {
99
func takesOptionalAny(_: Any?, _: Any?) {}
1010

1111
class C {
12-
var a: Int!
13-
var b: Any?!
14-
func returningIUO() -> Int! { return a }
15-
func returningAny() -> Any { return a } // expected-warning {{expression implicitly coerced from 'Int?' to 'Any'}}
12+
var a: Int! // expected-note 2{{implicitly unwrapped property 'a' declared here}}
13+
var b: Any?! // expected-note {{implicitly unwrapped property 'b' declared here}}
14+
func returningIUO() -> Int! { return a } // expected-note {{instance method 'returningIUO()' with implicitly unwrapped result type is declared here}}
15+
func returningAny() -> Any { return a } // expected-warning {{coercion of implicitly unwrappable value of type 'Int?' to 'Any' does not unwrap optional}}
1616
// expected-note@-1 {{provide a default value to avoid this warning}}{{40-40= ?? <#default value#>}}
1717
// expected-note@-2 {{force-unwrap the value to avoid this warning}}{{40-40=!}}
1818
// expected-note@-3 {{explicitly cast to 'Any' with 'as Any' to silence this warning}}{{40-40= as Any}}
1919

20-
subscript(i: Int) -> Int! { return 0 }
21-
subscript(i: Float) -> Any! { return 0 }
20+
subscript(i: Int) -> Int! { return 0 } // expected-note {{implicitly unwrapped subscript 'subscript(_:)' declared here}}
21+
subscript(i: Float) -> Any! { return 0 } // expected-note {{implicitly unwrapped subscript 'subscript(_:)' declared here}}
2222
}
2323

2424
class D {
25-
init!() {}
25+
init!() {} // expected-note 2{{implicitly unwrapped initializer 'init()' declared here}}
2626
}
2727

28-
func returningIUO() -> Int! { return 1 }
28+
func returningIUO() -> Int! { return 1 } // expected-note {{global function 'returningIUO()' with implicitly unwrapped result type is declared here}}
2929

30-
func warnIUOToAnyCoercion(_ a: Int!, _ b: Any?!) {
31-
_ = takeAny(a, b) // expected-warning {{expression implicitly coerced from 'Int?' to 'Any'}}
30+
func warnIUOToAnyCoercion(_ a: Int!, _ b: Any?!) { // expected-note {{implicitly unwrapped parameter 'a' declared here}} // expected-note {{implicitly unwrapped parameter 'b' declared here}}
31+
_ = takeAny(a, b) // expected-warning {{coercion of implicitly unwrappable value of type 'Int?' to 'Any' does not unwrap optional}}
3232
// expected-note@-1 {{provide a default value to avoid this warning}}{{16-16= ?? <#default value#>}}
3333
// expected-note@-2 {{force-unwrap the value to avoid this warning}}{{16-16=!}}
3434
// expected-note@-3 {{explicitly cast to 'Any' with 'as Any' to silence this warning}}{{16-16= as Any}}
35-
// expected-warning@-4 {{expression implicitly coerced from 'Any??' to 'Any'}}
35+
// expected-warning@-4 {{coercion of implicitly unwrappable value of type 'Any??' to 'Any' does not unwrap optional}}
3636
// expected-note@-5 {{force-unwrap the value to avoid this warning}}{{19-19=!!}}
3737
// expected-note@-6 {{explicitly cast to 'Any' with 'as Any' to silence this warning}}{{19-19= as Any}}
38-
_ = takeAny(returningIUO(), C().returningIUO()) // expected-warning {{expression implicitly coerced from 'Int?' to 'Any'}}
38+
_ = takeAny(returningIUO(), C().returningIUO()) // expected-warning {{coercion of implicitly unwrappable value of type 'Int?' to 'Any' does not unwrap optional}}
3939
// expected-note@-1 {{provide a default value to avoid this warning}}{{29-29= ?? <#default value#>}}
4040
// expected-note@-2 {{force-unwrap the value to avoid this warning}}{{29-29=!}}
4141
// expected-note@-3 {{explicitly cast to 'Any' with 'as Any' to silence this warning}}{{29-29= as Any}}
42-
// expected-warning@-4 {{expression implicitly coerced from 'Int?' to 'Any'}}
42+
// expected-warning@-4 {{coercion of implicitly unwrappable value of type 'Int?' to 'Any' does not unwrap optional}}
4343
// expected-note@-5 {{provide a default value to avoid this warning}}{{49-49= ?? <#default value#>}}
4444
// expected-note@-6 {{force-unwrap the value to avoid this warning}}{{49-49=!}}
4545
// expected-note@-7 {{explicitly cast to 'Any' with 'as Any' to silence this warning}}{{49-49= as Any}}
46-
_ = takeAny(C().a, C().b) // expected-warning {{expression implicitly coerced from 'Int?' to 'Any'}}
46+
_ = takeAny(C().a, C().b) // expected-warning {{coercion of implicitly unwrappable value of type 'Int?' to 'Any' does not unwrap optional}}
4747
// expected-note@-1 {{provide a default value to avoid this warning}}{{20-20= ?? <#default value#>}}
4848
// expected-note@-2 {{force-unwrap the value to avoid this warning}}{{20-20=!}}
4949
// expected-note@-3 {{explicitly cast to 'Any' with 'as Any' to silence this warning}}{{20-20= as Any}}
50-
// expected-warning@-4 {{expression implicitly coerced from 'Any??' to 'Any'}}
50+
// expected-warning@-4 {{coercion of implicitly unwrappable value of type 'Any??' to 'Any' does not unwrap optional}}
5151
// expected-note@-5 {{force-unwrap the value to avoid this warning}}{{27-27=!!}}
5252
// expected-note@-6 {{explicitly cast to 'Any' with 'as Any' to silence this warning}}{{27-27= as Any}}
53-
_ = takeAny(C()[0], C()[1.0]) // expected-warning {{expression implicitly coerced from 'Int?' to 'Any'}}
53+
_ = takeAny(C()[0], C()[1.0]) // expected-warning {{coercion of implicitly unwrappable value of type 'Int?' to 'Any' does not unwrap optional}}
5454
// expected-note@-1 {{provide a default value to avoid this warning}}{{21-21= ?? <#default value#>}}
5555
// expected-note@-2 {{force-unwrap the value to avoid this warning}}{{21-21=!}}
5656
// expected-note@-3 {{explicitly cast to 'Any' with 'as Any' to silence this warning}}{{21-21= as Any}}
57-
// expected-warning@-4 {{expression implicitly coerced from 'Any?' to 'Any'}}
57+
// expected-warning@-4 {{coercion of implicitly unwrappable value of type 'Any?' to 'Any' does not unwrap optional}}
5858
// expected-note@-5 {{provide a default value to avoid this warning}}{{31-31= ?? <#default value#>}}
5959
// expected-note@-6 {{force-unwrap the value to avoid this warning}}{{31-31=!}}
6060
// expected-note@-7 {{explicitly cast to 'Any' with 'as Any' to silence this warning}}{{31-31= as Any}}
61-
_ = takeAny(D(), D()) // expected-warning {{expression implicitly coerced from 'D?' to 'Any'}}
61+
_ = takeAny(D(), D()) // expected-warning {{coercion of implicitly unwrappable value of type 'D?' to 'Any' does not unwrap optional}}
6262
// expected-note@-1 {{provide a default value to avoid this warning}}{{18-18= ?? <#default value#>}}
6363
// expected-note@-2 {{force-unwrap the value to avoid this warning}}{{18-18=!}}
6464
// expected-note@-3 {{explicitly cast to 'Any' with 'as Any' to silence this warning}}{{18-18= as Any}}
65-
// expected-warning@-4 {{expression implicitly coerced from 'D?' to 'Any'}}
65+
// expected-warning@-4 {{coercion of implicitly unwrappable value of type 'D?' to 'Any' does not unwrap optional}}
6666
// expected-note@-5 {{provide a default value to avoid this warning}}{{23-23= ?? <#default value#>}}
6767
// expected-note@-6 {{force-unwrap the value to avoid this warning}}{{23-23=!}}
6868
// expected-note@-7 {{explicitly cast to 'Any' with 'as Any' to silence this warning}}{{23-23= as Any}}
6969

7070
_ = takeAny(a as Any, b as Any)
7171
}
7272

73-
func warnIUOToOptionalAnyCoercion(_ a: Int!, _ b: Any?!, _ c: Int??!, _ d: Any???!) {
74-
takesOptionalAny(a, b) // expected-warning {{expression implicitly coerced from 'Any??' to 'Any?'}}
73+
func warnIUOToOptionalAnyCoercion(_ a: Int!, _ b: Any?!, _ c: Int??!, _ d: Any???!) { // expected-note {{implicitly unwrapped parameter 'b' declared here}} // expected-note {{implicitly unwrapped parameter 'c' declared here}} // expected-note {{implicitly unwrapped parameter 'd' declared here}}
74+
takesOptionalAny(a, b) // expected-warning {{coercion of implicitly unwrappable value of type 'Any??' to 'Any?' does not unwrap optional}}
7575
// expected-note@-1 {{provide a default value to avoid this warning}}{{24-24= ?? <#default value#>}}
7676
// expected-note@-2 {{force-unwrap the value to avoid this warning}}{{24-24=!}}
7777
// expected-note@-3 {{explicitly cast to 'Any?' with 'as Any?' to silence this warning}}{{24-24= as Any?}}
@@ -80,10 +80,10 @@ func warnIUOToOptionalAnyCoercion(_ a: Int!, _ b: Any?!, _ c: Int??!, _ d: Any??
8080
takesOptionalAny(a, b!)
8181
takesOptionalAny(a, b as Any?)
8282

83-
takesOptionalAny(c, d) // expected-warning {{expression implicitly coerced from 'Int???' to 'Any?'}}
83+
takesOptionalAny(c, d) // expected-warning {{coercion of implicitly unwrappable value of type 'Int???' to 'Any?' does not unwrap optional}}
8484
// expected-note@-1 {{force-unwrap the value to avoid this warning}}{{21-21=!!}}
8585
// expected-note@-2 {{explicitly cast to 'Any?' with 'as Any?' to silence this warning}}{{21-21= as Any?}}
86-
// expected-warning@-3 {{expression implicitly coerced from 'Any????' to 'Any?'}}
86+
// expected-warning@-3 {{coercion of implicitly unwrappable value of type 'Any????' to 'Any?' does not unwrap optional}}
8787
// expected-note@-4 {{force-unwrap the value to avoid this warning}}{{24-24=!!!}}
8888
// expected-note@-5 {{explicitly cast to 'Any?' with 'as Any?' to silence this warning}}{{24-24= as Any?}}
8989

@@ -93,13 +93,21 @@ func warnIUOToOptionalAnyCoercion(_ a: Int!, _ b: Any?!, _ c: Int??!, _ d: Any??
9393

9494
func takesCollectionOfAny(_ a: [Any], _ d: [String : Any]) {}
9595

96-
func warnCollectionOfIUOToAnyCoercion(_ a: Int!) {
97-
takesCollectionOfAny([a], ["test" : a]) // expected-warning {{expression implicitly coerced from 'Int?' to 'Any'}}
96+
func warnCollectionOfIUOToAnyCoercion(_ a: Int!) { // expected-note 2{{implicitly unwrapped parameter 'a' declared here}}
97+
takesCollectionOfAny([a], ["test" : a]) // expected-warning {{coercion of implicitly unwrappable value of type 'Int?' to 'Any' does not unwrap optional}}
9898
// expected-note@-1 {{provide a default value to avoid this warning}}{{26-26= ?? <#default value#>}}
9999
// expected-note@-2 {{force-unwrap the value to avoid this warning}}{{26-26=!}}
100100
// expected-note@-3 {{explicitly cast to 'Any' with 'as Any' to silence this warning}}{{26-26= as Any}}
101-
// expected-warning@-4 {{expression implicitly coerced from 'Int?' to 'Any'}}
101+
// expected-warning@-4 {{coercion of implicitly unwrappable value of type 'Int?' to 'Any' does not unwrap optional}}
102102
// expected-note@-5 {{provide a default value to avoid this warning}}{{40-40= ?? <#default value#>}}
103103
// expected-note@-6 {{force-unwrap the value to avoid this warning}}{{40-40=!}}
104104
// expected-note@-7 {{explicitly cast to 'Any' with 'as Any' to silence this warning}}{{40-40= as Any}}
105105
}
106+
107+
func takesAny_sr10199(_ x: Any) {}
108+
109+
let fn_sr10199: (() -> Int?)! = { return nil }
110+
takesAny_sr10199(fn_sr10199()) // expected-warning {{expression implicitly coerced from 'Int?' to 'Any'}}
111+
// expected-note@-1 {{provide a default value to avoid this warning}}
112+
// expected-note@-2 {{force-unwrap the value to avoid this warning}}
113+
// expected-note@-3 {{explicitly cast to 'Any' with 'as Any' to silence this warning}}

0 commit comments

Comments
 (0)