Skip to content

Commit f608802

Browse files
committed
Sema: Emit diagnostics when walking into collection literals with defaulted types
Resolves #60011 Gardening: clean up `checkTypeDefaultedCollectionExpr` function
1 parent eb7a23f commit f608802

File tree

9 files changed

+104
-29
lines changed

9 files changed

+104
-29
lines changed

lib/Sema/MiscDiagnostics.cpp

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,15 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
109109
SmallPtrSet<DeclRefExpr*, 4> AlreadyDiagnosedBitCasts;
110110

111111
bool IsExprStmt;
112+
bool HasReachedSemanticsProvidingExpr;
112113

113-
public:
114114
ASTContext &Ctx;
115115
const DeclContext *DC;
116116

117+
public:
117118
DiagnoseWalker(const DeclContext *DC, bool isExprStmt)
118-
: IsExprStmt(isExprStmt), Ctx(DC->getASTContext()), DC(DC) {}
119+
: IsExprStmt(isExprStmt), HasReachedSemanticsProvidingExpr(false),
120+
Ctx(DC->getASTContext()), DC(DC) {}
119121

120122
std::pair<bool, Pattern*> walkToPatternPre(Pattern *P) override {
121123
return { false, P };
@@ -128,6 +130,17 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
128130
bool shouldWalkIntoTapExpression() override { return false; }
129131

130132
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
133+
134+
if (auto collection = dyn_cast<CollectionExpr>(E)) {
135+
if (collection->isTypeDefaulted()) {
136+
// Diagnose type defaulted collection literals in subexpressions as
137+
// warnings to preserve source compatibility.
138+
diagnoseTypeDefaultedCollectionExpr(
139+
collection, Ctx,
140+
/*downgradeToWarning=*/HasReachedSemanticsProvidingExpr);
141+
}
142+
}
143+
131144
// See through implicit conversions of the expression. We want to be able
132145
// to associate the parent of this expression with the ultimate callee.
133146
auto Base = E;
@@ -328,6 +341,11 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
328341
checkMoveExpr(moveExpr);
329342
}
330343

344+
if (!HasReachedSemanticsProvidingExpr &&
345+
E == E->getSemanticsProvidingExpr()) {
346+
HasReachedSemanticsProvidingExpr = true;
347+
}
348+
331349
return { true, E };
332350
}
333351

@@ -444,23 +462,34 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
444462
return false;
445463
}
446464

