Allow async as an identifier everywhere.

Fixes #37063

Bug: http://dartbug.com/37063
Change-Id: I2253c3088fbe33eca1072f2480cf0cf3cc363362
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/103524
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Leaf Petersen <leafp@google.com>
Commit-Queue: Lasse R.H. Nielsen <lrn@google.com>
This commit is contained in:
Lasse R.H. Nielsen 2019-05-24 08:21:14 +00:00 committed by commit-bot@chromium.org
parent dbd70dd214
commit eca6c8953f
12 changed files with 229 additions and 303 deletions

View file

@ -4,6 +4,9 @@
### Language
* The identifier `async` can now be used in asynchronous and generator
functions.
### Core library
#### `dart:io`

View file

@ -51,8 +51,8 @@ class ParserErrorCode extends ErrorCode {
static const ParserErrorCode ASYNC_KEYWORD_USED_AS_IDENTIFIER =
const ParserErrorCode(
'ASYNC_KEYWORD_USED_AS_IDENTIFIER',
"The keywords 'async', 'await', and 'yield' can't be used as "
"identifiers in an asynchronous or generator function.");
"The keywords 'await' and 'yield' can't be used as "
"identifiers in an asynchronous or generator function.");
static const ParserErrorCode BREAK_OUTSIDE_OF_LOOP = _BREAK_OUTSIDE_OF_LOOP;
@ -340,7 +340,7 @@ class ParserErrorCode extends ErrorCode {
static const ParserErrorCode INVALID_COMMENT_REFERENCE = const ParserErrorCode(
'INVALID_COMMENT_REFERENCE',
"Comment references should contain a possibly prefixed identifier and "
"can start with 'new', but shouldn't contain anything else.");
"can start with 'new', but shouldn't contain anything else.");
static const ParserErrorCode INVALID_CONSTRUCTOR_NAME = const ParserErrorCode(
'INVALID_CONSTRUCTOR_NAME',
@ -564,7 +564,7 @@ class ParserErrorCode extends ErrorCode {
const ParserErrorCode(
'MULTIPLE_VARIABLES_IN_FOR_EACH',
"A single loop variable must be declared in a for-each loop before "
"the 'in', but {0} were found.",
"the 'in', but {0} were found.",
correction:
"Try moving all but one of the declarations inside the loop body.");
@ -588,14 +588,14 @@ class ParserErrorCode extends ErrorCode {
const ParserErrorCode(
'NATIVE_CLAUSE_IN_NON_SDK_CODE',
"Native clause can only be used in the SDK and code that is loaded "
"through native extensions.",
"through native extensions.",
correction: "Try removing the native clause.");
static const ParserErrorCode NATIVE_FUNCTION_BODY_IN_NON_SDK_CODE =
const ParserErrorCode(
'NATIVE_FUNCTION_BODY_IN_NON_SDK_CODE',
"Native functions can only be declared in the SDK and code that is "
"loaded through native extensions.",
"loaded through native extensions.",
correction: "Try removing the word 'native'.");
static const ParserErrorCode NATIVE_CLAUSE_SHOULD_BE_ANNOTATION =

View file

@ -6976,8 +6976,7 @@ class Parser {
SimpleIdentifier _parseSimpleIdentifierUnchecked(
{bool isDeclaration: false}) {
String lexeme = _currentToken.lexeme;
if ((_inAsync || _inGenerator) &&
(lexeme == ASYNC || lexeme == _AWAIT || lexeme == _YIELD)) {
if ((_inAsync || _inGenerator) && (lexeme == _AWAIT || lexeme == _YIELD)) {
_reportErrorForCurrentToken(
ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER);
}

View file

@ -2726,7 +2726,6 @@ class A {
}
''', [
error(HintCode.UNUSED_LOCAL_VARIABLE, 32, 5),
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 32, 5),
]);
}

View file

@ -16,278 +16,6 @@ main() {
@reflectiveTest
class AsyncKeywordUsedAsIdentifierTest extends DriverResolutionTest {
test_async_annotation() async {
await assertErrorsInCode('''
const int async = 0;
f() async {
g(@async x) {}
g(0);
}
''', [
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 38, 5),
]);
}
test_async_argumentLabel() async {
await assertErrorsInCode('''
f(c) async {
c.g(async: 0);
}
''', [
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 19, 5),
]);
}
test_async_async() async {
await assertErrorsInCode('''
f() async {
var async = 1;
print(async);
}
''', [
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 18, 5),
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 37, 5),
]);
}
test_async_asyncStar() async {
await assertErrorsInCode('''
f() async* {
var async = 1;
print(async);
}
''', [
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 19, 5),
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 38, 5),
]);
}
test_async_break() async {
await assertErrorsInCode('''
f() async {
while (true) {
break async;
}
}
''', [
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 39, 5),
error(CompileTimeErrorCode.LABEL_UNDEFINED, 39, 5),
]);
}
test_async_catchException() async {
await assertErrorsInCode('''
g() {}
f() async {
try {
g();
} catch (async) { }
}
''', [
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 47, 5),
]);
}
test_async_catchStacktrace() async {
await assertErrorsInCode('''
g() {}
f() async {
try {
g();
} catch (e, async) { }
}
''', [
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 50, 5),
error(HintCode.UNUSED_CATCH_STACK, 50, 5),
]);
}
test_async_continue() async {
await assertErrorsInCode('''
f() async {
while (true) {
continue async;
}
}
''', [
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 42, 5),
error(CompileTimeErrorCode.LABEL_UNDEFINED, 42, 5),
]);
}
test_async_for() async {
await assertErrorsInCode('''
var async;
f() async {
for (async in []) {}
}
''', [
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 30, 5),
]);
}
test_async_formalParameter() async {
await assertErrorsInCode('''
f() async {
g(int async) {}
g(0);
}
''', [
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 20, 5),
]);
}
test_async_getter() async {
await assertErrorsInCode('''
class C {
int get async => 1;
}
f() async {
return new C().async;
}
''', [
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 63, 5),
]);
}
test_async_invocation() async {
await assertErrorsInCode('''
class C {
int async() => 1;
}
f() async {
return new C().async();
}
''', [
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 61, 5),
]);
}
test_async_invocation_cascaded() async {
await assertErrorsInCode('''
class C {
int async() => 1;
}
f() async {
return new C()..async();
}
''', [
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 62, 5),
]);
}
test_async_label() async {
await assertErrorsInCode('''
f() async {
async: g();
}
g() {}
''', [
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 14, 5),
error(HintCode.UNUSED_LABEL, 14, 6),
]);
}
test_async_localFunction() async {
await assertErrorsInCode('''
f() async {
int async() => null;
async();
}
''', [
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 18, 5),
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 37, 5),
]);
}
test_async_prefix() async {
await assertErrorsInCode('''
import 'dart:async' as async;
f() async {
return new async.Future.value(0);
}
''', [
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 55, 5),
]);
}
test_async_setter() async {
await assertErrorsInCode('''
class C {
void set async(int i) {}
}
f() async {
new C().async = 1;
}
''', [
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 61, 5),
]);
}
test_async_setter_cascaded() async {
await assertErrorsInCode('''
class C {
void set async(int i) {}
}
f() async {
return new C()..async = 1;
}
''', [
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 69, 5),
]);
}
test_async_stringInterpolation() async {
await assertErrorsInCode(r'''
int async = 1;
f() async {
return "$async";
}
''', [
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 38, 5),
]);
}
test_async_suffix() async {
newFile("/test/lib/lib1.dart", content: r'''
library lib1;
int async;
''');
await assertErrorsInCode('''
import 'lib1.dart' as l;
f() async {
return l.async;
}
''', [
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 48, 5),
]);
}
test_async_switchLabel() async {
await assertErrorsInCode('''
f() async {
switch (0) {
async: case 0: break;
}
}
''', [
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 31, 5),
error(HintCode.UNUSED_LABEL, 31, 6),
]);
}
test_async_syncStar() async {
await assertErrorsInCode('''
f() sync* {
var async = 1;
print(async);
}
''', [
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 18, 5),
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 37, 5),
]);
}
test_await_async() async {
await assertErrorsInCode('''
f() async {

View file

@ -232,16 +232,6 @@ const MessageCode messageAssertExtraneousArgument = const MessageCode(
"AssertExtraneousArgument",
message: r"""`assert` can't have more than two arguments.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeAsyncAsIdentifier = messageAsyncAsIdentifier;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const MessageCode messageAsyncAsIdentifier = const MessageCode(
"AsyncAsIdentifier",
analyzerCodes: <String>["ASYNC_KEYWORD_USED_AS_IDENTIFIER"],
message:
r"""'async' can't be used as an identifier in 'async', 'async*', or 'sync*' methods.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeAwaitAsIdentifier = messageAwaitAsIdentifier;

View file

@ -940,8 +940,6 @@ void checkAsyncAwaitYieldAsIdentifier(Token identifier, Parser parser) {
parser.reportRecoverableError(identifier, fasta.messageAwaitAsIdentifier);
} else if (optional('yield', identifier)) {
parser.reportRecoverableError(identifier, fasta.messageYieldAsIdentifier);
} else if (optional('async', identifier)) {
parser.reportRecoverableError(identifier, fasta.messageAsyncAsIdentifier);
}
}
}

View file

@ -1165,10 +1165,6 @@ AbstractNotSync:
template: "Abstract methods can't use 'async', 'async*', or 'sync*'."
analyzerCode: NON_SYNC_ABSTRACT_METHOD
AsyncAsIdentifier:
analyzerCode: ASYNC_KEYWORD_USED_AS_IDENTIFIER
template: "'async' can't be used as an identifier in 'async', 'async*', or 'sync*' methods."
AwaitAsIdentifier:
template: "'await' can't be used as an identifier in 'async', 'async*', or 'sync*' methods."
analyzerCode: ASYNC_KEYWORD_USED_AS_IDENTIFIER

View file

@ -0,0 +1,209 @@
// Copyright (c) 2019, 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.
import 'dart:async' as async;
import 'async_lib.dart' as l; // Minimal library containing "int async;".
// Adapted from Analyzer test testing where `async` was not previously allowed.
// Helpers
void ignore(argument) {}
class GNamed {
void g({Object async = null}) {}
}
class AGet {
int get async => 1;
set async(int i) {}
}
class ACall {
int async() => 1;
}
main() {
// Each test declares a spearate async function, tests that `async`
// can occur in it, and makes sure the function is run.
{
const int async = 0;
f() async {
g(@async x) {}
g(0);
}
f();
}
{
f(c) async {
c.g(async: 0);
}
f(GNamed());
}
{
f() async {
var async = 1;
ignore(async);
}
f();
}
{
f() async* {
var async = 1;
ignore(async);
}
f().forEach(ignore);
}
{
f() async {
async:
while (true) {
break async;
}
}
f();
}
{
g() {}
f() async {
try {
g();
} catch (async) {}
}
f();
}
{
g() {}
f() async {
try {
g();
} catch (e, async) {}
}
f();
}
{
f() async {
async:
while (true) {
if (false) continue async;
break;
}
}
f();
}
{
var async;
f() async {
for (async in []) {}
}
f();
}
{
f() async {
g(int async) {}
g(0);
}
f();
}
{
f() async {
return new AGet().async;
}
f();
}
{
f() async {
return new ACall().async();
}
f();
}
{
f() async {
return new ACall()..async();
}
f();
}
{
g() {}
f() async {
async:
g();
}
f();
}
{
f() async {
int async() => null;
async();
}
}
{
f() async {
return async.Future.value(0);
}
f();
}
{
f() async {
new AGet().async = 1;
}
f();
}
{
f() async {
return new AGet()..async = 1;
}
f();
}
{
int async = 1;
f() async {
return "$async";
}
f();
}
{
f() async {
return l.async;
}
f();
}
{
f() async {
switch (0) {
async:
case 0:
break;
}
}
f();
}
{
f() sync* {
var async = 1;
ignore(async);
}
f();
}
}

View file

@ -0,0 +1,7 @@
// Copyright (c) 2019, 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.
// Helper library for async_identifier_test.dart
int async;

View file

@ -21,7 +21,7 @@
import 'dart:async';
Future<int> f1() async {
int async = 1; //# 01: syntax error
int async = 1;
int await = 1; //# 02: syntax error
int yield = 1; //# 03: syntax error
@ -32,7 +32,7 @@ Future<int> f1() async {
}
Stream<int> f2() async* {
int async = 1; //# 04: syntax error
int async = 1;
int await = 1; //# 05: syntax error
int yield = 1; //# 06: syntax error
@ -43,7 +43,7 @@ Stream<int> f2() async* {
}
Iterable<int> f3() sync* {
int async = 1; //# 07: syntax error
int async = 1;
int await = 1; //# 08: syntax error
int yield = 1; //# 09: syntax error

View file

@ -15,13 +15,10 @@ var yield = "topLevelYield";
test01() sync* {
var yield = 0; // //# 01: syntax error
var await = 0; // //# 02: syntax error
var async = 0; // //# 03: syntax error
bool yield() => false; //# 04: syntax error
bool await() => false; //# 05: syntax error
bool async() => false; //# 06: syntax error
var x1 = sync;
var x2 = async; // //# 07: syntax error
var x3 = await; // //# 08: syntax error
var x4 = await 55; // //# 09: compile-time error
var x4 = yield; // //# 10: syntax error