Skip to content

Commit c341be5

Browse files
committed
Sema: Look through implicit conversions when diagnosing collection literals with defaulted types
Resolves #60011 Tests: add verification for emitted fixit, a flag for no availability checking; add expected warnings
1 parent 23e5143 commit c341be5

File tree

3 files changed

+58
-13
lines changed

3 files changed

+58
-13
lines changed

lib/Sema/MiscDiagnostics.cpp

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -423,20 +423,33 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
423423
/// We have a collection literal with a defaulted type, e.g. of [Any]. Emit
424424
/// an error if it was inferred to this type in an invalid context, which is
425425
/// one in which the parent expression is not itself a collection literal.
426-
void checkTypeDefaultedCollectionExpr(CollectionExpr *c) {
426+
void checkTypeDefaultedCollectionExpr(CollectionExpr *c,
427+
bool diagnoseAsWarning) {
427428
// If the parent is a non-expression, or is not itself a literal, then
428429
// produce an error with a fixit to add the type as an explicit
429430
// annotation.
430-
if (c->getNumElements() == 0)
431-
Ctx.Diags.diagnose(c->getLoc(), diag::collection_literal_empty)
432-
.highlight(c->getSourceRange());
433-
else {
431+
auto &diags = Ctx.Diags;
432+
433+
if (c->getNumElements() == 0) {
434+
InFlightDiagnostic inFlight =
435+
diags.diagnose(c->getLoc(), diag::collection_literal_empty);
436+
inFlight.highlight(c->getSourceRange());
437+
438+
if (diagnoseAsWarning) {
439+
inFlight.limitBehavior(DiagnosticBehavior::Warning);
440+
}
441+
} else {
434442
assert(c->getType()->hasTypeRepr() &&
435443
"a defaulted type should always be printable");
436-
Ctx.Diags.diagnose(c->getLoc(), diag::collection_literal_heterogeneous,
437-
c->getType())
438-
.highlight(c->getSourceRange())
439-
.fixItInsertAfter(c->getEndLoc(), " as " + c->getType()->getString());
444+
InFlightDiagnostic inFlight = diags.diagnose(
445+
c->getLoc(), diag::collection_literal_heterogeneous, c->getType());
446+
inFlight.highlight(c->getSourceRange());
447+
inFlight.fixItInsertAfter(c->getEndLoc(),
448+
" as " + c->getType()->getString());
449+
450+
if (diagnoseAsWarning) {
451+
inFlight.limitBehavior(DiagnosticBehavior::Warning);
452+
}
440453
}
441454
}
442455

@@ -1313,11 +1326,26 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
13131326

13141327
// Diagnose uses of collection literals with defaulted types at the top
13151328
// level.
1316-
if (auto collection
1317-
= dyn_cast<CollectionExpr>(E->getSemanticsProvidingExpr())) {
1329+
E = E->getSemanticsProvidingExpr();
1330+
bool diagnoseAsWarning = false;
1331+
1332+
// Look through implicit conversions.
1333+
if (auto conversion = dyn_cast<ImplicitConversionExpr>(E)) {
1334+
// This case was not diagnosed previously; emit a warning instead of an
1335+
// error for source compatibility.
1336+
diagnoseAsWarning = true;
1337+
while (auto *expr =
1338+
dyn_cast<ImplicitConversionExpr>(conversion->getSubExpr())) {
1339+
conversion = expr;
1340+
}
1341+
1342+
E = conversion->getSubExpr();
1343+
}
1344+
1345+
if (auto collection = dyn_cast<CollectionExpr>(E)) {
13181346
if (collection->isTypeDefaulted()) {
13191347
Walker.checkTypeDefaultedCollectionExpr(
1320-
const_cast<CollectionExpr *>(collection));
1348+
const_cast<CollectionExpr *>(collection), diagnoseAsWarning);
13211349
}
13221350
}
13231351
}

test/Constraints/array_literal.swift

Lines changed: 8 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
@@ -155,6 +155,13 @@ func defaultToAny(i: Int, s: String) {
155155

156156
let a6 = [B(), C()]
157157
let _: Int = a6 // expected-error{{value of type '[A]'}}
158+
159+
let a7: some Collection = [1, "Swift"]
160+
// expected-warning@-1{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}} {{41-41= as [Any]}}
161+
let a8: (any Sequence)? = [1, "Swift"]
162+
// expected-warning@-1{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}
163+
let a9: any Sequence = [1, nil, "Swift"]
164+
// expected-warning@-1{{heterogeneous collection literal could only be inferred to '[Any?]'; add explicit type annotation if this is intentional}}
158165
}
159166

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

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

0 commit comments

Comments
 (0)