447-
/// We have a collection literal with a defaulted type, e.g. of [Any]. Emit
448-
/// an error if it was inferred to this type in an invalid context, which is
449-
/// one in which the parent expression is not itself a collection literal.
450-
void checkTypeDefaultedCollectionExpr(CollectionExpr *c) {
451-
// If the parent is a non-expression, or is not itself a literal, then
452-
// produce an error with a fixit to add the type as an explicit
453-
// annotation.
454-
if (c->getNumElements() == 0)
455-
Ctx.Diags.diagnose(c->getLoc(), diag::collection_literal_empty)
456-
.highlight(c->getSourceRange());
457-
else {
465+
/// Diagnose a collection literal with a defaulted type such as \c [Any].
466+
static void diagnoseTypeDefaultedCollectionExpr(CollectionExpr *c,
467+
ASTContext &ctx,
468+
bool downgradeToWarning) {
469+
// Produce a diagnostic with a fixit to add the defaulted type as an
470+
// explicit annotation.
471+
auto &diags = ctx.Diags;
472+
473+
if (c->getNumElements() == 0) {
474+
InFlightDiagnostic inFlight =
475+
diags.diagnose(c->getLoc(), diag::collection_literal_empty);
476+
inFlight.highlight(c->getSourceRange());
477+
478+
if (downgradeToWarning) {
479+
inFlight.limitBehavior(DiagnosticBehavior::Warning);
480+
}
481+
} else {
458482
assert(c->getType()->hasTypeRepr() &&
459483
"a defaulted type should always be printable");
460-
Ctx.Diags.diagnose(c->getLoc(), diag::collection_literal_heterogeneous,
461-
c->getType())
462-
.highlight(c->getSourceRange())
463-
.fixItInsertAfter(c->getEndLoc(), " as " + c->getType()->getString());
484+
InFlightDiagnostic inFlight = diags.diagnose(
485+
c->getLoc(), diag::collection_literal_heterogeneous, c->getType());
486+
inFlight.highlight(c->getSourceRange());
487+
inFlight.fixItInsertAfter(c->getEndLoc(),
488+
" as " + c->getType()->getString());
489+
490+
if (downgradeToWarning) {
491+
inFlight.limitBehavior(DiagnosticBehavior::Warning);
492+
}
464493
}
465494
}
466495

@@ -1334,16 +1363,6 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
13341363

13351364
DiagnoseWalker Walker(DC, isExprStmt);
13361365
const_cast<Expr *>(E)->walk(Walker);
1337-
1338-
// Diagnose uses of collection literals with defaulted types at the top
1339-
// level.
1340-
if (auto collection
1341-
= dyn_cast<CollectionExpr>(E->getSemanticsProvidingExpr())) {
1342-
if (collection->isTypeDefaulted()) {
1343-
Walker.checkTypeDefaultedCollectionExpr(
1344-
const_cast<CollectionExpr *>(collection));
1345-
}
1346-
}
13471366
}
13481367

13491368

test/Constraints/array_literal.swift

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift
1+
// RUN: %target-typecheck-verify-swift -disable-availability-checking
22

33
struct IntList : ExpressibleByArrayLiteral {
44
typealias Element = Int
@@ -142,19 +142,56 @@ func defaultToAny(i: Int, s: String) {
142142
// expected-error@-1{{empty collection literal requires an explicit type}}
143143
let _: Int = a5 // expected-error{{value of type '[Any]'}}
144144

145+
let _: [Any] = []
145146
let _: [Any] = [1, "a", 3.5]
146147
let _: [Any] = [1, "a", [3.5, 3.7, 3.9]]
147148
let _: [Any] = [1, "a", [3.5, "b", 3]]
149+
// expected-warning@-1{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}
148150
let _: [Any] = [1, [2, [3]]]
151+
// expected-warning@-1{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}
152+
153+
func f1() -> [Any] {
154+
[]
155+
}
149156

150157
let _: [Any?] = [1, "a", nil, 3.5]
151158
let _: [Any?] = [1, "a", nil, [3.5, 3.7, 3.9]]
152159
let _: [Any?] = [1, "a", nil, [3.5, "b", nil]]
160+
// expected-warning@-1{{heterogeneous collection literal could only be inferred to '[Any?]'; add explicit type annotation if this is intentional}}
153161
let _: [Any?] = [1, [2, [3]]]
162+
// expected-warning@-1{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}
154163
let _: [Any?] = [1, nil, [2, nil, [3]]]
164+
// expected-warning@-1{{heterogeneous collection literal could only be inferred to '[Any?]'; add explicit type annotation if this is intentional}}
155165

156166
let a6 = [B(), C()]
157167
let _: Int = a6 // expected-error{{value of type '[A]'}}
168+
169+
let a7: some Collection = [1, "Swift"]
170+
// expected-warning@-1{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}} {{41-41= as [Any]}}
171+
let _: (any Sequence)? = [1, "Swift"]
172+
// expected-warning@-1{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}
173+
let _: any Sequence = [1, nil, "Swift"]
174+
// expected-warning@-1{{heterogeneous collection literal could only be inferred to '[Any?]'; add explicit type annotation if this is intentional}}
175+
let _ = [1, true, ([], 1)]
176+
// expected-error@-1 {{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}
177+
// expected-warning@-2 {{empty collection literal requires an explicit type}}
178+
let _ = true ? [] : []
179+
// expected-warning@-1{{empty collection literal requires an explicit type}}
180+
let _ = (true, ([1, "Swift"]))
181+
//expected-warning@-1{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}
182+
let _ = ([1, true])
183+
//expected-error@-1{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}
184+
185+
func f2<T>(_: [T]) {}
186+
187+
func f3<T>() -> [T]? {}
188+
189+
f2([])
190+
// expected-warning@-1{{empty collection literal requires an explicit type}}
191+
f2([1, nil, ""])
192+
// expected-warning@-1{{heterogeneous collection literal could only be inferred to '[Any?]'; add explicit type annotation if this is intentional}}
193+
_ = f3() ?? []
194+
// expected-warning@-1{{empty collection literal requires an explicit type}}
158195
}
159196

160197
func noInferAny(iob: inout B, ioc: inout C) {

test/Constraints/casts.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ func test_compatibility_coercions(_ arr: [Int], _ optArr: [Int]?, _ dict: [Strin
337337

338338
// The array can also be inferred to be [Any].
339339
_ = ([] ?? []) as Array // expected-warning {{left side of nil coalescing operator '??' has non-optional type '[Any]', so the right side is never used}}
340+
// expected-warning@-1{{empty collection literal requires an explicit type}}
340341

341342
// rdar://88334481 – Don't apply the compatibility logic for collection literals.
342343
typealias Magic<T> = T

test/Constraints/casts_swift6.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ func test_compatibility_coercions(_ arr: [Int], _ optArr: [Int]?, _ dict: [Strin
5757

5858
// The array can also be inferred to be [Any].
5959
_ = ([] ?? []) as Array // expected-warning {{left side of nil coalescing operator '??' has non-optional type '[Any]', so the right side is never used}}
60+
// expected-warning@-1 {{empty collection literal requires an explicit type}}
6061

6162
// Cases from rdar://88334481
6263
typealias Magic<T> = T

test/Constraints/construction.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ SR_5245(s: SR_5245.S(f: [.e1, .e2]))
172172

173173
// rdar://problem/34670592 - Compiler crash on heterogeneous collection literal
174174
_ = Array([1, "hello"]) // Ok
175+
// expected-warning@-1 {{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}
175176

176177
func init_via_non_const_metatype(_ s1: S1.Type) {
177178
_ = s1(i: 42) // expected-error {{initializing from a metatype value must reference 'init' explicitly}} {{9-9=.init}}

test/Constraints/dictionary_literal.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ func testDefaultExistentials() {
139139
"b": ["a", 2, 3.14159],
140140
"c": ["a": 2, "b": 3.5]]
141141
// expected-error@-3{{heterogeneous collection literal could only be inferred to '[String : Any]'; add explicit type annotation if this is intentional}}
142+
// expected-warning@-3{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}
142143

143144
let d3 = ["b" : B(), "c" : C()]
144145
let _: Int = d3 // expected-error{{value of type '[String : A]'}}
@@ -193,4 +194,4 @@ f59215(["", ""]) //expected-error{{dictionary of type '[String : String]' cannot
193194
f59215(["", "", "", ""]) //expected-error{{dictionary of type '[String : String]' cannot be used with array literal}}
194195
// expected-note@-1{{did you mean to use a dictionary literal instead?}} {{11-12=:}} {{19-20=:}}
195196
f59215(["", "", "", ""]) //expected-error{{dictionary of type '[String : String]' cannot be used with array literal}}
196-
// expected-note@-1{{did you mean to use a dictionary literal instead?}} {{11-12=:}} {{19-20=:}}
197+
// expected-note@-1{{did you mean to use a dictionary literal instead?}} {{11-12=:}} {{19-20=:}}

test/Constraints/subscript.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ extension Int {
104104
let _ = 1["1"] // expected-error {{ambiguous use of 'subscript(_:)'}}
105105

106106
let squares = [ 1, 2, 3 ].reduce([:]) { (dict, n) in
107+
// expected-warning@-1 {{empty collection literal requires an explicit type}}
107108
var dict = dict
108109
dict[n] = n * n
109110
return dict

test/IDE/print_usrs_opaque_types.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,34 @@
99
func testUnifyingGenericParams<T, U>(x: T) -> some Collection where T == U {
1010
// expected-warning@-1 {{same-type requirement makes generic parameters 'U' and 'T' equivalent}}
1111
return []
12+
// expected-warning@-1 {{empty collection literal requires an explicit type}}
1213
}
1314

1415
// CHECK: [[@LINE+1]]:{{[0-9]+}} s:14swift_ide_test0C22UnifyingGenericParams21xQrx_tSlRz7ElementQzRs_r0_lF
1516
func testUnifyingGenericParams2<T, U>(x: T) -> some Collection where T: Collection, U == T.Element {
1617
return []
18+
// expected-warning@-1 {{empty collection literal requires an explicit type}}
1719
}
1820

1921
// CHECK: [[@LINE+1]]:{{[0-9]+}} s:14swift_ide_test0C24ConcretizingGenericParam1xQrSi_tSiRszlF
2022
func testConcretizingGenericParam<T>(x: T) -> some Collection where T == Int {
2123
// expected-warning@-1 {{same-type requirement makes generic parameter 'T' non-generic}}
2224
return []
25+
// expected-warning@-1 {{empty collection literal requires an explicit type}}
2326
}
2427

2528
struct GenericContext<T> {
2629
// CHECK: [[@LINE+1]]:{{[0-9]+}} s:14swift_ide_test14GenericContextV0c8UnifyingD6Params1xQrx_tqd__RszlF
2730
func testUnifyingGenericParams<U>(x: T) -> some Collection where T == U {
2831
// expected-warning@-1 {{same-type requirement makes generic parameters 'U' and 'T' equivalent}}
2932
return []
33+
// expected-warning@-1 {{empty collection literal requires an explicit type}}
3034
}
3135

3236
// CHECK: [[@LINE+1]]:{{[0-9]+}} s:14swift_ide_test14GenericContextV0c8UnifyingD7Params21xQrx_tSlRz7ElementQzRsd__lF
3337
func testUnifyingGenericParams2<U>(x: T) -> some Collection where T: Collection, U == T.Element {
3438
return []
39+
// expected-warning@-1 {{empty collection literal requires an explicit type}}
3540
}
3641

3742
// CHECK: [[@LINE+1]]:{{[0-9]+}} s:14swift_ide_test14GenericContextVyQrxcqd__Rszluip
@@ -40,6 +45,7 @@ struct GenericContext<T> {
4045
// CHECK: [[@LINE+1]]:{{[0-9]+}} s:14swift_ide_test14GenericContextVyQrxcqd__Rszluig
4146
get {
4247
return []
48+
// expected-warning@-1 {{empty collection literal requires an explicit type}}
4349
}
4450
}
4551
}
@@ -48,6 +54,7 @@ extension GenericContext where T == Int {
4854
// CHECK: [[@LINE+1]]:{{[0-9]+}} s:14swift_ide_test14GenericContextVAASiRszlE0c12ConcretizingD5Param1xQrSi_tF
4955
func testConcretizingGenericParam(x: T) -> some Collection {
5056
return []
57+
// expected-warning@-1 {{empty collection literal requires an explicit type}}
5158
}
5259
}
5360

@@ -58,19 +65,22 @@ extension TooGenericTooContext where T == U {
5865
// CHECK: [[@LINE+1]]:{{[0-9]+}} s:14swift_ide_test010TooGenericD7ContextVAAq_RszrlE0c8UnifyingE6Params1xQrx_tF
5966
func testUnifyingGenericParams(x: T) -> some Collection {
6067
return []
68+
// expected-warning@-1 {{empty collection literal requires an explicit type}}
6169
}
6270
}
6371

6472
extension TooGenericTooContext where T: Collection, U == T.Element {
6573
// CHECK: [[@LINE+1]]:{{[0-9]+}} s:14swift_ide_test010TooGenericD7ContextVAASlRz7ElementQzRs_rlE0c8UnifyingE7Params21xQrx_tF
6674
func testUnifyingGenericParams2(x: T) -> some Collection {
6775
return []
76+
// expected-warning@-1 {{empty collection literal requires an explicit type}}
6877
}
6978
}
7079
extension TooGenericTooContext where T == Int {
7180
// CHECK: [[@LINE+1]]:{{[0-9]+}} s:14swift_ide_test010TooGenericD7ContextVAASiRszrlE0c12ConcretizingE5Param1xQrSi_tF
7281
func testConcretizingGenericParam(x: T) -> some Collection {
7382
return []
83+
// expected-warning@-1 {{empty collection literal requires an explicit type}}
7484
}
7585
}
7686

test/expr/cast/objc_coerce_array.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@ var x = 1
77
_ = [x] as [NSNumber]
88

99
_ = ["x":["y":"z","a":1]] as [String : [String : AnyObject]]
10+
// expected-warning@-1{{heterogeneous collection literal could only be inferred to '[String : AnyObject]'; add explicit type annotation if this is intentiona}}
1011
_ = ["x":["z",1]] as [String : [AnyObject]]
12+
// expected-warning@-1{{heterogeneous collection literal could only be inferred to '[AnyObject]'; add explicit type annotation if this is intentional}}
1113
_ = [["y":"z","a":1]] as [[String : AnyObject]]
14+
// expected-warning@-1{{heterogeneous collection literal could only be inferred to '[String : AnyObject]'; add explicit type annotation if this is intentional}}
1215
_ = [["z",1]] as [[AnyObject]]
16+
// expected-warning@-1{{heterogeneous collection literal could only be inferred to '[AnyObject]'; add explicit type annotation if this is intentional}}
1317

1418
var y: Any = 1
1519

0 commit comments

Comments
 (0)