[Parse] Remove Parser support for C-style for statement.

This commit is contained in:
Rintaro Ishizaki
2017-08-01 20:11:02 +09:00
parent 07957070cd
commit 546aeb2336
15 changed files with 205 additions and 465 deletions

View File

@@ -992,30 +992,16 @@ ERROR(docatch_not_trycatch,PointsToFirstBadToken,
"the 'do' keyword is used to specify a 'catch' region",
())
// C-Style For Stmt
ERROR(expected_init_for_stmt,PointsToFirstBadToken,
"expected initialization in a 'for' statement", ())
ERROR(missing_init_for_stmt,none,
"missing initialization in a 'for' statement", ())
ERROR(expected_semi_for_stmt,PointsToFirstBadToken,
"expected ';' in 'for' statement", ())
ERROR(expected_cond_for_stmt,none,
"expected condition in 'for' statement", ())
ERROR(expected_rparen_for_stmt,none,
"expected ')' in 'for' statement", ())
ERROR(expected_lbrace_after_for,none,
"expected '{' in 'for' statement", ())
ERROR(expected_var_decl_for_stmt,PointsToFirstBadToken,
"expected var declaration in a 'for' statement", ())
ERROR(c_style_for_stmt_removed,none,
"C-style for statement has been removed in Swift 3", ())
// For-each Stmt
ERROR(expected_foreach_in,none,
ERROR(expected_foreach_in,PointsToFirstBadToken,
"expected 'in' after for-each pattern", ())
ERROR(expected_foreach_container,none,
ERROR(expected_foreach_container,PointsToFirstBadToken,
"expected Sequence expression for for-each loop", ())
ERROR(expected_foreach_lbrace,none,
ERROR(expected_foreach_lbrace,PointsToFirstBadToken,
"expected '{' to start the body of for-each loop", ())
ERROR(expected_foreach_where_expr,PointsToFirstBadToken,
"expected expression in 'where' guard of 'for/in'", ())

View File

@@ -476,6 +476,7 @@ public:
void skipUntilDeclRBrace();
void skipUntilDeclStmtRBrace(tok T1);
void skipUntilDeclStmtRBrace(tok T1, tok T2);
void skipUntilDeclRBrace(tok T1, tok T2);
@@ -1279,11 +1280,7 @@ public:
ParserResult<Stmt> parseStmtRepeat(LabeledStmtInfo LabelInfo);
ParserResult<Stmt> parseStmtDo(LabeledStmtInfo LabelInfo);
ParserResult<CatchStmt> parseStmtCatch();
ParserResult<Stmt> parseStmtFor(LabeledStmtInfo LabelInfo);
ParserResult<Stmt> parseStmtForCStyle(SourceLoc ForLoc,
LabeledStmtInfo LabelInfo);
ParserResult<Stmt> parseStmtForEach(SourceLoc ForLoc,
LabeledStmtInfo LabelInfo);
ParserResult<Stmt> parseStmtForEach(LabeledStmtInfo LabelInfo);
ParserResult<Stmt> parseStmtSwitch(LabeledStmtInfo LabelInfo);
ParserStatus parseStmtCases(SmallVectorImpl<ASTNode> &cases, bool IsActive);
ParserResult<CaseStmt> parseStmtCase(bool IsActive);

View File

@@ -573,10 +573,14 @@ std::pair<bool, Stmt *> ModelASTWalker::walkToStmtPre(Stmt *S) {
SyntaxStructureNode SN;
SN.Kind = SyntaxStructureKind::ForEachStatement;
SN.Range = charSourceRangeFromSourceRange(SM, S->getSourceRange());
if (ForEachS->getPattern())
SN.Elements.emplace_back(SyntaxStructureElementKind::Id,
charSourceRangeFromSourceRange(SM,
ForEachS->getPattern()->getSourceRange()));
if (ForEachS->getPattern()) {
auto Pat = ForEachS->getPattern();
if (!Pat->isImplicit()) {
SourceRange ElemRange = Pat->getSourceRange();
SN.Elements.emplace_back(SyntaxStructureElementKind::Id,
charSourceRangeFromSourceRange(SM, ElemRange));
}
}
if (ForEachS->getSequence())
addExprElem(SyntaxStructureElementKind::Expr, ForEachS->getSequence(),SN);
pushStructureNode(SN, S);

View File

@@ -545,7 +545,7 @@ ParserResult<Stmt> Parser::parseStmt() {
return parseStmtDo(LabelInfo);
case tok::kw_for:
if (tryLoc.isValid()) diagnose(tryLoc, diag::try_on_stmt, Tok.getText());
return parseStmtFor(LabelInfo);
return parseStmtForEach(LabelInfo);
case tok::kw_switch:
if (tryLoc.isValid()) diagnose(tryLoc, diag::try_on_stmt, Tok.getText());
return parseStmtSwitch(LabelInfo);
@@ -1749,308 +1749,48 @@ ParserResult<CatchStmt> Parser::parseStmtCatch() {
return makeParserResult(status, result);
}
ParserResult<Stmt> Parser::parseStmtFor(LabeledStmtInfo LabelInfo) {
SourceLoc ForLoc = consumeToken(tok::kw_for);
static bool isStmtForCStyle(Parser &P) {
// If we have a leading identifier followed by a ':' or 'in', or have a
// 'case', then this is obviously a for-each loop. "for in ..." is malformed
// but it's obviously not a C-style for.
if ((P.Tok.isIdentifierOrUnderscore() &&
P.peekToken().isAny(tok::colon, tok::kw_in)) ||
P.Tok.isAny(tok::kw_case, tok::kw_in))
return false;
// The c-style-for loop and foreach-style-for loop are conflated together into
// a single keyword, so we have to do some lookahead to resolve what is going
// on.
// Otherwise, we have to look forward if we see ';' in control part.
Parser::BacktrackingScope Backtrack(P);
// If we have a leading identifier followed by a ':' or 'in', then this is
// obviously a for-each loop. For error recovery, also parse "for in ..." as
// foreach.
if ((Tok.isIdentifierOrUnderscore() &&
peekToken().isAny(tok::colon, tok::kw_in)) ||
Tok.is(tok::kw_in))
return parseStmtForEach(ForLoc, LabelInfo);
// The condition of a c-style-for loop can be parenthesized.
auto HasLParen = P.consumeIf(tok::l_paren);
// If we have "for ;" then this is clearly a c-style for loop.
if (Tok.is(tok::semi))
return parseStmtForCStyle(ForLoc, LabelInfo);
// Otherwise, we have to do lookahead. An unparenthesized valid C-style
// for-each loop will start with "let/var <irrefutable pattern> =". Check for
// that.
bool isCStyleFor = false;
{
Parser::BacktrackingScope Backtrack(*this);
// The condition of a foreach loop can be parenthesized.
consumeIf(tok::l_paren);
// Skip until we see eof, "in" (in which case we have a for-in loop),
// ";" in which case we have a simple expression as the first part of a
// c-style for loop, or "{" in which case we have a malformed statement.
while (Tok.isNot(tok::eof, tok::kw_in, tok::semi, tok::l_brace))
skipSingle();
isCStyleFor = Tok.isAny(tok::semi, tok::l_brace, tok::eof);
// Skip until we see ';', or something that ends control part.
while (P.Tok.isNot(tok::eof, tok::kw_in, tok::semi, tok::l_brace,
tok::r_brace, tok::r_paren) && !P.isStartOfStmt()) {
// If we saw newline before ';', consider it is a foreach statement.
if (!HasLParen && P.Tok.isAtStartOfLine())
return false;
P.skipSingle();
}
// Otherwise, this is some sort of c-style for loop.
if (isCStyleFor)
return parseStmtForCStyle(ForLoc, LabelInfo);
return parseStmtForEach(ForLoc, LabelInfo);
}
/// Given an expression, check to see if it is a set of braces "{...}" parsed as
/// a ClosureExpr that is probably a body of a statement. If so, convert it
/// into a BraceStmt that can be used as the body of a control flow statement
/// to improve error recovery.
///
/// If this expression isn't a ClosureExpr or isn't convertible, this returns
/// null.
///
static BraceStmt *ConvertClosureToBraceStmt(Expr *E, ASTContext &Ctx) {
if (!E) return nullptr;
auto *CE = dyn_cast<ClosureExpr>(E);
if (!CE) return nullptr;
// If this had a signature or anon-closure parameters (like $0) used, then it
// doesn't "look" like the body of a control flow statement, it looks like a
// closure.
if (CE->getInLoc().isValid() || CE->hasExplicitResultType() ||
CE->getParameters()->size() != 0)
return nullptr;
// Silence downstream errors by giving it type ()->(), to match up with the
// call we will produce.
CE->setImplicit();
auto empty = TupleTypeRepr::createEmpty(Ctx, CE->getStartLoc());
CE->setExplicitResultType(CE->getStartLoc(), empty);
// The trick here is that the ClosureExpr provides a DeclContext for stuff
// inside of it, so it isn't safe to just drop it and rip the BraceStmt
// from inside of it. While we could try to walk the body and update any
// Decls, ClosureExprs, etc within the body of the ClosureExpr, it is easier
// to just turn it into BraceStmt(CallExpr(TheClosure, VoidTuple)). This also
// more correctly handles the implicit ReturnStmt injected into single-expr
// closures.
ASTNode theCall = CallExpr::createImplicit(Ctx, CE, { }, { });
return BraceStmt::create(Ctx, CE->getStartLoc(), theCall, CE->getEndLoc(),
/*implicit*/true);
}
/// stmt-for-c-style:
/// (identifier ':')? 'for' stmt-for-c-style-init? ';' expr-basic? ';'
/// (expr-basic (',' expr-basic)*)? stmt-brace
/// (identifier ':')? 'for' '(' stmt-for-c-style-init? ';' expr-basic? ';'
/// (expr-basic (',' expr-basic)*)? ')' stmt-brace
/// stmt-for-c-style-init:
/// decl-var
/// expr (',' expr)*
ParserResult<Stmt> Parser::parseStmtForCStyle(SourceLoc ForLoc,
LabeledStmtInfo LabelInfo) {
SourceLoc Semi1Loc, Semi2Loc;
SourceLoc LPLoc, RPLoc;
bool LPLocConsumed = false;
ParserStatus Status;
ParserResult<Expr> First;
SmallVector<Decl*, 2> FirstDecls;
ParserResult<Expr> Second;
ParserResult<Expr> Third;
ParserResult<BraceStmt> Body;
// Introduce a new scope to contain any var decls in the init value.
Scope S(this, ScopeKind::ForVars);
if (Tok.is(tok::l_paren)) {
LPLoc = consumeToken();
LPLocConsumed = true;
}
// Parse the first part, either a var, let, expr, or stmt-assign.
if (Tok.is(tok::kw_var) || Tok.is(tok::kw_let) || Tok.is(tok::at_sign)) {
DeclAttributes Attributes;
bool FoundCCToken;
parseDeclAttributeList(Attributes, FoundCCToken);
// After parsing optional attributes above we should be at 'var' or 'let'
if (!Tok.is(tok::kw_var) && !Tok.is(tok::kw_let)) {
diagnose(Tok.getLoc(), diag::expected_var_decl_for_stmt);
return makeParserError();
}
ParserStatus VarDeclStatus = parseDeclVar(PD_InLoop, Attributes, FirstDecls,
SourceLoc(),
StaticSpellingKind::None,
SourceLoc());
if (VarDeclStatus.isError())
return VarDeclStatus; // FIXME: better recovery
} else if (Tok.isNot(tok::semi)) {
SmallVector<Expr *, 1> FirstExprs;
// Parse the first expression.
First = parseExpr(diag::expected_init_for_stmt);
Status |= First;
if (First.isNull() || First.hasCodeCompletion())
return makeParserResult<Stmt>(Status, nullptr); // FIXME: better recovery
FirstExprs.push_back(First.get());
// Parse additional expressions.
while (Tok.is(tok::comma)) {
consumeToken(tok::comma);
First = parseExpr(diag::expected_expr);
Status |= First;
if (First.isNull() || First.hasCodeCompletion())
return makeParserResult<Stmt>(Status, nullptr); // FIXME: better recovery
if (First.isNonNull())
FirstExprs.push_back(First.get());
}
// If we had more than one expression, form a tuple.
if (FirstExprs.size() > 1) {
First = makeParserResult(
TupleExpr::createImplicit(Context, FirstExprs, { }));
}
}
ArrayRef<Decl *> FirstDeclsContext;
if (!FirstDecls.empty())
FirstDeclsContext = Context.AllocateCopy(FirstDecls);
// If we're missing a semicolon, try to recover.
if (Tok.isNot(tok::semi)) {
// Provide a reasonable default location for the first semicolon.
Semi1Loc = PreviousLoc;
if (auto *BS = ConvertClosureToBraceStmt(First.getPtrOrNull(), Context)) {
// We have seen:
// for { ... }
// and there's no semicolon after that.
//
// We parsed the brace statement as a closure. Recover by using the
// brace statement as a 'for' body.
First = makeParserErrorResult(new (Context) ErrorExpr(BS->getStartLoc()));
Second = nullptr;
Third = nullptr;
Body = makeParserErrorResult(BS);
diagnose(ForLoc, diag::missing_init_for_stmt)
.highlight(SourceRange(ForLoc, BS->getStartLoc()));
Status.setIsParseError();
return makeParserResult(
Status, new (Context) ForStmt(LabelInfo, ForLoc, First.getPtrOrNull(),
FirstDeclsContext,
Semi1Loc, Second.getPtrOrNull(),
Semi2Loc, Third.getPtrOrNull(),
Body.get()));
}
}
// Consume the first semicolon.
if (parseToken(tok::semi, Semi1Loc, diag::expected_semi_for_stmt))
Status.setIsParseError();
if (Tok.isNot(tok::semi)) {
Second = parseExprBasic(diag::expected_cond_for_stmt);
Status |= Second;
}
if (Tok.isNot(tok::semi) && Second.isNonNull()) {
Expr *RecoveredCondition = nullptr;
BraceStmt *RecoveredBody = ConvertClosureToBraceStmt(Second.get(), Context);
if (auto *CE = dyn_cast<CallExpr>(Second.get())) {
if (auto *PE = dyn_cast<ParenExpr>(CE->getArg())) {
if (PE->hasTrailingClosure() && !RecoveredBody) {
// We have seen:
// for ... ; ... { ... }
// and there's no semicolon after that.
//
// We parsed the condition as a CallExpr with a brace statement as a
// trailing closure. Recover by using the original expression as the
// condition and brace statement as a 'for' body.
RecoveredBody = ConvertClosureToBraceStmt(PE->getSubExpr(), Context);
RecoveredCondition = CE->getFn();
}
}
}
if (RecoveredBody) {
SourceLoc LBraceLoc = RecoveredBody->getStartLoc();
Second = makeParserErrorResult(RecoveredCondition);
Third = nullptr;
Body = makeParserErrorResult(RecoveredBody);
diagnose(LBraceLoc, diag::expected_semi_for_stmt)
.highlight(SourceRange(ForLoc, LBraceLoc));
Status.setIsParseError();
return makeParserResult(
Status, new (Context) ForStmt(LabelInfo, ForLoc, First.getPtrOrNull(),
FirstDeclsContext,
Semi1Loc, Second.getPtrOrNull(),
Semi2Loc, Third.getPtrOrNull(),
Body.get()));
}
}
// Consume the second semicolon.
if (parseToken(tok::semi, Semi2Loc, diag::expected_semi_for_stmt))
Status.setIsParseError();
if (Tok.isNot(tok::l_brace, tok::r_paren)) {
SmallVector<Expr *, 1> ThirdExprs;
// Parse the first expression.
Third = parseExprBasic(diag::expected_expr);
Status |= Third;
if (Third.isNonNull())
ThirdExprs.push_back(Third.get());
// Parse additional expressions.
while (Tok.is(tok::comma)) {
consumeToken(tok::comma);
Third = parseExprBasic(diag::expected_expr);
Status |= Third;
if (Third.isNonNull())
ThirdExprs.push_back(Third.get());
}
// If we had more than one expression, form a tuple.
if (ThirdExprs.size() > 1) {
Third = makeParserResult(
TupleExpr::createImplicit(Context, ThirdExprs, { }));
}
}
if (LPLocConsumed && parseMatchingToken(tok::r_paren, RPLoc,
diag::expected_rparen_for_stmt,LPLoc))
Status.setIsParseError();
Body = parseBraceItemList(diag::expected_lbrace_after_for);
Status |= Body;
if (Body.isNull())
Body = makeParserResult(
Body, BraceStmt::create(Context, PreviousLoc, {}, PreviousLoc, true));
return makeParserResult(
Status,
new (Context) ForStmt(LabelInfo, ForLoc, First.getPtrOrNull(),
FirstDeclsContext,
Semi1Loc, Second.getPtrOrNull(), Semi2Loc,
Third.getPtrOrNull(), Body.get()));
return P.Tok.is(tok::semi);
}
///
/// stmt-for-each:
/// (identifier ':')? 'for' pattern 'in' expr-basic \
/// ('where' expr-basic)? stmt-brace
ParserResult<Stmt> Parser::parseStmtForEach(SourceLoc ForLoc,
LabeledStmtInfo LabelInfo) {
ParserResult<Stmt> Parser::parseStmtForEach(LabeledStmtInfo LabelInfo) {
SourceLoc ForLoc = consumeToken(tok::kw_for);
ParserStatus Status;
ParserResult<Pattern> pattern;
ParserResult<Expr> Container;
// The C-style for loop which was supported in Swift2 and foreach-style-for
// loop are conflated together into a single keyword, so we have to do some
// lookahead to resolve what is going on.
bool IsCStyleFor = isStmtForCStyle(*this);
auto StartOfControl = Tok.getLoc();
// Parse the pattern. This is either 'case <refutable pattern>' or just a
// normal pattern.
@@ -2059,7 +1799,7 @@ ParserResult<Stmt> Parser::parseStmtForEach(SourceLoc ForLoc,
T(InVarOrLetPattern, Parser::IVOLP_InMatchingPattern);
pattern = parseMatchingPattern(/*isExprBasic*/true);
pattern = parseOptionalPatternTypeAnnotation(pattern, /*isOptional*/false);
} else {
} else if (!IsCStyleFor || Tok.is(tok::kw_var)) {
// Change the parser state to know that the pattern we're about to parse is
// implicitly mutable. Bound variables can be changed to mutable explicitly
// if desired by using a 'var' pattern.
@@ -2071,18 +1811,38 @@ ParserResult<Stmt> Parser::parseStmtForEach(SourceLoc ForLoc,
InVarOrLetPattern = IVOLP_NotInVarOrLet;
}
if (pattern.isNull())
SourceLoc InLoc;
if (pattern.isNull()) {
// Recover by creating a "_" pattern.
pattern = makeParserErrorResult(new (Context) AnyPattern(SourceLoc()));
consumeIf(tok::kw_in, InLoc);
} else if (!IsCStyleFor) {
parseToken(tok::kw_in, InLoc, diag::expected_foreach_in);
}
// Bound variables all get their initial values from the generator.
pattern.get()->markHasNonPatternBindingInit();
SourceLoc InLoc;
parseToken(tok::kw_in, InLoc, diag::expected_foreach_in);
if (IsCStyleFor) {
// Skip until start of body part.
if (Tok.is(tok::l_paren)) {
skipSingle();
} else {
// If not parenthesized, don't run over the line.
while (Tok.isNot(tok::eof, tok::r_brace, tok::l_brace, tok::code_complete)
&& !Tok.isAtStartOfLine())
skipSingle();
}
if (Tok.is(tok::code_complete))
return makeParserCodeCompletionStatus();
ParserResult<Expr> Container;
if (Tok.is(tok::l_brace)) {
assert(StartOfControl != Tok.getLoc());
SourceRange ControlRange(StartOfControl, PreviousLoc);
Container = makeParserErrorResult(new (Context) ErrorExpr(ControlRange));
diagnose(ForLoc, diag::c_style_for_stmt_removed)
.highlight(ControlRange);
Status = makeParserError();
} else if (Tok.is(tok::l_brace)) {
SourceLoc LBraceLoc = Tok.getLoc();
diagnose(LBraceLoc, diag::expected_foreach_container);
Container = makeParserErrorResult(new (Context) ErrorExpr(LBraceLoc));
@@ -2099,6 +1859,10 @@ ParserResult<Stmt> Parser::parseStmtForEach(SourceLoc ForLoc,
Container = parseExprBasic(diag::expected_foreach_container);
if (Container.isNull())
Container = makeParserErrorResult(new (Context) ErrorExpr(Tok.getLoc()));
if (Container.isParseError())
// Recover.
skipUntilDeclStmtRBrace(tok::l_brace, tok::kw_where);
Status |= Container;
}
@@ -2120,7 +1884,6 @@ ParserResult<Stmt> Parser::parseStmtForEach(SourceLoc ForLoc,
Status |= Where;
}
// stmt-brace
ParserResult<BraceStmt> Body =
parseBraceItemList(diag::expected_foreach_lbrace);

View File

@@ -496,6 +496,14 @@ void Parser::skipUntilDeclStmtRBrace(tok T1) {
}
}
void Parser::skipUntilDeclStmtRBrace(tok T1, tok T2) {
while (Tok.isNot(T1, T2, tok::eof, tok::r_brace, tok::pound_endif,
tok::code_complete) &&
!isStartOfStmt() && !isStartOfDecl()) {
skipSingle();
}
}
void Parser::skipUntilDeclRBrace(tok T1, tok T2) {
while (Tok.isNot(T1, T2, tok::eof, tok::r_brace, tok::pound_endif) &&
!isStartOfDecl()) {

View File

@@ -344,7 +344,7 @@ func resyncParserB5() {}
for var i = 0; ; {
#^TOP_LEVEL_STMT_5^#
// TOP_LEVEL_STMT_5: Begin completions
// TOP_LEVEL_STMT_5: Decl[LocalVar]/Local: i[#Int#]{{; name=.+$}}
// TOP_LEVEL_STMT_5: Decl[LocalVar]/Local: i[#<<error type>>#]{{; name=.+$}}
// TOP_LEVEL_STMT_5: End completions
}

View File

@@ -18,7 +18,7 @@
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_DO_WHILE_1 | %FileCheck %s -check-prefix=COND-WITH-RELATION
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_DO_WHILE_2 | %FileCheck %s -check-prefix=COND-WITH-RELATION1
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_INIT_1 | %FileCheck %s -check-prefix=COND_COMMON
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_INIT_1 | %FileCheck %s -check-prefix=COND_NONE
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_INIT_2 | %FileCheck %s -check-prefix=COND_COMMON
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_INIT_3 | %FileCheck %s -check-prefix=COND_COMMON
@@ -26,54 +26,26 @@
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_COND_2 | %FileCheck %s -check-prefix=COND_COMMON
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_COND_3 | %FileCheck %s -check-prefix=COND_COMMON
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_COND_I_1 > %t.cond.txt
// RUN: %FileCheck %s -check-prefix=COND_COMMON < %t.cond.txt
// RUN: %FileCheck %s -check-prefix=WITH_I_INT_LOCAL < %t.cond.txt
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_COND_I_2 > %t.cond.txt
// RUN: %FileCheck %s -check-prefix=COND_COMMON < %t.cond.txt
// RUN: %FileCheck %s -check-prefix=WITH_I_ERROR_LOCAL < %t.cond.txt
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_COND_I_E_1 > %t.cond.txt
// RUN: %FileCheck %s -check-prefix=COND_COMMON < %t.cond.txt
// RUN: %FileCheck %s -check-prefix=WITH_I_E_LOCAL < %t.cond.txt
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_COND_I_1 | %FileCheck %s -check-prefix=COND_COMMON
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_COND_I_2 | %FileCheck %s -check-prefix=COND_COMMON
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_COND_I_E_1 | %FileCheck %s -check-prefix=COND_COMMON
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_INCR_1 | %FileCheck %s -check-prefix=COND_COMMON
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_INCR_2 | %FileCheck %s -check-prefix=COND_COMMON
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_INCR_I_1 | %FileCheck %s -check-prefix=COND_COMMON
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_INCR_I_2 | %FileCheck %s -check-prefix=COND_COMMON
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_INCR_I_3 | %FileCheck %s -check-prefix=COND_COMMON
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_INCR_I_4 | %FileCheck %s -check-prefix=COND_COMMON
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_INCR_I_E_1 | %FileCheck %s -check-prefix=COND_COMMON
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_INCR_I_1 > %t.incr.txt
// RUN: %FileCheck %s -check-prefix=COND_COMMON < %t.incr.txt
// RUN: %FileCheck %s -check-prefix=WITH_I_INT_LOCAL < %t.incr.txt
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_INCR_I_2 > %t.incr.txt
// RUN: %FileCheck %s -check-prefix=COND_COMMON < %t.incr.txt
// RUN: %FileCheck %s -check-prefix=WITH_I_INT_LOCAL < %t.incr.txt
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_INCR_I_3 > %t.incr.txt
// RUN: %FileCheck %s -check-prefix=COND_COMMON < %t.incr.txt
// RUN: %FileCheck %s -check-prefix=WITH_I_INT_LOCAL < %t.incr.txt
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_INCR_I_4 > %t.incr.txt
// RUN: %FileCheck %s -check-prefix=COND_COMMON < %t.incr.txt
// RUN: %FileCheck %s -check-prefix=WITH_I_ERROR_LOCAL < %t.incr.txt
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_INCR_I_E_1 > %t.incr.txt
// RUN: %FileCheck %s -check-prefix=COND_COMMON < %t.incr.txt
// RUN: %FileCheck %s -check-prefix=WITH_I_E_LOCAL < %t.incr.txt
// FIXME: should have 'i' in these results.
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_BODY_I_1 > %t.body.txt
// RUN: %FileCheck %s -check-prefix=COND_COMMON < %t.body.txt
// FIXME: %FileCheck %s -check-prefix=WITH_I_INT_LOCAL < %t.body.txt
// RUN: %FileCheck %s -check-prefix=WITH_I_ERROR_LOCAL < %t.body.txt
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_BODY_I_2 > %t.body.txt
// RUN: %FileCheck %s -check-prefix=COND_COMMON < %t.body.txt
// RUN: %FileCheck %s -check-prefix=WITH_I_INT_LOCAL < %t.body.txt
// RUN: %FileCheck %s -check-prefix=WITH_I_ERROR_LOCAL < %t.body.txt
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_BODY_I_3 > %t.body.txt
// RUN: %FileCheck %s -check-prefix=COND_COMMON < %t.body.txt
@@ -81,16 +53,15 @@
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_BODY_I_4 > %t.body.txt
// RUN: %FileCheck %s -check-prefix=COND_COMMON < %t.body.txt
// RUN: %FileCheck %s -check-prefix=WITH_I_INT_LOCAL < %t.body.txt
// RUN: %FileCheck %s -check-prefix=WITH_I_ERROR_LOCAL < %t.body.txt
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_BODY_I_5 > %t.body.txt
// RUN: %FileCheck %s -check-prefix=COND_COMMON < %t.body.txt
// RUN: %FileCheck %s -check-prefix=WITH_I_INT_LOCAL < %t.body.txt
// RUN: %FileCheck %s -check-prefix=WITH_I_ERROR_LOCAL < %t.body.txt
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=C_STYLE_FOR_BODY_I_6 > %t.body.txt
// RUN: %FileCheck %s -check-prefix=COND_COMMON < %t.body.txt
// RUN: %FileCheck %s -check-prefix=WITH_I_INT_LOCAL < %t.body.txt
// RUN: %FileCheck %s -check-prefix=WITH_I_ERROR_LOCAL < %t.body.txt
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=FOR_EACH_EXPR_1 | %FileCheck %s -check-prefix=COND_COMMON
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=FOR_EACH_EXPR_2 | %FileCheck %s -check-prefix=COND_COMMON
@@ -518,10 +489,6 @@ func testSwitchCaseWhereExprIJ1(_ fooObject: FooStruct) {
// WITH_J_INT: Decl[LocalVar]/Local: j[#Int#]{{; name=.+$}}
// WITH_I_E_LOCAL: Decl[LocalVar]/Local: i[#Int#]{{; name=.+$}}
// WITH_I_E_LOCAL: Decl[LocalVar]/Local: e[#Int#]{{; name=.+$}}
enum A { case aaa }
enum B { case bbb }
// UNRESOLVED_B-NOT: aaa

View File

@@ -66,9 +66,11 @@ func ffoo() {}
// CHECK: <foreach>for <elem-id>i</elem-id> in <elem-expr>0...5</elem-expr> <brace>{}</brace></foreach>
for i in 0...5 {}
// CHECK: <for>for <elem-initexpr>var i = 0, i2 = 1</elem-initexpr>; <elem-expr>i == 0</elem-expr>; <elem-expr>++i</elem-expr> <brace>{}</brace></for>
// CHECK: <foreach>for <elem-id>var (i, j)</elem-id> in <elem-expr>array</elem-expr> <brace>{}</brace></foreach>
for var (i, j) in array {}
// CHECK: <foreach>for <elem-id>var i</elem-id> = 0, i2 = 1; i == 0; ++i <brace>{}</brace></foreach>
for var i = 0, i2 = 1; i == 0; ++i {}
// CHECK: <for>for <elem-initexpr>var (i,i2) = (0,0), i3 = 1</elem-initexpr>; <elem-expr>i == 0</elem-expr>; <elem-expr>++i</elem-expr> <brace>{}</brace></for>
// CHECK: <foreach>for <elem-id>var (i,i2)</elem-id> = (0,0), i3 = 1; i == 0; ++i <brace>{}</brace></foreach>
for var (i,i2) = (0,0), i3 = 1; i == 0; ++i {}
for i = 0; i == 0; ++i {}
@@ -105,7 +107,7 @@ let myArray2 = [1]
// CHECK: <gvar>let <name>myDict2</name> = <dictionary>[<elem-expr>1</elem-expr>:<elem-expr>1</elem-expr>]</dictionary></gvar>
let myDict2 = [1:1]
// CHECK: <for>for <brace><brace>{}</brace></brace></for>
// CHECK: <foreach>for <brace>{}</brace></foreach>
for {}
// CHECK: <class>class <name><#MyCls#></name> : <inherited><elem-typeref><#OtherClass#></elem-typeref></inherited> {}

View File

@@ -319,8 +319,8 @@ class LazyProperties {
// CHECK-EXPANDED-NEXT: {{^}} `-BraceStmt {{.*}} [94:5 - 94:10] expanded
// CHECK-EXPANDED-NEXT: {{^}} `-CaseStmt {{.*}} [97:5 - 97:10] expanded
// CHECK-EXPANDED-NEXT: {{^}} `-BraceStmt {{.*}} [97:5 - 97:10] expanded
// CHECK-EXPANDED-NEXT: {{^}} `-ForStmt {{.*}} [99:3 - 99:38] expanded
// CHECK-EXPANDED-NEXT: {{^}} `-ForStmtInitializer {{.*}} [99:17 - 99:38] expanded
// CHECK-EXPANDED-NEXT: {{^}} `-ForEachStmt {{.*}} [99:3 - 99:38] expanded
// CHECK-EXPANDED-NEXT: {{^}} `-ForEachPattern {{.*}} [99:36 - 99:38] expanded
// CHECK-EXPANDED-NEXT: {{^}} `-BraceStmt {{.*}} [99:36 - 99:38] expanded
// CHECK-EXPANDED: TypeDecl {{.*}} StructContainsAbstractStorageDecls [114:1 - 130:1] expanded

View File

@@ -1,10 +1,8 @@
// RUN: %target-typecheck-verify-swift
func fuzz() { for var H
// expected-note@-1 {{to match this opening '{'}}
// expected-error@-2{{type annotation missing in pattern}}
// expected-error@-3 2 {{expected ';' in 'for' statement}}
// expected-error@+4{{expected '{' in 'for' statement}}
// expected-error@+3{{expected '}' at end of brace statement}}
// expected-error@+2{{expected condition in 'for' statement}}
// expected-error@+1{{expected expression}}
// expected-error@-1{{expected 'in' after for-each pattern}}
// expected-error@-2{{expected Sequence expression for for-each loop}}
// expected-error@-3{{expected '{' to start the body of for-each loop}}
// expected-note@-4 {{to match this opening '{'}}
// expected-error@+1{{expected '}' at end of brace statement}}

View File

@@ -8,7 +8,7 @@ struct IntRange<Int> : Sequence, IteratorProtocol {
func makeIterator() -> IntRange<Int> { return self }
}
func for_each(r: Range<Int>, iir: IntRange<Int>) { // expected-note 2 {{did you mean 'r'?}}
func for_each(r: Range<Int>, iir: IntRange<Int>) { // expected-note {{did you mean 'r'?}}
var sum = 0
// Simple foreach loop, using the variable in the body
@@ -30,7 +30,11 @@ func for_each(r: Range<Int>, iir: IntRange<Int>) { // expected-note 2 {{did you
}
// Parse errors
for i r { // expected-error 2{{expected ';' in 'for' statement}} expected-error {{use of unresolved identifier 'i'}} expected-error {{'Range<Int>' is not convertible to 'Bool'}}
}
// FIXME: Bad diagnostics; should be just 'expected 'in' after for-each patter'.
for i r { // expected-error {{found an unexpected second identifier in constant declaration}}
} // expected-note @-1 {{join the identifiers together}}
// expected-note @-2 {{join the identifiers together with camel-case}}
// expected-error @-3 {{expected 'in' after for-each pattern}}
// expected-error @-4 {{expected Sequence expression for for-each loop}}
for i in CountableRange(r) sum = sum + i; // expected-error{{expected '{' to start the body of for-each loop}}
}

View File

@@ -140,64 +140,81 @@ func missingWhileInRepeat() {
func acceptsClosure<T>(t: T) -> Bool { return true }
func missingControllingExprInFor() {
for // expected-error {{expected initialization in a 'for' statement}}
for { // expected-error {{missing initialization in a 'for' statement}}
for ; { // expected-error {{C-style for statement has been removed in Swift 3}}
}
for // expected-error {{missing initialization in a 'for' statement}}
for ; // expected-error {{C-style for statement has been removed in Swift 3}}
{
}
for var i { // expected-error 2{{expected ';' in 'for' statement}} expected-error {{type annotation missing in pattern}}
for ; true { // expected-error {{C-style for statement has been removed in Swift 3}}
}
for ; { // expected-error {{expected ';' in 'for' statement}}
for var i = 0; true { // expected-error {{C-style for statement has been removed in Swift 3}}
i += 1
}
// FIXME: it would be better if this diagnostic appeared on the previous line.
for ;
{ // expected-error {{expected ';' in 'for' statement}}
}
for ; true { // expected-error {{expected ';' in 'for' statement}}
}
for var i = 0; true { // expected-error {{expected ';' in 'for' statement}}
}
// The #if block is used to provide a scope for the for stmt to force it to end
// where necessary to provoke the crash.
#if true // <rdar://problem/21679557> compiler crashes on "for{{"
// expected-error @+2 {{missing initialization in a 'for' statement}}
// expected-note @+1 2 {{to match this opening '{'}}
for{{ // expected-error {{expression resolves to an unused function}}
#endif // expected-error 2 {{expected '}' at end of closure}}
#if true
// expected-error @+1 {{missing initialization in a 'for' statement}}
for{
var x = 42
}
#endif
}
func missingControllingExprInForEach() {
for in { // expected-error {{expected pattern}} expected-error {{expected Sequence expression for for-each loop}}
}
// expected-error @+3 {{expected pattern}}
// expected-error @+2 {{expected Sequence expression for for-each loop}}
// expected-error @+1 {{expected '{' to start the body of for-each loop}}
for
// expected-error @+4 {{expected 'in' after for-each pattern}}
// expected-error @+3 {{expected '{' to start the body of for-each loop}}
// expected-error @+2 {{expected pattern}}
// expected-error @+1 {{expected Sequence expression for for-each loop}}
for {
}
// expected-error @+2 {{expected pattern}}
// expected-error @+1 {{expected Sequence expression for for-each loop}}
for
{
}
// expected-error @+2 {{expected 'in' after for-each pattern}}
// expected-error @+1 {{expected Sequence expression for for-each loop}}
for i {
}
// expected-error @+2 {{expected 'in' after for-each pattern}}
// expected-error @+1 {{expected Sequence expression for for-each loop}}
for var i {
}
// expected-error @+2 {{expected pattern}}
// expected-error @+1 {{expected Sequence expression for for-each loop}}
for in {
}
// expected-error @+1 {{expected pattern}}
for 0..<12 {
}
// expected-error @+3 {{expected pattern}}
// expected-error @+2 {{expected Sequence expression for for-each loop}}
// expected-error @+1 {{expected '{' to start the body of for-each loop}}
for for in { // expected-error {{expected pattern}} expected-error {{expected Sequence expression for for-each loop}}
}
for i in { // expected-error {{expected Sequence expression for for-each loop}}
}
// The #if block is used to provide a scope for the for stmt to force it to end
// where necessary to provoke the crash.
#if true // <rdar://problem/21679557> compiler crashes on "for{{"
// expected-error @+2 {{expected pattern}}
// expected-error @+1 {{expected Sequence expression for for-each loop}}
for{{ // expected-note 2 {{to match this opening '{'}}
#endif // expected-error {{expected '}' at end of closure}} expected-error {{expected '}' at end of brace statement}}
#if true
// expected-error @+2 {{expected pattern}}
// expected-error @+1 {{expected Sequence expression for for-each loop}}
for{
var x = 42
}
#endif
}
func missingControllingExprInSwitch() {

View File

@@ -1,7 +1,7 @@
// RUN: %target-typecheck-verify-swift -parse-as-library
// RUN: %target-typecheck-verify-swift -parse-as-library -enable-astscope-lookup
let x = 42 // expected-note{{did you mean 'x'?}}
let x = 42
x + x; // expected-error {{expressions are not allowed at the top level}} expected-warning {{result of operator '+' is unused}}
x + x; // expected-error {{expressions are not allowed at the top level}} expected-warning {{result of operator '+' is unused}}
// Make sure we don't crash on closures at the top level
@@ -10,9 +10,7 @@ x + x; // expected-error {{expressions are not allowed at the top level}} expect
// expected-warning @-1 {{result of call is unused}}
// FIXME: Too many errors for this.
for i // expected-error 2 {{expected ';' in 'for' statement}}
// expected-error @-1{{use of unresolved identifier 'i'}}
// expected-error @+3{{expected '{' in 'for' statement}}
// expected-error @+2{{expected condition in 'for' statement}}
// expected-error @+1{{expected expression}}
// expected-error @+3 {{expected 'in' after for-each pattern}}
// expected-error @+2 {{expected Sequence expression for for-each loop}}
// expected-error @+1 {{expected '{' to start the body of for-each loop}}
for i

View File

@@ -624,26 +624,16 @@
]
},
{
key.kind: source.lang.swift.stmt.for,
key.kind: source.lang.swift.stmt.foreach,
key.offset: 1132,
key.length: 37,
key.nameoffset: 0,
key.namelength: 0,
key.elements: [
{
key.kind: source.lang.swift.structure.elem.init_expr,
key.kind: source.lang.swift.structure.elem.id,
key.offset: 1136,
key.length: 17
},
{
key.kind: source.lang.swift.structure.elem.expr,
key.offset: 1155,
key.length: 6
},
{
key.kind: source.lang.swift.structure.elem.expr,
key.offset: 1163,
key.length: 3
key.length: 5
}
],
key.substructure: [
@@ -984,6 +974,20 @@
key.severity: source.diagnostic.severity.error,
key.description: "getter/setter can only be defined for a single variable",
key.diagnostic_stage: source.diagnostic.stage.swift.parse
},
{
key.line: 77,
key.column: 1,
key.filepath: main.swift,
key.severity: source.diagnostic.severity.error,
key.description: "C-style for statement has been removed in Swift 3",
key.diagnostic_stage: source.diagnostic.stage.swift.parse,
key.ranges: [
{
key.offset: 1136,
key.length: 30
}
]
}
]
}

View File

@@ -1,33 +1,25 @@
// RUN: %target-typecheck-verify-swift -typecheck %s
for var i = 0; i < 10; i++ {}
// expected-error @-1 {{C-style for statement has been removed in Swift 3}} {{5-9=}} {{10-13= in }} {{14-20= ..< }} {{22-27=}}
// expected-error @-2 {{unary operator '++' cannot be applied}}
// expected-note @-3 {{overloads for '++' exist}}
// expected-error @-1 {{C-style for statement has been removed in Swift 3}} {{none}}
for var i = 0; i < 10; i += 1 {}
// expected-error @-1 {{C-style for statement has been removed in Swift 3}} {{5-9=}} {{10-13= in }} {{14-20= ..< }} {{22-30=}}
// expected-error @-1 {{C-style for statement has been removed in Swift 3}} {{none}}
for var i = 0; i <= 10; i++ {}
// expected-error @-1 {{C-style for statement has been removed in Swift 3}} {{5-9=}} {{10-13= in }} {{14-21= ... }} {{23-28=}}
// expected-error @-2 {{unary operator '++' cannot be applied}}
// expected-note @-3 {{overloads for '++' exist}}
// expected-error @-1 {{C-style for statement has been removed in Swift 3}} {{none}}
for var i = 0; i <= 10; i += 1 {}
// expected-error @-1 {{C-style for statement has been removed in Swift 3}} {{5-9=}} {{10-13= in }} {{14-21= ... }} {{23-31=}}
// expected-error @-1 {{C-style for statement has been removed in Swift 3}} {{none}}
for var i = 10; i > 0; i-- {}
// expected-error @-1 {{C-style for statement has been removed in Swift 3}} {{5-9=}} {{10-13= in }} {{13-13=((0 + 1)...}} {{15-15=).reversed()}} {{15-27=}}
// expected-error @-2 {{unary operator '--' cannot be applied}}
// expected-note @-3 {{overloads for '--' exist}}
// expected-error @-1 {{C-style for statement has been removed in Swift 3}} {{none}}
for var i = 10; i > 0; i -= 1 {}
// expected-error @-1 {{C-style for statement has been removed in Swift 3}} {{5-9=}} {{10-13= in }} {{13-13=((0 + 1)...}} {{15-15=).reversed()}} {{15-30=}}
// expected-error @-1 {{C-style for statement has been removed in Swift 3}} {{none}}
for var i = 10; i >= 0; i-- {}
// expected-error @-1 {{C-style for statement has been removed in Swift 3}} {{5-9=}} {{10-13= in }} {{13-13=(0...}} {{15-15=).reversed()}} {{15-28=}}
// expected-error @-2 {{unary operator '--' cannot be applied}}
// expected-note @-3 {{overloads for '--' exist}}
// expected-error @-1 {{C-style for statement has been removed in Swift 3}} {{none}}
for var i = 10; i >= 0; i -= 1 {}
// expected-error @-1 {{C-style for statement has been removed in Swift 3}} {{5-9=}} {{10-13= in }} {{13-13=(0...}} {{15-15=).reversed()}} {{15-31=}}
// expected-error @-1 {{C-style for statement has been removed in Swift 3}} {{none}}