Skip to content

Commit d3193f8

Browse files
authored
Merge pull request #26149 from theblixguy/fix/SR-11134
[Parser] Diagnose use of subscript inside an array literal
2 parents f931572 + 4b8cbb8 commit d3193f8

File tree

4 files changed

+60
-1
lines changed

4 files changed

+60
-1
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,13 @@ ERROR(extra_rbracket,PointsToFirstBadToken,
762762
"unexpected ']' in type; did you mean to write an array type?", ())
763763
ERROR(extra_colon,PointsToFirstBadToken,
764764
"unexpected ':' in type; did you mean to write a dictionary type?", ())
765+
WARNING(subscript_array_element, none,
766+
"unexpected subscript in array literal; did you mean to write two "
767+
"separate elements instead?", ())
768+
NOTE(subscript_array_element_fix_it_add_comma, none, "add a separator between "
769+
"the elements", ())
770+
NOTE(subscript_array_element_fix_it_remove_space, none,
771+
"remove the space between the elements to silence this warning", ())
765772

766773
// Tuple Types
767774
ERROR(expected_rparen_tuple_type_list,none,

include/swift/Parse/Parser.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1435,6 +1435,8 @@ class Parser {
14351435

14361436
UnresolvedDeclRefExpr *parseExprOperator();
14371437

1438+
void validateCollectionElement(ParserResult<Expr> element);
1439+
14381440
//===--------------------------------------------------------------------===//
14391441
// Statement Parsing
14401442

lib/Parse/ParseExpr.cpp

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3447,8 +3447,10 @@ Parser::parseExprCollectionElement(Optional<bool> &isDictionary) {
34473447
if (!isDictionary.hasValue())
34483448
isDictionary = Tok.is(tok::colon);
34493449

3450-
if (!*isDictionary)
3450+
if (!*isDictionary) {
3451+
validateCollectionElement(Element);
34513452
return Element;
3453+
}
34523454

34533455
if (Element.isNull())
34543456
return Element;
@@ -3471,6 +3473,43 @@ Parser::parseExprCollectionElement(Optional<bool> &isDictionary) {
34713473
TupleExpr::createImplicit(Context, {Element.get(), Value.get()}, {}));
34723474
}
34733475

3476+
/// validateCollectionElement - Check if a given collection element is valid.
3477+
///
3478+
/// At the moment, this checks whether a given collection element is a subscript
3479+
/// expression and whether we're subscripting into an array. If we are, then it
3480+
/// we emit a diagnostic in case it was not something that the user was
3481+
/// expecting.
3482+
///
3483+
/// For example: `let array [ [0, 1] [42] ]`
3484+
void Parser::validateCollectionElement(ParserResult<Expr> element) {
3485+
if (element.isNull())
3486+
return;
3487+
3488+
auto elementExpr = element.get();
3489+
if (!isa<SubscriptExpr>(elementExpr))
3490+
return;
3491+
3492+
auto subscriptExpr = cast<SubscriptExpr>(elementExpr);
3493+
if (!isa<ArrayExpr>(subscriptExpr->getBase()))
3494+
return;
3495+
3496+
auto arrayExpr = cast<ArrayExpr>(subscriptExpr->getBase());
3497+
3498+
auto startLocOfSubscript = subscriptExpr->getIndex()->getStartLoc();
3499+
auto endLocOfArray = arrayExpr->getEndLoc();
3500+
auto locForEndOfTokenArray = L->getLocForEndOfToken(SourceMgr, endLocOfArray);
3501+
3502+
if (locForEndOfTokenArray != startLocOfSubscript) {
3503+
auto subscriptLoc = subscriptExpr->getLoc();
3504+
diagnose(subscriptLoc, diag::subscript_array_element)
3505+
.highlight(subscriptExpr->getSourceRange());
3506+
diagnose(subscriptLoc, diag::subscript_array_element_fix_it_add_comma)
3507+
.fixItInsertAfter(endLocOfArray, ",");
3508+
diagnose(subscriptLoc, diag::subscript_array_element_fix_it_remove_space)
3509+
.fixItRemoveChars(locForEndOfTokenArray, startLocOfSubscript);
3510+
}
3511+
}
3512+
34743513
void Parser::addPatternVariablesToScope(ArrayRef<Pattern *> Patterns) {
34753514
for (Pattern *Pat : Patterns) {
34763515
Pat->forEachVariable([&](VarDecl *VD) {

test/type/array.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,14 @@ func passAssocType<T : HasAssocType>(_ t: T) {
114114
takesAssocType(t, [T.A](), [T.A?]())
115115
}
116116

117+
// SR-11134
118+
119+
let sr_11134_1 = [[1, 2, 3][0]] // ok
120+
let sr_11134_2 = [[1, 2, 3] [1]] // expected-warning {{unexpected subscript in array literal; did you mean to write two separate elements instead?}}
121+
// expected-note@-1 {{add a separator between the elements}}{{28-28=,}}
122+
// expected-note@-2 {{remove the space between the elements to silence this warning}}{{28-29=}}
123+
let sr_11134_3 = [
124+
[1, 2, 3] [1] // expected-warning {{unexpected subscript in array literal; did you mean to write two separate elements instead?}}
125+
// expected-note@-1 {{add a separator between the elements}}{{12-12=,}}
126+
// expected-note@-2 {{remove the space between the elements to silence this warning}}{{12-13=}}
127+
]

0 commit comments

Comments
 (0)