Skip to content

Commit

Permalink
[parser] Better recovery on variable declaration with missing name be…
Browse files Browse the repository at this point in the history
…fore type parameter

Change-Id: Ie3e2995748c6f36c2cd98235658cbadfc53157a9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/394303
Commit-Queue: Jens Johansen <[email protected]>
Reviewed-by: Brian Wilkerson <[email protected]>
Reviewed-by: Johnni Winther <[email protected]>
  • Loading branch information
jensjoha authored and Commit Queue committed Nov 13, 2024
1 parent 2dda80a commit 0b07f2e
Show file tree
Hide file tree
Showing 21 changed files with 223 additions and 225 deletions.
10 changes: 10 additions & 0 deletions pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8355,6 +8355,16 @@ class Parser {
listener.beginMetadataStar(start.next!);
listener.endMetadataStar(/* count = */ 0);
}
// Having settled on a variable declaration possibly do some error recovery.
if (beforeType.next!.isA(TokenType.LT)) {
// E.g. `final <int> foo = [42];` where we're missing `List` before
// `<int>`.
insertSyntheticIdentifier(
beforeType, IdentifierContext.localVariableDeclaration,
message:
codes.templateExpectedIdentifier.withArguments(beforeType.next!));
typeInfo = computeType(beforeType, /* required = */ true);
}
token = typeInfo.parseType(beforeType, this);
next = token.next!;
listener.beginVariablesDeclaration(next, lateToken, varFinalOrConst);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

