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>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8dbdc24..4bb5e3d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,9 @@
### Language
+* The identifier `async` can now be used in asynchronous and generator
+ functions.
+
### Core library
#### `dart:io`
diff --git a/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart b/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
index 5110557..11be8e1 100644
--- a/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
+++ b/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
@@ -51,8 +51,8 @@
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 @@
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 @@
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 @@
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 =
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index 21a62ae..d494c4e 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -6976,8 +6976,7 @@
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);
}
diff --git a/pkg/analyzer/test/generated/compile_time_error_code.dart b/pkg/analyzer/test/generated/compile_time_error_code.dart
index e11ba55..01c9695 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code.dart
@@ -2726,7 +2726,6 @@
}
''', [
error(HintCode.UNUSED_LOCAL_VARIABLE, 32, 5),
- error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 32, 5),
]);
}
diff --git a/pkg/analyzer/test/src/diagnostics/async_keyword_used_as_identifier_test.dart b/pkg/analyzer/test/src/diagnostics/async_keyword_used_as_identifier_test.dart
index 28ab163..f773a8c 100644
--- a/pkg/analyzer/test/src/diagnostics/async_keyword_used_as_identifier_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/async_keyword_used_as_identifier_test.dart
@@ -16,278 +16,6 @@
@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 {
diff --git a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
index 991c13b..24ab44d 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
@@ -233,16 +233,6 @@
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;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
diff --git a/pkg/front_end/lib/src/fasta/parser/identifier_context_impl.dart b/pkg/front_end/lib/src/fasta/parser/identifier_context_impl.dart
index db81019..0d0fccb 100644
--- a/pkg/front_end/lib/src/fasta/parser/identifier_context_impl.dart
+++ b/pkg/front_end/lib/src/fasta/parser/identifier_context_impl.dart
@@ -940,8 +940,6 @@
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);
}
}
}
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 42b24b6..4abb6b2 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -1165,10 +1165,6 @@
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
diff --git a/tests/language_2/async_identifier_test.dart b/tests/language_2/async_identifier_test.dart
new file mode 100644
index 0000000..5af2722
--- /dev/null
+++ b/tests/language_2/async_identifier_test.dart
@@ -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();
+ }
+}
diff --git a/tests/language_2/async_lib.dart b/tests/language_2/async_lib.dart
new file mode 100644
index 0000000..a6be037
--- /dev/null
+++ b/tests/language_2/async_lib.dart
@@ -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;
diff --git a/tests/language_2/known_identifier_usage_error_test.dart b/tests/language_2/known_identifier_usage_error_test.dart
index 9c96dc1..0d56f26 100644
--- a/tests/language_2/known_identifier_usage_error_test.dart
+++ b/tests/language_2/known_identifier_usage_error_test.dart
@@ -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 @@
}
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 @@
}
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
diff --git a/tests/language_2/sync_generator2_test.dart b/tests/language_2/sync_generator2_test.dart
index 9e33f0c..feaee63 100644
--- a/tests/language_2/sync_generator2_test.dart
+++ b/tests/language_2/sync_generator2_test.dart
@@ -15,13 +15,10 @@
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