Skip to content

Commit 8486eaf

Browse files
authored
Merge pull request #11502 from benlangmuir/cc-for-collection-syntax
[code-completion] Fix for-loop sequences containing collection syntax
2 parents 70a82f8 + 48d191f commit 8486eaf

File tree

5 files changed

+109
-29
lines changed

5 files changed

+109
-29
lines changed

include/swift/Parse/Parser.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,8 +1252,10 @@ class Parser {
12521252
ParserResult<Expr> parseExprCallSuffix(ParserResult<Expr> fn,
12531253
bool isExprBasic);
12541254
ParserResult<Expr> parseExprCollection(SourceLoc LSquareLoc = SourceLoc());
1255-
ParserResult<Expr> parseExprArray(SourceLoc LSquareLoc, Expr *FirstExpr);
1256-
ParserResult<Expr> parseExprDictionary(SourceLoc LSquareLoc, Expr *FirstKey);
1255+
ParserResult<Expr> parseExprArray(SourceLoc LSquareLoc,
1256+
ParserResult<Expr> FirstExpr);
1257+
ParserResult<Expr> parseExprDictionary(SourceLoc LSquareLoc,
1258+
ParserResult<Expr> FirstKey);
12571259

12581260
UnresolvedDeclRefExpr *parseExprOperator();
12591261

lib/Parse/ParseExpr.cpp

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3056,22 +3056,20 @@ ParserResult<Expr> Parser::parseExprCollection(SourceLoc LSquareLoc) {
30563056
// Parse the first expression.
30573057
ParserResult<Expr> FirstExpr
30583058
= parseExpr(diag::expected_expr_in_collection_literal);
3059-
if (FirstExpr.isNull() || FirstExpr.hasCodeCompletion()) {
3059+
if (FirstExpr.isNull()) {
30603060
skipUntil(tok::r_square);
30613061
if (Tok.is(tok::r_square))
30623062
consumeToken();
3063-
if (FirstExpr.hasCodeCompletion())
3064-
return makeParserCodeCompletionResult<Expr>();
3065-
return nullptr;
3063+
return FirstExpr;
30663064
}
30673065

30683066
// If we have a ':', this is a dictionary literal.
30693067
if (Tok.is(tok::colon)) {
3070-
return parseExprDictionary(LSquareLoc, FirstExpr.get());
3068+
return parseExprDictionary(LSquareLoc, FirstExpr);
30713069
}
30723070

30733071
// Otherwise, we have an array literal.
3074-
return parseExprArray(LSquareLoc, FirstExpr.get());
3072+
return parseExprArray(LSquareLoc, FirstExpr);
30753073
}
30763074

30773075
/// parseExprArray - Parse an array literal expression.
@@ -3083,13 +3081,13 @@ ParserResult<Expr> Parser::parseExprCollection(SourceLoc LSquareLoc) {
30833081
/// '[' expr (',' expr)* ','? ']'
30843082
/// '[' ']'
30853083
ParserResult<Expr> Parser::parseExprArray(SourceLoc LSquareLoc,
3086-
Expr *FirstExpr) {
3084+
ParserResult<Expr> FirstExpr) {
30873085
SmallVector<Expr *, 8> SubExprs;
30883086
SmallVector<SourceLoc, 8> CommaLocs;
3089-
SubExprs.push_back(FirstExpr);
3087+
SubExprs.push_back(FirstExpr.get());
30903088

30913089
SourceLoc CommaLoc, RSquareLoc;
3092-
ParserStatus Status;
3090+
ParserStatus Status(FirstExpr);
30933091

30943092
if (Tok.isNot(tok::r_square) && !consumeIf(tok::comma, CommaLoc)) {
30953093
diagnose(Tok, diag::expected_separator, ",")
@@ -3115,9 +3113,6 @@ ParserResult<Expr> Parser::parseExprArray(SourceLoc LSquareLoc,
31153113
return Element;
31163114
});
31173115

3118-
if (Status.hasCodeCompletion())
3119-
return makeParserCodeCompletionResult<Expr>();
3120-
31213116
assert(SubExprs.size() >= 1);
31223117
return makeParserResult(Status,
31233118
ArrayExpr::create(Context, LSquareLoc, SubExprs, CommaLocs,
@@ -3133,7 +3128,7 @@ ParserResult<Expr> Parser::parseExprArray(SourceLoc LSquareLoc,
31333128
/// '[' expr ':' expr (',' expr ':' expr)* ','? ']'
31343129
/// '[' ':' ']'
31353130
ParserResult<Expr> Parser::parseExprDictionary(SourceLoc LSquareLoc,
3136-
Expr *FirstKey) {
3131+
ParserResult<Expr> FirstKey) {
31373132
assert(Tok.is(tok::colon));
31383133

31393134
// Each subexpression is a (key, value) tuple.
@@ -3149,48 +3144,44 @@ ParserResult<Expr> Parser::parseExprDictionary(SourceLoc LSquareLoc,
31493144

31503145
bool FirstPair = true;
31513146

3152-
ParserStatus Status =
3147+
ParserStatus Status(FirstKey);
3148+
Status |=
31533149
parseList(tok::r_square, LSquareLoc, RSquareLoc,
31543150
/*AllowSepAfterLast=*/true,
31553151
diag::expected_rsquare_array_expr, [&]() -> ParserStatus {
31563152
// Parse the next key.
31573153
ParserResult<Expr> Key;
31583154
if (FirstPair) {
3159-
Key = makeParserResult(FirstKey);
3155+
Key = makeParserResult(FirstKey.get());
31603156
FirstPair = false;
31613157
} else {
31623158
Key = parseExpr(diag::expected_key_in_dictionary_literal);
3163-
if (Key.isNull() || Key.hasCodeCompletion())
3159+
if (Key.isNull())
31643160
return Key;
31653161
}
31663162

31673163
// Parse the ':'.
31683164
if (Tok.isNot(tok::colon)) {
31693165
diagnose(Tok, diag::expected_colon_in_dictionary_literal);
3170-
return makeParserError();
3166+
return ParserStatus(Key) | makeParserError();
31713167
}
31723168
consumeToken();
31733169

31743170
// Parse the next value.
31753171
ParserResult<Expr> Value =
31763172
parseExpr(diag::expected_value_in_dictionary_literal);
3177-
if (Value.hasCodeCompletion())
3178-
return Value;
31793173

31803174
if (Value.isNull())
31813175
Value = makeParserResult(Value, new (Context) ErrorExpr(PreviousLoc));
31823176

31833177
// Add this key/value pair.
31843178
addKeyValuePair(Key.get(), Value.get());
3185-
return Value;
3179+
return ParserStatus(Key) | ParserStatus(Value);
31863180
});
31873181

3188-
if (Status.hasCodeCompletion())
3189-
return makeParserCodeCompletionResult<Expr>();
3190-
31913182
assert(SubExprs.size() >= 1);
3192-
return makeParserResult(DictionaryExpr::create(Context, LSquareLoc, SubExprs,
3193-
RSquareLoc));
3183+
return makeParserResult(Status, DictionaryExpr::create(Context, LSquareLoc,
3184+
SubExprs, RSquareLoc));
31943185
}
31953186

31963187
void Parser::addPatternVariablesToScope(ArrayRef<Pattern *> Patterns) {

lib/Parse/ParseStmt.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1857,13 +1857,16 @@ ParserResult<Stmt> Parser::parseStmtForEach(LabeledStmtInfo LabelInfo) {
18571857
consumeToken(tok::code_complete);
18581858
} else {
18591859
Container = parseExprBasic(diag::expected_foreach_container);
1860+
llvm::errs() << "container:\n";
1861+
if (!Container.isNull()) {
1862+
Container.get()->dump();
1863+
}
1864+
Status |= Container;
18601865
if (Container.isNull())
18611866
Container = makeParserErrorResult(new (Context) ErrorExpr(Tok.getLoc()));
18621867
if (Container.isParseError())
18631868
// Recover.
18641869
skipUntilDeclStmtRBrace(tok::l_brace, tok::kw_where);
1865-
1866-
Status |= Container;
18671870
}
18681871

18691872
// Introduce a new scope and place the variables in the pattern into that

test/IDE/complete_at_top_level.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,31 @@
123123
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=STRING_INTERP_3 | %FileCheck %s -check-prefix=STRING_INTERP
124124
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=STRING_INTERP_4 | %FileCheck %s -check-prefix=STRING_INTERP
125125

126+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=FOR_COLLECTION_1 > %t.for_collection1
127+
// RUN: %FileCheck %s -check-prefix=PLAIN_TOP_LEVEL < %t.for_collection1
128+
// RUN: %FileCheck %s -check-prefix=FOR_COLLECTION < %t.for_collection1
129+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=FOR_COLLECTION_2 > %t.for_collection2
130+
// RUN: %FileCheck %s -check-prefix=PLAIN_TOP_LEVEL < %t.for_collection2
131+
// RUN: %FileCheck %s -check-prefix=FOR_COLLECTION < %t.for_collection2
132+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=FOR_COLLECTION_3 > %t.for_collection3
133+
// RUN: %FileCheck %s -check-prefix=PLAIN_TOP_LEVEL < %t.for_collection3
134+
// RUN: %FileCheck %s -check-prefix=FOR_COLLECTION < %t.for_collection3
135+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=FOR_COLLECTION_4 > %t.for_collection4
136+
// RUN: %FileCheck %s -check-prefix=PLAIN_TOP_LEVEL < %t.for_collection4
137+
// RUN: %FileCheck %s -check-prefix=FOR_COLLECTION < %t.for_collection4
138+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=FOR_COLLECTION_5 > %t.for_collection5
139+
// RUN: %FileCheck %s -check-prefix=PLAIN_TOP_LEVEL < %t.for_collection5
140+
// RUN: %FileCheck %s -check-prefix=FOR_COLLECTION < %t.for_collection5
141+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=FOR_COLLECTION_6 > %t.for_collection6
142+
// RUN: %FileCheck %s -check-prefix=PLAIN_TOP_LEVEL < %t.for_collection6
143+
// RUN: %FileCheck %s -check-prefix=FOR_COLLECTION < %t.for_collection6
144+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=FOR_COLLECTION_7 > %t.for_collection7
145+
// RUN: %FileCheck %s -check-prefix=PLAIN_TOP_LEVEL < %t.for_collection7
146+
// RUN: %FileCheck %s -check-prefix=FOR_COLLECTION < %t.for_collection7
147+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=FOR_COLLECTION_8 > %t.for_collection8
148+
// RUN: %FileCheck %s -check-prefix=PLAIN_TOP_LEVEL < %t.for_collection8
149+
// RUN: %FileCheck %s -check-prefix=FOR_COLLECTION < %t.for_collection8
150+
126151
// Test code completion in top-level code.
127152
//
128153
// This test is not meant to test that we can correctly form all kinds of
@@ -437,6 +462,16 @@ _ = "" + "\(#^STRING_INTERP_4^#)" + ""
437462
// STRING_INTERP: End completions
438463
func resyncParserC1() {}
439464

465+
// FOR_COLLECTION-NOT: forIndex
466+
for forIndex in [#^FOR_COLLECTION_1^#] {}
467+
for forIndex in [1,#^FOR_COLLECTION_2^#] {}
468+
for forIndex in [1:#^FOR_COLLECTION_3^#] {}
469+
for forIndex in [#^FOR_COLLECTION_4^#:] {}
470+
for forIndex in [#^FOR_COLLECTION_5^#:2] {}
471+
for forIndex in [1:2, #^FOR_COLLECTION_6^#] {}
472+
for forIndex in [1:2, #^FOR_COLLECTION_7^#:] {}
473+
for forIndex in [1:2, #^FOR_COLLECTION_8^#:2] {}
474+
440475

441476
//
442477
//===--- DON'T ADD ANY TESTS AFTER THIS LINE.

test/IDE/complete_expr_postfix_begin.swift

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@
6161
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IN_FOR_EACH_2 | %FileCheck %s -check-prefix=IN_FOR_EACH_1
6262
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IN_FOR_EACH_3 | %FileCheck %s -check-prefix=IN_FOR_EACH_3
6363
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IN_FOR_EACH_4 | %FileCheck %s -check-prefix=IN_FOR_EACH_3
64+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IN_FOR_EACH_5 | %FileCheck %s -check-prefix=IN_FOR_EACH_1
65+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IN_FOR_EACH_6 | %FileCheck %s -check-prefix=IN_FOR_EACH_1
66+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IN_FOR_EACH_7 | %FileCheck %s -check-prefix=IN_FOR_EACH_1
67+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IN_FOR_EACH_8 | %FileCheck %s -check-prefix=IN_FOR_EACH_1
68+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IN_FOR_EACH_9 | %FileCheck %s -check-prefix=IN_FOR_EACH_1
69+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IN_FOR_EACH_10 | %FileCheck %s -check-prefix=IN_FOR_EACH_1
70+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IN_FOR_EACH_11 | %FileCheck %s -check-prefix=IN_FOR_EACH_1
71+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IN_FOR_EACH_12 | %FileCheck %s -check-prefix=IN_FOR_EACH_1
6472

6573
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=DEPRECATED_1 | %FileCheck %s -check-prefix=DEPRECATED_1
6674

@@ -458,6 +466,47 @@ func testInForEach4(arg: Int) {
458466
let after = 4
459467
}
460468

469+
func testInForEach5(arg: Int) {
470+
let local = 2
471+
for index in [#^IN_FOR_EACH_5^#] {}
472+
let after = 4
473+
}
474+
func testInForEach6(arg: Int) {
475+
let local = 2
476+
for index in [1,#^IN_FOR_EACH_6^#] {}
477+
let after = 4
478+
}
479+
func testInForEach7(arg: Int) {
480+
let local = 2
481+
for index in [1:#^IN_FOR_EACH_7^#] {}
482+
let after = 4
483+
}
484+
func testInForEach8(arg: Int) {
485+
let local = 2
486+
for index in [#^IN_FOR_EACH_8^#:] {}
487+
let after = 4
488+
}
489+
func testInForEach9(arg: Int) {
490+
let local = 2
491+
for index in [#^IN_FOR_EACH_9^#:2] {}
492+
let after = 4
493+
}
494+
func testInForEach10(arg: Int) {
495+
let local = 2
496+
for index in [1:2, #^IN_FOR_EACH_10^#] {}
497+
let after = 4
498+
}
499+
func testInForEach11(arg: Int) {
500+
let local = 2
501+
for index in [1:2, #^IN_FOR_EACH_11^#:] {}
502+
let after = 4
503+
}
504+
func testInForEach12(arg: Int) {
505+
let local = 2
506+
for index in [1:2, #^IN_FOR_EACH_12^#:2] {}
507+
let after = 4
508+
}
509+
461510
@available(*, deprecated)
462511
struct Deprecated {
463512
@available(*, deprecated)

0 commit comments

Comments
 (0)