Skip to content

Commit 29b0b24

Browse files
authored
Merge pull request #24145 from theblixguy/fix/SR-10199-5.1
[5.1] [MiscDiagnostics] Update diagnostics for IUO to Any coercion
2 parents 31e5af9 + e2e2d50 commit 29b0b24

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
@@ -3032,6 +3032,15 @@ WARNING(optional_pattern_match_promotion,none,
30323032
(Type, Type))
30333033
WARNING(optional_to_any_coercion,none,
30343034
"expression implicitly coerced from %0 to %1", (Type, Type))
3035+
WARNING(iuo_to_any_coercion,none,
3036+
"coercion of implicitly unwrappable value of type %0 to %1 does not "
3037+
"unwrap optional", (Type, Type))
3038+
NOTE(iuo_to_any_coercion_note,none,
3039+
"implicitly unwrapped %0 %1 declared here",
3040+
(DescriptiveDeclKind, DeclName))
3041+
NOTE(iuo_to_any_coercion_note_func_result,none,
3042+
"%0 %1 with implicitly unwrapped result type is declared here",
3043+
(DescriptiveDeclKind, DeclName))
30353044
NOTE(default_optional_to_any,none,
30363045
"provide a default value to avoid this warning", ())
30373046
NOTE(force_optional_to_any,none,

lib/Sema/MiscDiagnostics.cpp

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

34423442
static bool hasImplicitlyUnwrappedResult(Expr *E) {
3443-
auto getDeclForExpr = [&](Expr *E) -> ValueDecl * {
3444-
if (auto *call = dyn_cast<CallExpr>(E))
3445-
E = call->getDirectCallee();
3443+
auto *decl = getDeclForImplicitlyUnwrappedExpr(E);
34463444

3447-
if (auto *subscript = dyn_cast<SubscriptExpr>(E)) {
3448-
if (subscript->hasDecl())
3449-
return subscript->getDecl().getDecl();
3450-
3451-
return nullptr;
3452-
}
3453-
3454-
if (auto *memberRef = dyn_cast<MemberRefExpr>(E))
3455-
return memberRef->getMember().getDecl();
3456-
if (auto *declRef = dyn_cast<DeclRefExpr>(E))
3457-
return declRef->getDecl();
3458-
if (auto *apply = dyn_cast<ApplyExpr>(E))
3459-
return apply->getCalledValue();
3445+
return decl
3446+
&& decl->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
3447+
}
34603448

3461-
return nullptr;
3462-
};
3449+
static ValueDecl *getDeclForImplicitlyUnwrappedExpr(Expr *E) {
3450+
E = E->getValueProvidingExpr();
34633451

34643452
// Look through implicit conversions like loads, derived-to-base
34653453
// conversion, etc.
3466-
if (auto *ICE = dyn_cast<ImplicitConversionExpr>(E))
3454+
if (auto *ICE = dyn_cast<ImplicitConversionExpr>(E)) {
34673455
E = ICE->getSubExpr();
3456+
}
34683457

3469-
auto *decl = getDeclForExpr(E);
3458+
if (auto *subscript = dyn_cast<SubscriptExpr>(E)) {
3459+
if (subscript->hasDecl())
3460+
return subscript->getDecl().getDecl();
3461+
return nullptr;
3462+
}
34703463

3471-
return decl
3472-
&& decl->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
3464+
if (auto *memberRef = dyn_cast<MemberRefExpr>(E))
3465+
return memberRef->getMember().getDecl();
3466+
3467+
if (auto *declRef = dyn_cast<DeclRefExpr>(E))
3468+
return declRef->getDecl();
3469+
3470+
if (auto *apply = dyn_cast<ApplyExpr>(E)) {
3471+
auto *decl = apply->getCalledValue();
3472+
if (decl && isa<AbstractFunctionDecl>(decl))
3473+
return decl;
3474+
}
3475+
return nullptr;
34733476
}
34743477

34753478
void visitErasureExpr(ErasureExpr *E, OptionalToAnyCoercion coercion) {
@@ -3500,15 +3503,32 @@ static void diagnoseUnintendedOptionalBehavior(TypeChecker &TC, const Expr *E,
35003503
size_t optionalityDifference = 0;
35013504
if (!isOptionalToAnyCoercion(srcType, destType, optionalityDifference))
35023505
return;
3503-
3504-
TC.diagnose(subExpr->getStartLoc(), diag::optional_to_any_coercion,
3505-
/* from */ srcType, /* to */ destType)
3506-
.highlight(subExpr->getSourceRange());
3507-
3506+
3507+
// If we're implicitly unwrapping from IUO to Any then emit a custom
3508+
// diagnostic
3509+
if (hasImplicitlyUnwrappedResult(subExpr)) {
3510+
if (auto decl = getDeclForImplicitlyUnwrappedExpr(subExpr)) {
3511+
TC.diagnose(subExpr->getStartLoc(), diag::iuo_to_any_coercion,
3512+
/* from */ srcType, /* to */ destType)
3513+
.highlight(subExpr->getSourceRange());
3514+
3515+
auto noteDiag = isa<FuncDecl>(decl)
3516+
? diag::iuo_to_any_coercion_note_func_result
3517+
: diag::iuo_to_any_coercion_note;
3518+
3519+
TC.diagnose(decl->getLoc(), noteDiag, decl->getDescriptiveKind(),
3520+
decl->getFullName());
3521+
}
3522+
} else {
3523+
TC.diagnose(subExpr->getStartLoc(), diag::optional_to_any_coercion,
3524+
/* from */ srcType, /* to */ destType)
3525+
.highlight(subExpr->getSourceRange());
3526+
}
3527+
35083528
if (optionalityDifference == 1) {
35093529
TC.diagnose(subExpr->getLoc(), diag::default_optional_to_any)
3510-
.highlight(subExpr->getSourceRange())
3511-
.fixItInsertAfter(subExpr->getEndLoc(), " ?? <#default value#>");
3530+
.highlight(subExpr->getSourceRange())
3531+
.fixItInsertAfter(subExpr->getEndLoc(), " ?? <#default value#>");
35123532
}
35133533

35143534
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)