Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "Sema: Emit diagnostics when walking into collection literals with defaulted types" #65318

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
72 changes: 28 additions & 44 deletions lib/Sema/MiscDiagnostics.cpp
Expand Up @@ -112,15 +112,13 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
SmallPtrSet<DeclRefExpr*, 4> AlreadyDiagnosedBitCasts;

bool IsExprStmt;
bool HasReachedSemanticsProvidingExpr;

ASTContext &Ctx;
const DeclContext *DC;

public:
DiagnoseWalker(const DeclContext *DC, bool isExprStmt)
: IsExprStmt(isExprStmt), HasReachedSemanticsProvidingExpr(false),
Ctx(DC->getASTContext()), DC(DC) {}
: IsExprStmt(isExprStmt), Ctx(DC->getASTContext()), DC(DC) {}

MacroWalking getMacroWalkingBehavior() const override {
return MacroWalking::Expansion;
Expand All @@ -139,16 +137,6 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
bool shouldWalkIntoTapExpression() override { return false; }

PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
if (auto collection = dyn_cast<CollectionExpr>(E)) {
if (collection->isTypeDefaulted()) {
// Diagnose type defaulted collection literals in subexpressions as
// warnings to preserve source compatibility.
diagnoseTypeDefaultedCollectionExpr(
collection, Ctx,
/*downgradeToWarning=*/HasReachedSemanticsProvidingExpr);
}
}

// See through implicit conversions of the expression. We want to be able
// to associate the parent of this expression with the ultimate callee.
auto Base = E;
Expand Down Expand Up @@ -356,11 +344,6 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
checkBorrowExpr(borrowExpr);
}

if (!HasReachedSemanticsProvidingExpr &&
E == E->getSemanticsProvidingExpr()) {
HasReachedSemanticsProvidingExpr = true;
}

return Action::Continue(E);
}

Expand Down Expand Up @@ -508,34 +491,25 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
return false;
}

