Skip to content

Commit 0b0d807

Browse files
committed
[QoI] Check before trying to emit fix-it to convert from array to dictionary
Before trying to replace every other "," with ":" to help convert from array to dictionary, let's first check if it's appropriate e.g. the number of commas matches the number of elements and number of elements in the array is even which constitutes key/value pairs. Resolves: SR-4952.
1 parent 9520aff commit 0b0d807

File tree

2 files changed

+27
-6
lines changed

2 files changed

+27
-6
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7254,11 +7254,12 @@ bool FailureDiagnosis::visitArrayExpr(ArrayExpr *E) {
72547254
}
72557255
}
72567256
}
7257-
7257+
7258+
auto numElements = E->getNumElements();
72587259
if (!Conformance) {
72597260
// If the contextual type conforms to ExpressibleByDictionaryLiteral and
72607261
// this is an empty array, then they meant "[:]".
7261-
if (E->getNumElements() == 0 &&
7262+
if (numElements == 0 &&
72627263
isDictionaryLiteralCompatible(contextualType, CS, E->getLoc())) {
72637264
diagnose(E->getStartLoc(), diag::should_use_empty_dictionary_literal)
72647265
.fixItInsert(E->getEndLoc(), ":");
@@ -7271,13 +7272,19 @@ bool FailureDiagnosis::visitArrayExpr(ArrayExpr *E) {
72717272

72727273
// If the contextual type conforms to ExpressibleByDictionaryLiteral, then
72737274
// they wrote "x = [1,2]" but probably meant "x = [1:2]".
7274-
if ((E->getElements().size() & 1) == 0 && !E->getElements().empty() &&
7275+
if ((numElements & 1) == 0 && numElements > 0 &&
72757276
isDictionaryLiteralCompatible(contextualType, CS, E->getLoc())) {
72767277
auto diag = diagnose(E->getStartLoc(), diag::meant_dictionary_lit);
72777278

7278-
// Change every other comma into a colon.
7279-
for (unsigned i = 0, e = E->getElements().size()/2; i != e; ++i)
7280-
diag.fixItReplace(E->getCommaLocs()[i*2], ":");
7279+
// Change every other comma into a colon, only if the number
7280+
// of commas present matches the number of elements, because
7281+
// otherwise it might a structural problem with the expression
7282+
// e.g. ["a""b": 1].
7283+
const auto commaLocs = E->getCommaLocs();
7284+
if (commaLocs.size() == numElements - 1) {
7285+
for (unsigned i = 0, e = numElements / 2; i != e; ++i)
7286+
diag.fixItReplace(commaLocs[i*2], ":");
7287+
}
72817288
}
72827289

72837290
return true;

test/Constraints/dictionary_literal.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,17 @@ func testDefaultExistentials() {
9797
let _ = ["a" : "hello", 17 : "string"]
9898
// expected-error@-1{{heterogeneous collection literal could only be inferred to 'Dictionary<AnyHashable, String>'}}
9999
}
100+
101+
// SR-4952, rdar://problem/32330004 - Assertion failure during swift::ASTVisitor<::FailureDiagnosis,...>::visit
102+
func rdar32330004_1() -> [String: Any] {
103+
return ["a""one": 1, "two": 2, "three": 3] // expected-note {{did you mean to use a dictionary literal instead?}}
104+
// expected-error@-1 2 {{expected ',' separator}}
105+
// expected-error@-2 {{expected expression in container literal}}
106+
// expected-error@-3 {{contextual type '[String : Any]' cannot be used with array literal}}
107+
}
108+
109+
func rdar32330004_2() -> [String: Any] {
110+
return ["a", 0, "one", 1, "two", 2, "three", 3]
111+
// expected-error@-1 {{contextual type '[String : Any]' cannot be used with array literal}}
112+
// expected-note@-2 {{did you mean to use a dictionary literal instead?}} {{14-15=:}} {{24-25=:}} {{34-35=:}} {{46-47=:}}
113+
}

0 commit comments

Comments
 (0)