mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 08:44:27 +00:00
[parser] Use endInvalidYieldStatement for async methods
This changes the parser to call endInvalidYieldStatement for yield statement both in sync and async methods. This ensures that the CFE creates an invalid expression for yield in async methods, making the generated AST verifiable. Change-Id: I1bfe922878fcf3dc19c823cb89ee869af3dd2ce3 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/309200 Commit-Queue: Johnni Winther <johnniwinther@google.com> Reviewed-by: Jens Johansen <jensj@google.com>
This commit is contained in:
parent
1100859b7e
commit
e5a68252e3
11 changed files with 381 additions and 9 deletions
|
@ -5484,7 +5484,6 @@ class Parser {
|
|||
return parseYieldStatement(token);
|
||||
|
||||
case AsyncModifier.Async:
|
||||
reportRecoverableError(token.next!, codes.messageYieldNotGenerator);
|
||||
return parseYieldStatement(token);
|
||||
}
|
||||
} else if (identical(value, 'const')) {
|
||||
|
@ -5530,18 +5529,15 @@ class Parser {
|
|||
}
|
||||
token = parseExpression(token);
|
||||
token = ensureSemicolon(token);
|
||||
if (inPlainSync) {
|
||||
// `yield` is only allowed in generators; A recoverable error is already
|
||||
// reported in the "async" case in `parseStatementX`. Only the "sync" case
|
||||
// needs to be handled here.
|
||||
if (inGenerator) {
|
||||
listener.endYieldStatement(begin, starToken, token);
|
||||
} else {
|
||||
codes.MessageCode errorCode = codes.messageYieldNotGenerator;
|
||||
reportRecoverableError(begin, errorCode);
|
||||
// TODO(srawlins): Add tests in analyzer to ensure the AstBuilder
|
||||
// correctly handles invalid yields, and that the error message is
|
||||
// correctly plumbed through.
|
||||
listener.endInvalidYieldStatement(begin, starToken, token, errorCode);
|
||||
} else {
|
||||
listener.endYieldStatement(begin, starToken, token);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
@ -8484,7 +8480,7 @@ class Parser {
|
|||
// declaration).
|
||||
return true;
|
||||
}
|
||||
} else if (token == Keyword.NULL) {
|
||||
} else if (token.keyword == Keyword.NULL) {
|
||||
return true;
|
||||
}
|
||||
// TODO(srawlins): Consider other possibilities for `token` which would
|
||||
|
|
|
@ -124,7 +124,7 @@ parseUnit(Future)
|
|||
listener: endArguments(0, (, ))
|
||||
listener: handleSend(f, ;)
|
||||
ensureSemicolon())
|
||||
inPlainSync()
|
||||
inGenerator()
|
||||
reportRecoverableError(yield, YieldNotGenerator)
|
||||
listener: handleRecoverableError(YieldNotGenerator, yield, yield)
|
||||
listener: endInvalidYieldStatement(yield, null, ;, YieldNotGenerator)
|
||||
|
|
22
pkg/front_end/testcases/general/invalid_yield.dart
Normal file
22
pkg/front_end/testcases/general/invalid_yield.dart
Normal file
|
@ -0,0 +1,22 @@
|
|||
// Copyright (c) 2023, 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.
|
||||
|
||||
method1(var a) {
|
||||
yield null;
|
||||
yield a;
|
||||
yield a();
|
||||
yield 1;
|
||||
}
|
||||
|
||||
method2() {
|
||||
yield* [1];
|
||||
}
|
||||
|
||||
method3() async {
|
||||
yield 1;
|
||||
}
|
||||
|
||||
method4() async {
|
||||
yield [1];
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
library;
|
||||
//
|
||||
// Problems in library:
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:6:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
// yield null;
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:7:3: Error: 'yield' isn't a type.
|
||||
// yield a;
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:8:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
// yield a();
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:9:3: Error: Expected ';' after this.
|
||||
// yield 1;
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:9:3: Error: Undefined name 'yield'.
|
||||
// yield 1;
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:13:3: Error: Undefined name 'yield'.
|
||||
// yield* [1];
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:17:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
// yield 1;
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:21:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
// yield [1];
|
||||
// ^^^^^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method method1(dynamic a) → dynamic {
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:6:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
yield null;
|
||||
^";
|
||||
invalid-type a;
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:8:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
yield a();
|
||||
^";
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:9:3: Error: Undefined name 'yield'.
|
||||
yield 1;
|
||||
^^^^^";
|
||||
1;
|
||||
}
|
||||
static method method2() → dynamic {
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:13:3: Error: Undefined name 'yield'.
|
||||
yield* [1];
|
||||
^^^^^"{<invalid>}.*(<core::int>[1]);
|
||||
}
|
||||
static method method3() → dynamic async /* futureValueType= dynamic */ {
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:17:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
yield 1;
|
||||
^";
|
||||
}
|
||||
static method method4() → dynamic async /* futureValueType= dynamic */ {
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:21:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
yield [1];
|
||||
^";
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
library;
|
||||
//
|
||||
// Problems in library:
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:6:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
// yield null;
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:7:3: Error: 'yield' isn't a type.
|
||||
// yield a;
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:8:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
// yield a();
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:9:3: Error: Expected ';' after this.
|
||||
// yield 1;
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:9:3: Error: Undefined name 'yield'.
|
||||
// yield 1;
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:13:3: Error: Undefined name 'yield'.
|
||||
// yield* [1];
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:17:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
// yield 1;
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:21:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
// yield [1];
|
||||
// ^^^^^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method method1(dynamic a) → dynamic {
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:6:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
yield null;
|
||||
^";
|
||||
invalid-type a;
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:8:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
yield a();
|
||||
^";
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:9:3: Error: Undefined name 'yield'.
|
||||
yield 1;
|
||||
^^^^^";
|
||||
1;
|
||||
}
|
||||
static method method2() → dynamic {
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:13:3: Error: Undefined name 'yield'.
|
||||
yield* [1];
|
||||
^^^^^"{<invalid>}.*(core::_GrowableList::_literal1<core::int>(1));
|
||||
}
|
||||
static method method3() → dynamic async /* futureValueType= dynamic */ {
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:17:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
yield 1;
|
||||
^";
|
||||
}
|
||||
static method method4() → dynamic async /* futureValueType= dynamic */ {
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:21:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
yield [1];
|
||||
^";
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
method1(var a) {}
|
||||
method2() {}
|
||||
method3() async {}
|
||||
method4() async {}
|
|
@ -0,0 +1,4 @@
|
|||
method1(var a) {}
|
||||
method2() {}
|
||||
method3() async {}
|
||||
method4() async {}
|
|
@ -0,0 +1,67 @@
|
|||
library;
|
||||
//
|
||||
// Problems in library:
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:6:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
// yield null;
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:7:3: Error: 'yield' isn't a type.
|
||||
// yield a;
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:8:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
// yield a();
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:9:3: Error: Expected ';' after this.
|
||||
// yield 1;
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:9:3: Error: Undefined name 'yield'.
|
||||
// yield 1;
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:13:3: Error: Undefined name 'yield'.
|
||||
// yield* [1];
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:17:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
// yield 1;
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:21:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
// yield [1];
|
||||
// ^^^^^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method method1(dynamic a) → dynamic {
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:6:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
yield null;
|
||||
^";
|
||||
invalid-type a;
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:8:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
yield a();
|
||||
^";
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:9:3: Error: Undefined name 'yield'.
|
||||
yield 1;
|
||||
^^^^^";
|
||||
1;
|
||||
}
|
||||
static method method2() → dynamic {
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:13:3: Error: Undefined name 'yield'.
|
||||
yield* [1];
|
||||
^^^^^"{<invalid>}.*(<core::int>[1]);
|
||||
}
|
||||
static method method3() → dynamic async /* futureValueType= dynamic */ {
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:17:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
yield 1;
|
||||
^";
|
||||
}
|
||||
static method method4() → dynamic async /* futureValueType= dynamic */ {
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:21:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
yield [1];
|
||||
^";
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
library;
|
||||
//
|
||||
// Problems in library:
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:6:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
// yield null;
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:7:3: Error: 'yield' isn't a type.
|
||||
// yield a;
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:8:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
// yield a();
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:9:3: Error: Expected ';' after this.
|
||||
// yield 1;
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:9:3: Error: Undefined name 'yield'.
|
||||
// yield 1;
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:13:3: Error: Undefined name 'yield'.
|
||||
// yield* [1];
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:17:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
// yield 1;
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:21:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
// yield [1];
|
||||
// ^^^^^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method method1(dynamic a) → dynamic {
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:6:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
yield null;
|
||||
^";
|
||||
invalid-type a;
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:8:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
yield a();
|
||||
^";
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:9:3: Error: Undefined name 'yield'.
|
||||
yield 1;
|
||||
^^^^^";
|
||||
1;
|
||||
}
|
||||
static method method2() → dynamic {
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:13:3: Error: Undefined name 'yield'.
|
||||
yield* [1];
|
||||
^^^^^"{<invalid>}.*(<core::int>[1]);
|
||||
}
|
||||
static method method3() → dynamic async /* futureValueType= dynamic */ {
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:17:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
yield 1;
|
||||
^";
|
||||
}
|
||||
static method method4() → dynamic async /* futureValueType= dynamic */ {
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:21:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
yield [1];
|
||||
^";
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
library;
|
||||
import self as self;
|
||||
|
||||
static method method1(dynamic a) → dynamic
|
||||
;
|
||||
static method method2() → dynamic
|
||||
;
|
||||
static method method3() → dynamic async
|
||||
;
|
||||
static method method4() → dynamic async
|
||||
;
|
|
@ -0,0 +1,67 @@
|
|||
library;
|
||||
//
|
||||
// Problems in library:
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:6:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
// yield null;
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:7:3: Error: 'yield' isn't a type.
|
||||
// yield a;
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:8:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
// yield a();
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:9:3: Error: Expected ';' after this.
|
||||
// yield 1;
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:9:3: Error: Undefined name 'yield'.
|
||||
// yield 1;
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:13:3: Error: Undefined name 'yield'.
|
||||
// yield* [1];
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:17:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
// yield 1;
|
||||
// ^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/invalid_yield.dart:21:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
// yield [1];
|
||||
// ^^^^^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method method1(dynamic a) → dynamic {
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:6:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
yield null;
|
||||
^";
|
||||
invalid-type a;
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:8:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
yield a();
|
||||
^";
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:9:3: Error: Undefined name 'yield'.
|
||||
yield 1;
|
||||
^^^^^";
|
||||
1;
|
||||
}
|
||||
static method method2() → dynamic {
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:13:3: Error: Undefined name 'yield'.
|
||||
yield* [1];
|
||||
^^^^^"{<invalid>}.*(core::_GrowableList::_literal1<core::int>(1));
|
||||
}
|
||||
static method method3() → dynamic async /* futureValueType= dynamic */ {
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:17:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
yield 1;
|
||||
^";
|
||||
}
|
||||
static method method4() → dynamic async /* futureValueType= dynamic */ {
|
||||
invalid-expression "pkg/front_end/testcases/general/invalid_yield.dart:21:3: Error: 'yield' can only be used in 'sync*' or 'async*' methods.
|
||||
yield [1];
|
||||
^";
|
||||
}
|
Loading…
Reference in a new issue