/// Diagnose a collection literal with a defaulted type such as \c [Any].
static void diagnoseTypeDefaultedCollectionExpr(CollectionExpr *c,
ASTContext &ctx,
bool downgradeToWarning) {
// Produce a diagnostic with a fixit to add the defaulted type as an
// explicit annotation.
auto &diags = ctx.Diags;

if (c->getNumElements() == 0) {
InFlightDiagnostic inFlight =
diags.diagnose(c->getLoc(), diag::collection_literal_empty);
inFlight.highlight(c->getSourceRange());

if (downgradeToWarning) {
inFlight.limitBehavior(DiagnosticBehavior::Warning);
}
} else {
/// We have a collection literal with a defaulted type, e.g. of [Any]. Emit
/// an error if it was inferred to this type in an invalid context, which is
/// one in which the parent expression is not itself a collection literal.
void checkTypeDefaultedCollectionExpr(CollectionExpr *c) {
// If the parent is a non-expression, or is not itself a literal, then
// produce an error with a fixit to add the type as an explicit
// annotation.
if (c->getNumElements() == 0)
Ctx.Diags.diagnose(c->getLoc(), diag::collection_literal_empty)
.highlight(c->getSourceRange());
else {
assert(c->getType()->hasTypeRepr() &&
"a defaulted type should always be printable");
InFlightDiagnostic inFlight = diags.diagnose(
c->getLoc(), diag::collection_literal_heterogeneous, c->getType());
inFlight.highlight(c->getSourceRange());
inFlight.fixItInsertAfter(c->getEndLoc(),
" as " + c->getType()->getString());

if (downgradeToWarning) {
inFlight.limitBehavior(DiagnosticBehavior::Warning);
}
Ctx.Diags
.diagnose(c->getLoc(), diag::collection_literal_heterogeneous,
c->getType())
.highlight(c->getSourceRange())
.fixItInsertAfter(c->getEndLoc(),
" as " + c->getType()->getString());
}
}

Expand Down Expand Up @@ -1421,6 +1395,16 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,

DiagnoseWalker Walker(DC, isExprStmt);
const_cast<Expr *>(E)->walk(Walker);

// Diagnose uses of collection literals with defaulted types at the top
// level.
if (auto collection =
dyn_cast<CollectionExpr>(E->getSemanticsProvidingExpr())) {
if (collection->isTypeDefaulted()) {
Walker.checkTypeDefaultedCollectionExpr(
const_cast<CollectionExpr *>(collection));
}
}
}


Expand Down
23 changes: 5 additions & 18 deletions test/Constraints/array_literal.swift
Expand Up @@ -126,6 +126,11 @@ func defaultToAny(i: Int, s: String) {
// expected-error@-1{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}
let _: Int = a1 // expected-error{{value of type '[Any]'}}

let _ = ([1, "a"])
// expected-error@-1{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}
let _ = [1, true, []]
// expected-error@-1:11 {{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}

let a2: Array = [1, "a", 3.5]
// expected-error@-1{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}
let _: Int = a2 // expected-error{{value of type '[Any]'}}
Expand All @@ -146,9 +151,7 @@ func defaultToAny(i: Int, s: String) {
let _: [Any] = [1, "a", 3.5]
let _: [Any] = [1, "a", [3.5, 3.7, 3.9]]
let _: [Any] = [1, "a", [3.5, "b", 3]]
// expected-warning@-1{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}
let _: [Any] = [1, [2, [3]]]
// expected-warning@-1{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}

func f1() -> [Any] {
[]
Expand All @@ -157,41 +160,25 @@ func defaultToAny(i: Int, s: String) {
let _: [Any?] = [1, "a", nil, 3.5]
let _: [Any?] = [1, "a", nil, [3.5, 3.7, 3.9]]
let _: [Any?] = [1, "a", nil, [3.5, "b", nil]]
// expected-warning@-1{{heterogeneous collection literal could only be inferred to '[Any?]'; add explicit type annotation if this is intentional}}
let _: [Any?] = [1, [2, [3]]]
// expected-warning@-1{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}
let _: [Any?] = [1, nil, [2, nil, [3]]]
// expected-warning@-1{{heterogeneous collection literal could only be inferred to '[Any?]'; add explicit type annotation if this is intentional}}

let a6 = [B(), C()]
let _: Int = a6 // expected-error{{value of type '[A]'}}

let a7: some Collection = [1, "Swift"]
// expected-warning@-1{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}} {{41-41= as [Any]}}
let _: (any Sequence)? = [1, "Swift"]
// expected-warning@-1{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}
let _: any Sequence = [1, nil, "Swift"]
// expected-warning@-1{{heterogeneous collection literal could only be inferred to '[Any?]'; add explicit type annotation if this is intentional}}
let _ = [1, true, ([], 1)]
// expected-error@-1 {{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}
// expected-warning@-2 {{empty collection literal requires an explicit type}}
let _ = true ? [] : []
// expected-warning@-1{{empty collection literal requires an explicit type}}
let _ = (true, ([1, "Swift"]))
//expected-warning@-1{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}
let _ = ([1, true])
//expected-error@-1{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}

func f2<T>(_: [T]) {}

func f3<T>() -> [T]? {}

f2([])
// expected-warning@-1{{empty collection literal requires an explicit type}}
f2([1, nil, ""])
// expected-warning@-1{{heterogeneous collection literal could only be inferred to '[Any?]'; add explicit type annotation if this is intentional}}
_ = f3() ?? []
// expected-warning@-1{{empty collection literal requires an explicit type}}
}

func noInferAny(iob: inout B, ioc: inout C) {
Expand Down
1 change: 0 additions & 1 deletion test/Constraints/casts.swift
Expand Up @@ -338,7 +338,6 @@ func test_compatibility_coercions(_ arr: [Int], _ optArr: [Int]?, _ dict: [Strin

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

// rdar://88334481 – Don't apply the compatibility logic for collection literals.
typealias Magic<T> = T
Expand Down
1 change: 0 additions & 1 deletion test/Constraints/casts_swift6.swift
Expand Up @@ -57,7 +57,6 @@ func test_compatibility_coercions(_ arr: [Int], _ optArr: [Int]?, _ dict: [Strin

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

// Cases from rdar://88334481
typealias Magic<T> = T
Expand Down
1 change: 0 additions & 1 deletion test/Constraints/construction.swift
Expand Up @@ -175,7 +175,6 @@ do {

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

func init_via_non_const_metatype(_ s1: S1.Type) {
_ = s1(i: 42) // expected-error {{initializing from a metatype value must reference 'init' explicitly}} {{9-9=.init}}
Expand Down
3 changes: 2 additions & 1 deletion test/Constraints/dictionary_literal.swift
Expand Up @@ -120,6 +120,8 @@ class B : A { }
class C : A { }

func testDefaultExistentials() {
let _ = ["a": ["b": ["c": ["d", 1, true]]]]

let _ = ["a" : 1, "b" : 2.5, "c" : "hello"]
// expected-error@-1{{heterogeneous collection literal could only be inferred to '[String : Any]'; add explicit type annotation if this is intentional}}{{46-46= as [String : Any]}}

Expand All @@ -139,7 +141,6 @@ func testDefaultExistentials() {
"b": ["a", 2, 3.14159],
"c": ["a": 2, "b": 3.5]]
// expected-error@-3{{heterogeneous collection literal could only be inferred to '[String : Any]'; add explicit type annotation if this is intentional}}
// expected-warning@-3{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}

let d3 = ["b" : B(), "c" : C()]
let _: Int = d3 // expected-error{{value of type '[String : A]'}}
Expand Down
1 change: 0 additions & 1 deletion test/Constraints/subscript.swift
Expand Up @@ -104,7 +104,6 @@ extension Int {
let _ = 1["1"] // expected-error {{ambiguous use of 'subscript(_:)'}}

let squares = [ 1, 2, 3 ].reduce([:]) { (dict, n) in
// expected-warning@-1 {{empty collection literal requires an explicit type}}
var dict = dict
dict[n] = n * n
return dict
Expand Down
10 changes: 0 additions & 10 deletions test/IDE/print_usrs_opaque_types.swift
Expand Up @@ -9,34 +9,29 @@
func testUnifyingGenericParams<T, U>(x: T) -> some Collection where T == U {
// expected-warning@-1 {{same-type requirement makes generic parameters 'U' and 'T' equivalent}}
return []
// expected-warning@-1 {{empty collection literal requires an explicit type}}
}

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

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

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

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

// CHECK: [[@LINE+1]]:{{[0-9]+}} s:14swift_ide_test14GenericContextVyQrxcqd__Rszluip
Expand All @@ -45,7 +40,6 @@ struct GenericContext<T> {
// CHECK: [[@LINE+1]]:{{[0-9]+}} s:14swift_ide_test14GenericContextVyQrxcqd__Rszluig
get {
return []
// expected-warning@-1 {{empty collection literal requires an explicit type}}
}
}
}
Expand All @@ -54,7 +48,6 @@ extension GenericContext where T == Int {
// CHECK: [[@LINE+1]]:{{[0-9]+}} s:14swift_ide_test14GenericContextVAASiRszlE0c12ConcretizingD5Param1xQrSi_tF
func testConcretizingGenericParam(x: T) -> some Collection {
return []
// expected-warning@-1 {{empty collection literal requires an explicit type}}
}
}

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

extension TooGenericTooContext where T: Collection, U == T.Element {
// CHECK: [[@LINE+1]]:{{[0-9]+}} s:14swift_ide_test010TooGenericD7ContextVAASlRz7ElementQzRs_rlE0c8UnifyingE7Params21xQrx_tF
func testUnifyingGenericParams2(x: T) -> some Collection {
return []
// expected-warning@-1 {{empty collection literal requires an explicit type}}
}
}
extension TooGenericTooContext where T == Int {
// CHECK: [[@LINE+1]]:{{[0-9]+}} s:14swift_ide_test010TooGenericD7ContextVAASiRszrlE0c12ConcretizingE5Param1xQrSi_tF
func testConcretizingGenericParam(x: T) -> some Collection {
return []
// expected-warning@-1 {{empty collection literal requires an explicit type}}
}
}

2 changes: 0 additions & 2 deletions test/Parse/matching_patterns.swift
Expand Up @@ -307,8 +307,6 @@ do {
while case let _ as [Derived] = arr {}
// expected-warning@-1 {{'let' pattern has no effect; sub-pattern didn't bind any variables}}

// FIXME: https://github.com/apple/swift/issues/61850
// expected-warning@+1 {{heterogeneous collection literal could only be inferred to '[[Base]]'; add explicit type annotation if this is intentional}}
for case _ as [Derived] in [arr] {}

if case is [Derived] = arr {}
Expand Down
2 changes: 0 additions & 2 deletions test/Parse/matching_patterns_reference_bindings.swift
Expand Up @@ -328,8 +328,6 @@ do {
while case let _ as [Derived] = arr {}
// expected-warning@-1 {{'let' pattern has no effect; sub-pattern didn't bind any variables}}

// FIXME: https://github.com/apple/swift/issues/61850
// expected-warning@+1 {{heterogeneous collection literal could only be inferred to '[[Base]]'; add explicit type annotation if this is intentional}}
for case _ as [Derived] in [arr] {}

if case is [Derived] = arr {}
Expand Down
4 changes: 0 additions & 4 deletions test/expr/cast/objc_coerce_array.swift
Expand Up @@ -7,13 +7,9 @@ var x = 1
_ = [x] as [NSNumber]

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

var y: Any = 1

Expand Down