mirror of
https://github.com/dart-lang/sdk
synced 2024-10-04 19:18:27 +00:00
update parser to handle "!." in nnbd expressions
Fix https://github.com/dart-lang/sdk/issues/37111 Change-Id: I6e156a804085c9be12e5e7a0d0019cfeb77c9128 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/104187 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Dan Rubel <danrubel@google.com>
This commit is contained in:
parent
dc7fa3bae7
commit
2938630937
|
@ -2207,19 +2207,24 @@ class FormalParameterParserTest_Fasta extends FastaParserTestCase
|
|||
*/
|
||||
@reflectiveTest
|
||||
class NNBDParserTest_Fasta extends FastaParserTestCase {
|
||||
@override
|
||||
CompilationUnit parseCompilationUnit(String content,
|
||||
{List<ErrorCode> codes,
|
||||
List<ExpectedError> errors,
|
||||
FeatureSet featureSet}) =>
|
||||
super.parseCompilationUnit(content,
|
||||
codes: codes, errors: errors, featureSet: featureSet ?? nonNullable);
|
||||
|
||||
void test_assignment_complex() {
|
||||
parseCompilationUnit('D? foo(X? x) { X? x1; X? x2 = x + bar(7); }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('D? foo(X? x) { X? x1; X? x2 = x + bar(7); }');
|
||||
}
|
||||
|
||||
void test_assignment_simple() {
|
||||
parseCompilationUnit('D? foo(X? x) { X? x1; X? x2 = x; }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('D? foo(X? x) { X? x1; X? x2 = x; }');
|
||||
}
|
||||
|
||||
void test_binary_expression_statement() {
|
||||
final unit = parseCompilationUnit('D? foo(X? x) { X ?? x2; }',
|
||||
featureSet: nonNullable);
|
||||
final unit = parseCompilationUnit('D? foo(X? x) { X ?? x2; }');
|
||||
FunctionDeclaration funct = unit.declarations[0];
|
||||
BlockFunctionBody body = funct.functionExpression.body;
|
||||
ExpressionStatement statement = body.block.statements[0];
|
||||
|
@ -2232,13 +2237,11 @@ class NNBDParserTest_Fasta extends FastaParserTestCase {
|
|||
}
|
||||
|
||||
void test_conditional() {
|
||||
parseCompilationUnit('D? foo(X? x) { X ? 7 : y; }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('D? foo(X? x) { X ? 7 : y; }');
|
||||
}
|
||||
|
||||
void test_conditional_complex() {
|
||||
parseCompilationUnit('D? foo(X? x) { X ? x2 = x + bar(7) : y; }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('D? foo(X? x) { X ? x2 = x + bar(7) : y; }');
|
||||
}
|
||||
|
||||
void test_conditional_error() {
|
||||
|
@ -2247,74 +2250,62 @@ class NNBDParserTest_Fasta extends FastaParserTestCase {
|
|||
expectedError(ParserErrorCode.MISSING_IDENTIFIER, 19, 1),
|
||||
expectedError(ParserErrorCode.EXPECTED_TOKEN, 40, 1),
|
||||
expectedError(ParserErrorCode.MISSING_IDENTIFIER, 40, 1),
|
||||
],
|
||||
featureSet: nonNullable);
|
||||
]);
|
||||
}
|
||||
|
||||
void test_conditional_simple() {
|
||||
parseCompilationUnit('D? foo(X? x) { X ? x2 = x : y; }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('D? foo(X? x) { X ? x2 = x : y; }');
|
||||
}
|
||||
|
||||
void test_enableNonNullable_false() {
|
||||
parseCompilationUnit('main() { x is String? ? (x + y) : z; }',
|
||||
errors: [expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 20, 1)]);
|
||||
errors: [expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 20, 1)],
|
||||
featureSet: preNonNullable);
|
||||
}
|
||||
|
||||
void test_for() {
|
||||
parseCompilationUnit('main() { for(int x = 0; x < 7; ++x) { } }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('main() { for(int x = 0; x < 7; ++x) { } }');
|
||||
}
|
||||
|
||||
void test_for_conditional() {
|
||||
parseCompilationUnit('main() { for(x ? y = 7 : y = 8; y < 10; ++y) { } }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('main() { for(x ? y = 7 : y = 8; y < 10; ++y) { } }');
|
||||
}
|
||||
|
||||
void test_for_nullable() {
|
||||
parseCompilationUnit('main() { for(int? x = 0; x < 7; ++x) { } }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('main() { for(int? x = 0; x < 7; ++x) { } }');
|
||||
}
|
||||
|
||||
void test_foreach() {
|
||||
parseCompilationUnit('main() { for(int x in [7]) { } }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('main() { for(int x in [7]) { } }');
|
||||
}
|
||||
|
||||
void test_foreach_nullable() {
|
||||
parseCompilationUnit('main() { for(int? x in [7, null]) { } }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('main() { for(int? x in [7, null]) { } }');
|
||||
}
|
||||
|
||||
void test_gft_nullable() {
|
||||
parseCompilationUnit('main() { C? Function() x = 7; }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('main() { C? Function() x = 7; }');
|
||||
}
|
||||
|
||||
void test_gft_nullable_1() {
|
||||
parseCompilationUnit('main() { C Function()? x = 7; }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('main() { C Function()? x = 7; }');
|
||||
}
|
||||
|
||||
void test_gft_nullable_2() {
|
||||
parseCompilationUnit('main() { C? Function()? x = 7; }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('main() { C? Function()? x = 7; }');
|
||||
}
|
||||
|
||||
void test_gft_nullable_3() {
|
||||
parseCompilationUnit('main() { C? Function()? Function()? x = 7; }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('main() { C? Function()? Function()? x = 7; }');
|
||||
}
|
||||
|
||||
void test_gft_nullable_prefixed() {
|
||||
parseCompilationUnit('main() { C.a? Function()? x = 7; }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('main() { C.a? Function()? x = 7; }');
|
||||
}
|
||||
|
||||
void test_is_nullable() {
|
||||
CompilationUnit unit = parseCompilationUnit(
|
||||
'main() { x is String? ? (x + y) : z; }',
|
||||
featureSet: nonNullable);
|
||||
CompilationUnit unit =
|
||||
parseCompilationUnit('main() { x is String? ? (x + y) : z; }');
|
||||
FunctionDeclaration function = unit.declarations[0];
|
||||
BlockFunctionBody body = function.functionExpression.body;
|
||||
ExpressionStatement statement = body.block.statements[0];
|
||||
|
@ -2329,9 +2320,8 @@ class NNBDParserTest_Fasta extends FastaParserTestCase {
|
|||
}
|
||||
|
||||
void test_is_nullable_parenthesis() {
|
||||
CompilationUnit unit = parseCompilationUnit(
|
||||
'main() { (x is String?) ? (x + y) : z; }',
|
||||
featureSet: nonNullable);
|
||||
CompilationUnit unit =
|
||||
parseCompilationUnit('main() { (x is String?) ? (x + y) : z; }');
|
||||
FunctionDeclaration function = unit.declarations[0];
|
||||
BlockFunctionBody body = function.functionExpression.body;
|
||||
ExpressionStatement statement = body.block.statements[0];
|
||||
|
@ -2350,9 +2340,7 @@ class NNBDParserTest_Fasta extends FastaParserTestCase {
|
|||
parseCompilationUnit('''
|
||||
// @dart = 2.2
|
||||
main() { (x is String?) ? (x + y) : z; }
|
||||
''',
|
||||
errors: [expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 36, 1)],
|
||||
featureSet: nonNullable);
|
||||
''', errors: [expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 36, 1)]);
|
||||
}
|
||||
|
||||
void test_late_as_identifier() {
|
||||
|
@ -2385,12 +2373,11 @@ void f(C c) {
|
|||
main() {
|
||||
f(new C());
|
||||
}
|
||||
''', featureSet: nonNullable);
|
||||
''');
|
||||
}
|
||||
|
||||
void test_nullCheck() {
|
||||
var unit = parseCompilationUnit('f(int? y) { var x = y!; }',
|
||||
featureSet: nonNullable);
|
||||
var unit = parseCompilationUnit('f(int? y) { var x = y!; }');
|
||||
FunctionDeclaration function = unit.declarations[0];
|
||||
BlockFunctionBody body = function.functionExpression.body;
|
||||
VariableDeclarationStatement statement = body.block.statements[0];
|
||||
|
@ -2414,23 +2401,36 @@ main() {
|
|||
expect(identifier.name, 'y');
|
||||
}
|
||||
|
||||
void test_nullCheckAfterGetterAccess() {
|
||||
parseCompilationUnit('f() { var x = g.x!.y + 7; }');
|
||||
}
|
||||
|
||||
void test_nullCheckAfterMethodCall() {
|
||||
parseCompilationUnit('f() { var x = g.m()!.y + 7; }');
|
||||
}
|
||||
|
||||
void test_nullCheckBeforeGetterAccess() {
|
||||
parseCompilationUnit('f() { var x = g!.x + 7; }');
|
||||
}
|
||||
|
||||
void test_nullCheckBeforeMethodCall() {
|
||||
parseCompilationUnit('f() { var x = g!.m() + 7; }');
|
||||
}
|
||||
|
||||
void test_nullCheckFunctionResult() {
|
||||
parseCompilationUnit('f() { var x = g()! + 7; }', featureSet: nonNullable);
|
||||
parseCompilationUnit('f() { var x = g()! + 7; }');
|
||||
}
|
||||
|
||||
void test_nullCheckIndexedValue() {
|
||||
parseCompilationUnit('f(int? y) { var x = y[0]! + 7; }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('f(int? y) { var x = y[0]! + 7; }');
|
||||
}
|
||||
|
||||
void test_nullCheckIndexedValue2() {
|
||||
parseCompilationUnit('f(int? y) { var x = super.y[0]! + 7; }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('f(int? y) { var x = super.y[0]! + 7; }');
|
||||
}
|
||||
|
||||
void test_nullCheckInExpression() {
|
||||
parseCompilationUnit('f(int? y) { var x = y! + 7; }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('f(int? y) { var x = y! + 7; }');
|
||||
}
|
||||
|
||||
void test_nullCheckInExpression_disabled() {
|
||||
|
@ -2443,28 +2443,23 @@ main() {
|
|||
}
|
||||
|
||||
void test_nullCheckMethodResult() {
|
||||
parseCompilationUnit('f() { var x = g.m()! + 7; }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('f() { var x = g.m()! + 7; }');
|
||||
}
|
||||
|
||||
void test_nullCheckMethodResult2() {
|
||||
parseCompilationUnit('f() { var x = g?.m()! + 7; }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('f() { var x = g?.m()! + 7; }');
|
||||
}
|
||||
|
||||
void test_nullCheckMethodResult3() {
|
||||
parseCompilationUnit('f() { var x = super.m()! + 7; }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('f() { var x = super.m()! + 7; }');
|
||||
}
|
||||
|
||||
void test_nullCheckOnConstConstructor() {
|
||||
parseCompilationUnit('f() { var x = const Foo()!; }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('f() { var x = const Foo()!; }');
|
||||
}
|
||||
|
||||
void test_nullCheckOnConstructor() {
|
||||
parseCompilationUnit('f() { var x = new Foo()!; }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('f() { var x = new Foo()!; }');
|
||||
}
|
||||
|
||||
void test_nullCheckOnLiteral_disabled() {
|
||||
|
@ -2475,47 +2470,46 @@ main() {
|
|||
|
||||
void test_nullCheckOnLiteralDouble() {
|
||||
// Issues like this should be caught during later analysis
|
||||
parseCompilationUnit('f() { var x = 1.2!; }', featureSet: nonNullable);
|
||||
parseCompilationUnit('f() { var x = 1.2!; }');
|
||||
}
|
||||
|
||||
void test_nullCheckOnLiteralInt() {
|
||||
// Issues like this should be caught during later analysis
|
||||
parseCompilationUnit('f() { var x = 0!; }', featureSet: nonNullable);
|
||||
parseCompilationUnit('f() { var x = 0!; }');
|
||||
}
|
||||
|
||||
void test_nullCheckOnLiteralList() {
|
||||
// Issues like this should be caught during later analysis
|
||||
parseCompilationUnit('f() { var x = [1,2]!; }', featureSet: nonNullable);
|
||||
parseCompilationUnit('f() { var x = [1,2]!; }');
|
||||
}
|
||||
|
||||
void test_nullCheckOnLiteralMap() {
|
||||
// Issues like this should be caught during later analysis
|
||||
parseCompilationUnit('f() { var x = {1:2}!; }', featureSet: nonNullable);
|
||||
parseCompilationUnit('f() { var x = {1:2}!; }');
|
||||
}
|
||||
|
||||
void test_nullCheckOnLiteralSet() {
|
||||
// Issues like this should be caught during later analysis
|
||||
parseCompilationUnit('f() { var x = {1,2}!; }', featureSet: nonNullable);
|
||||
parseCompilationUnit('f() { var x = {1,2}!; }');
|
||||
}
|
||||
|
||||
void test_nullCheckOnLiteralString() {
|
||||
// Issues like this should be caught during later analysis
|
||||
parseCompilationUnit('f() { var x = "seven"!; }', featureSet: nonNullable);
|
||||
parseCompilationUnit('f() { var x = "seven"!; }');
|
||||
}
|
||||
|
||||
void test_nullCheckOnNull() {
|
||||
// Issues like this should be caught during later analysis
|
||||
parseCompilationUnit('f() { var x = null!; }', featureSet: nonNullable);
|
||||
parseCompilationUnit('f() { var x = null!; }');
|
||||
}
|
||||
|
||||
void test_nullCheckOnSymbol() {
|
||||
// Issues like this should be caught during later analysis
|
||||
parseCompilationUnit('f() { var x = #seven!; }', featureSet: nonNullable);
|
||||
parseCompilationUnit('f() { var x = #seven!; }');
|
||||
}
|
||||
|
||||
void test_nullCheckOnValue() {
|
||||
parseCompilationUnit('f(Point p) { var x = p.y! + 7; }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('f(Point p) { var x = p.y! + 7; }');
|
||||
}
|
||||
|
||||
void test_nullCheckOnValue_disabled() {
|
||||
|
@ -2525,27 +2519,24 @@ main() {
|
|||
}
|
||||
|
||||
void test_nullCheckParenthesizedExpression() {
|
||||
parseCompilationUnit('f(int? y) { var x = (y)! + 7; }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('f(int? y) { var x = (y)! + 7; }');
|
||||
}
|
||||
|
||||
void test_nullCheckPropertyAccess() {
|
||||
parseCompilationUnit('f() { var x = g.p! + 7; }', featureSet: nonNullable);
|
||||
parseCompilationUnit('f() { var x = g.p! + 7; }');
|
||||
}
|
||||
|
||||
void test_nullCheckPropertyAccess2() {
|
||||
parseCompilationUnit('f() { var x = g?.p! + 7; }', featureSet: nonNullable);
|
||||
parseCompilationUnit('f() { var x = g?.p! + 7; }');
|
||||
}
|
||||
|
||||
void test_nullCheckPropertyAccess3() {
|
||||
parseCompilationUnit('f() { var x = super.p! + 7; }',
|
||||
featureSet: nonNullable);
|
||||
parseCompilationUnit('f() { var x = super.p! + 7; }');
|
||||
}
|
||||
|
||||
void test_postfix_null_assertion_and_unary_prefix_operator_precedence() {
|
||||
// -x! is parsed as -(x!).
|
||||
var unit =
|
||||
parseCompilationUnit('void main() { -x!; }', featureSet: nonNullable);
|
||||
var unit = parseCompilationUnit('void main() { -x!; }');
|
||||
var function = unit.declarations[0] as FunctionDeclaration;
|
||||
var body = function.functionExpression.body as BlockFunctionBody;
|
||||
var statement = body.block.statements[0] as ExpressionStatement;
|
||||
|
@ -2557,8 +2548,7 @@ main() {
|
|||
|
||||
void test_postfix_null_assertion_of_postfix_expression() {
|
||||
// x++! is parsed as (x++)!.
|
||||
var unit =
|
||||
parseCompilationUnit('void main() { x++!; }', featureSet: nonNullable);
|
||||
var unit = parseCompilationUnit('void main() { x++!; }');
|
||||
var function = unit.declarations[0] as FunctionDeclaration;
|
||||
var body = function.functionExpression.body as BlockFunctionBody;
|
||||
var statement = body.block.statements[0] as ExpressionStatement;
|
||||
|
|
|
@ -3939,7 +3939,7 @@ class Parser {
|
|||
}
|
||||
Token next = token.next;
|
||||
TokenType type = next.type;
|
||||
int tokenLevel = _computePrecedence(type);
|
||||
int tokenLevel = _computePrecedence(next);
|
||||
for (int level = tokenLevel; level >= precedence; --level) {
|
||||
int lastBinaryExpressionLevel = -1;
|
||||
while (identical(tokenLevel, level)) {
|
||||
|
@ -3988,10 +3988,14 @@ class Parser {
|
|||
rewriter.replaceTokenFollowing(token, replacement);
|
||||
replacement.endToken = replacement.next;
|
||||
token = parseArgumentOrIndexStar(token, noTypeParamOrArg);
|
||||
} else if (identical(type, TokenType.BANG)) {
|
||||
listener.handleNonNullAssertExpression(token.next);
|
||||
token = next;
|
||||
} else {
|
||||
// Recovery
|
||||
reportRecoverableErrorWithToken(
|
||||
token.next, fasta.templateUnexpectedToken);
|
||||
token = next;
|
||||
}
|
||||
} else if (identical(type, TokenType.IS)) {
|
||||
token = parseIsOperatorRest(token);
|
||||
|
@ -4020,20 +4024,23 @@ class Parser {
|
|||
}
|
||||
next = token.next;
|
||||
type = next.type;
|
||||
tokenLevel = _computePrecedence(type);
|
||||
tokenLevel = _computePrecedence(next);
|
||||
}
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
int _computePrecedence(TokenType type) {
|
||||
int _computePrecedence(Token token) {
|
||||
TokenType type = token.type;
|
||||
if (identical(type, TokenType.BANG)) {
|
||||
// The '!' has prefix precedence but here it's being used as a
|
||||
// postfix operator to assert the expression has a non-null value.
|
||||
if (identical(token.next.type, TokenType.PERIOD)) {
|
||||
return SELECTOR_PRECEDENCE;
|
||||
}
|
||||
return POSTFIX_PRECEDENCE;
|
||||
} else {
|
||||
return type.precedence;
|
||||
}
|
||||
return type.precedence;
|
||||
}
|
||||
|
||||
Token parseCascadeExpression(Token token) {
|
||||
|
|
Loading…
Reference in a new issue