foo() {
if(true)
final <int> f = [42];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
Problems reported:

parser/error_recovery/bad_variable_in_if:7:11: Expected an identifier, but got '<'.
final <int> f = [42];
^

beginCompilationUnit(foo)
beginMetadataStar(foo)
endMetadataStar(0)
beginTopLevelMember(foo)
beginTopLevelMethod(, null, null)
handleNoType()
handleIdentifier(foo, topLevelFunctionDeclaration)
handleNoTypeVariables(()
beginFormalParameters((, MemberKind.TopLevelMethod)
endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
handleAsyncModifier(null, null)
beginBlockFunctionBody({)
beginIfStatement(if)
handleLiteralBool(true)
handleParenthesizedCondition((, null, null)
beginThenStatement(final)
beginMetadataStar(final)
endMetadataStar(0)
handleRecoverableError(Message[ExpectedIdentifier, Expected an identifier, but got '<'., Try inserting an identifier before '<'., {lexeme: <}], <, <)
handleIdentifier(, typeReference)
beginTypeArguments(<)
handleIdentifier(int, typeReference)
handleNoTypeArguments(>)
handleType(int, null)
endTypeArguments(1, <, >)
handleType(, null)
beginVariablesDeclaration(f, null, final)
handleIdentifier(f, localVariableDeclaration)
beginInitializedIdentifier(f)
beginVariableInitializer(=)
handleNoTypeArguments([)
handleLiteralInt(42)
handleLiteralList(1, [, null, ])
endVariableInitializer(=)
endInitializedIdentifier(f)
endVariablesDeclaration(1, ;)
endThenStatement(final, ;)
endIfStatement(if, null, ;)
endBlockFunctionBody(1, {, })
endTopLevelMethod(foo, null, })
endTopLevelDeclaration(})
endCompilationUnit(1, )
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
parseUnit(foo)
skipErrorTokens(foo)
listener: beginCompilationUnit(foo)
syntheticPreviousToken(foo)
parseTopLevelDeclarationImpl(, DirectiveContext(DirectiveState.Unknown))
parseMetadataStar()
listener: beginMetadataStar(foo)
listener: endMetadataStar(0)
parseTopLevelMemberImpl()
listener: beginTopLevelMember(foo)
isReservedKeyword(()
parseTopLevelMethod(, null, null, , NoType(), null, foo, false)
listener: beginTopLevelMethod(, null, null)
listener: handleNoType()
ensureIdentifierPotentiallyRecovered(, topLevelFunctionDeclaration, false)
listener: handleIdentifier(foo, topLevelFunctionDeclaration)
parseMethodTypeVar(foo)
listener: handleNoTypeVariables(()
parseGetterOrFormalParameters(foo, foo, false, MemberKind.TopLevelMethod)
parseFormalParameters(foo, MemberKind.TopLevelMethod)
parseFormalParametersRest((, MemberKind.TopLevelMethod)
listener: beginFormalParameters((, MemberKind.TopLevelMethod)
listener: endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
parseAsyncModifierOpt())
listener: handleAsyncModifier(null, null)
inPlainSync()
parseFunctionBody(), false, false)
listener: beginBlockFunctionBody({)
notEofOrValue(}, if)
parseStatement({)
parseStatementX({)
parseIfStatement({)
listener: beginIfStatement(if)
ensureParenthesizedCondition(if, allowCase: false)
parseExpressionInParenthesisRest((, allowCase: false)
parseExpression(()
parsePrecedenceExpression((, 1, true, ConstantPatternContext.none)
parseUnaryExpression((, true, ConstantPatternContext.none)
parsePrimary((, expression, ConstantPatternContext.none)
parseLiteralBool(()
listener: handleLiteralBool(true)
ensureCloseParen(true, ()
listener: handleParenthesizedCondition((, null, null)
listener: beginThenStatement(final)
parseStatement())
parseStatementX())
parseExpressionStatementOrDeclarationAfterModifiers(final, ), null, final, null, null)
looksLikeLocalFunction(<)
listener: beginMetadataStar(final)
listener: endMetadataStar(0)
insertSyntheticIdentifier(final, localVariableDeclaration, message: Message[ExpectedIdentifier, Expected an identifier, but got '<'., Try inserting an identifier before '<'., {lexeme: <}], messageOnToken: null)
reportRecoverableError(<, Message[ExpectedIdentifier, Expected an identifier, but got '<'., Try inserting an identifier before '<'., {lexeme: <}])
listener: handleRecoverableError(Message[ExpectedIdentifier, Expected an identifier, but got '<'., Try inserting an identifier before '<'., {lexeme: <}], <, <)
rewriter()
listener: handleIdentifier(, typeReference)
listener: beginTypeArguments(<)
listener: handleIdentifier(int, typeReference)
listener: handleNoTypeArguments(>)
listener: handleType(int, null)
listener: endTypeArguments(1, <, >)
listener: handleType(, null)
listener: beginVariablesDeclaration(f, null, final)
parseVariablesDeclarationRest(>, true)
parseOptionallyInitializedIdentifier(>)
ensureIdentifier(>, localVariableDeclaration)
listener: handleIdentifier(f, localVariableDeclaration)
listener: beginInitializedIdentifier(f)
parseVariableInitializerOpt(f)
listener: beginVariableInitializer(=)
parseExpression(=)
parsePrecedenceExpression(=, 1, true, ConstantPatternContext.none)
parseUnaryExpression(=, true, ConstantPatternContext.none)
parsePrimary(=, expression, ConstantPatternContext.none)
listener: handleNoTypeArguments([)
parseLiteralListSuffix(=, null)
parseExpression([)
parsePrecedenceExpression([, 1, true, ConstantPatternContext.none)
parseUnaryExpression([, true, ConstantPatternContext.none)
parsePrimary([, expression, ConstantPatternContext.none)
parseLiteralInt([)
listener: handleLiteralInt(42)
listener: handleLiteralList(1, [, null, ])
listener: endVariableInitializer(=)
listener: endInitializedIdentifier(f)
ensureSemicolon(])
listener: endVariablesDeclaration(1, ;)
listener: endThenStatement(final, ;)
listener: endIfStatement(if, null, ;)
notEofOrValue(}, })
listener: endBlockFunctionBody(1, {, })
listener: endTopLevelMethod(foo, null, })
listener: endTopLevelDeclaration(})
reportAllErrorTokens(foo)
listener: endCompilationUnit(1, )
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
NOTICE: Stream was rewritten by parser!

foo() {
if(true)
final *synthetic*<int> f = [42];
}


foo[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
if[KeywordToken]([BeginToken]true[KeywordToken])[SimpleToken]
final[KeywordToken] [SyntheticStringToken]<[BeginToken]int[StringToken]>[SimpleToken] f[StringToken] =[SimpleToken] [[BeginToken]42[StringToken]][SimpleToken];[SimpleToken]
}[SimpleToken]
[SimpleToken]
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
foo() {
if(true)
final <int> f = [42];
}


foo[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
if[KeywordToken]([BeginToken]true[KeywordToken])[SimpleToken]
final[KeywordToken] <[BeginToken]int[StringToken]>[SimpleToken] f[StringToken] =[SimpleToken] [[BeginToken]42[StringToken]][SimpleToken];[SimpleToken]
}[SimpleToken]
[SimpleToken]
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,10 @@ library;
// final <int> f = [42];
// ^
//
// pkg/front_end/testcases/regress/parser_recovery_01.dart:7:11: Error: Expected ';' after this.
// pkg/front_end/testcases/regress/parser_recovery_01.dart:7:11: Error: This couldn't be parsed.
// final <int> f = [42];
// ^
//
// pkg/front_end/testcases/regress/parser_recovery_01.dart:7:17: Error: Undefined name 'f'.
// final <int> f = [42];
// ^
//
// pkg/front_end/testcases/regress/parser_recovery_01.dart:7:19: Error: Can't assign to this.
// final <int> f = [42];
// ^
//
// pkg/front_end/testcases/regress/parser_recovery_01.dart:12:13: Error: Undefined name 'a'.
// var y = a<int, void>?.c = 42;
// ^
Expand Down Expand Up @@ -51,15 +43,11 @@ library;
// ^
//
import self as self;
import "dart:core" as core;

static method foo() → dynamic {
while (true) {
invalid-expression "pkg/front_end/testcases/regress/parser_recovery_01.dart:6:3: Error: This couldn't be parsed.
while(true)
^";
final invalid-type f = <core::int>[42];
}
invalid-expression "pkg/front_end/testcases/regress/parser_recovery_01.dart:7:19: Error: Can't assign to this.
final <int> f = [42];
^";
}
static method bar() → dynamic {}
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,10 @@ library;
// final <int> f = [42];
// ^
//
// pkg/front_end/testcases/regress/parser_recovery_01.dart:7:11: Error: Expected ';' after this.
// pkg/front_end/testcases/regress/parser_recovery_01.dart:7:11: Error: This couldn't be parsed.
// final <int> f = [42];
// ^
//
// pkg/front_end/testcases/regress/parser_recovery_01.dart:7:17: Error: Undefined name 'f'.
// final <int> f = [42];
// ^
//
// pkg/front_end/testcases/regress/parser_recovery_01.dart:7:19: Error: Can't assign to this.
// final <int> f = [42];
// ^
//
// pkg/front_end/testcases/regress/parser_recovery_01.dart:12:13: Error: Undefined name 'a'.
// var y = a<int, void>?.c = 42;
// ^
Expand Down Expand Up @@ -51,15 +43,11 @@ library;
// ^
//
import self as self;
import "dart:core" as core;

static method foo() → dynamic {
while (true) {
invalid-expression "pkg/front_end/testcases/regress/parser_recovery_01.dart:6:3: Error: This couldn't be parsed.
while(true)
^";
final invalid-type f = <core::int>[42];
}
invalid-expression "pkg/front_end/testcases/regress/parser_recovery_01.dart:7:19: Error: Can't assign to this.
final <int> f = [42];
^";
}
static method bar() → dynamic {}
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,10 @@ library;
// final <int> f = [42];
// ^
//
// pkg/front_end/testcases/regress/parser_recovery_01.dart:7:11: Error: Expected ';' after this.
// pkg/front_end/testcases/regress/parser_recovery_01.dart:7:11: Error: This couldn't be parsed.
// final <int> f = [42];
// ^
//
// pkg/front_end/testcases/regress/parser_recovery_01.dart:7:17: Error: Undefined name 'f'.
// final <int> f = [42];
// ^
//
// pkg/front_end/testcases/regress/parser_recovery_01.dart:7:19: Error: Can't assign to this.
// final <int> f = [42];
// ^
//
// pkg/front_end/testcases/regress/parser_recovery_01.dart:12:13: Error: Undefined name 'a'.
// var y = a<int, void>?.c = 42;
// ^
Expand Down Expand Up @@ -51,15 +43,11 @@ library;
// ^
//
import self as self;
import "dart:core" as core;

static method foo() → dynamic {
while (true) {
invalid-expression "pkg/front_end/testcases/regress/parser_recovery_01.dart:6:3: Error: This couldn't be parsed.
while(true)
^";
final invalid-type f = core::_GrowableList::_literal1<core::int>(42);
}
invalid-expression "pkg/front_end/testcases/regress/parser_recovery_01.dart:7:19: Error: Can't assign to this.
final <int> f = [42];
^";
}
static method bar() → dynamic {}
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,10 @@ library;
// final <int> f = [42];
// ^
//
// pkg/front_end/testcases/regress/parser_recovery_02.dart:7:11: Error: Expected ';' after this.
// pkg/front_end/testcases/regress/parser_recovery_02.dart:7:11: Error: This couldn't be parsed.
// final <int> f = [42];
// ^
//
// pkg/front_end/testcases/regress/parser_recovery_02.dart:7:17: Error: Undefined name 'f'.
// final <int> f = [42];
// ^
//
// pkg/front_end/testcases/regress/parser_recovery_02.dart:7:19: Error: Can't assign to this.
// final <int> f = [42];
// ^
//
// pkg/front_end/testcases/regress/parser_recovery_02.dart:12:13: Error: Undefined name 'a'.
// var y = a<int, void>?.c = 42;
// ^
Expand Down Expand Up @@ -51,15 +43,11 @@ library;
// ^
//
import self as self;
import "dart:core" as core;

static method foo() → dynamic {
if(true) {
invalid-expression "pkg/front_end/testcases/regress/parser_recovery_02.dart:6:3: Error: This couldn't be parsed.
if(true)
^";
final invalid-type f = <core::int>[42];
}
invalid-expression "pkg/front_end/testcases/regress/parser_recovery_02.dart:7:19: Error: Can't assign to this.
final <int> f = [42];
^";
}
static method bar() → dynamic {}
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,10 @@ library;
// final <int> f = [42];
// ^
//
// pkg/front_end/testcases/regress/parser_recovery_02.dart:7:11: Error: Expected ';' after this.
// pkg/front_end/testcases/regress/parser_recovery_02.dart:7:11: Error: This couldn't be parsed.
// final <int> f = [42];
// ^
//
// pkg/front_end/testcases/regress/parser_recovery_02.dart:7:17: Error: Undefined name 'f'.
// final <int> f = [42];
// ^
//
// pkg/front_end/testcases/regress/parser_recovery_02.dart:7:19: Error: Can't assign to this.
// final <int> f = [42];
// ^
//
// pkg/front_end/testcases/regress/parser_recovery_02.dart:12:13: Error: Undefined name 'a'.
// var y = a<int, void>?.c = 42;
// ^
Expand Down Expand Up @@ -51,15 +43,11 @@ library;
// ^
//
import self as self;
import "dart:core" as core;

static method foo() → dynamic {
if(true) {
invalid-expression "pkg/front_end/testcases/regress/parser_recovery_02.dart:6:3: Error: This couldn't be parsed.
if(true)
^";
final invalid-type f = <core::int>[42];
}
invalid-expression "pkg/front_end/testcases/regress/parser_recovery_02.dart:7:19: Error: Can't assign to this.
final <int> f = [42];
^";
}
static method bar() → dynamic {}
Loading

0 comments on commit 0b07f2e

Please sign in to comment.