diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dbdc2410ff..4bb5e3dfd43 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 511055704f2..11be8e1aae1 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 @@ 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 = diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart index 21a62ae2518..d494c4e6b48 100644 --- a/pkg/analyzer/lib/src/generated/parser.dart +++ b/pkg/analyzer/lib/src/generated/parser.dart @@ -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); } diff --git a/pkg/analyzer/test/generated/compile_time_error_code.dart b/pkg/analyzer/test/generated/compile_time_error_code.dart index e11ba552e68..01c9695c691 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 @@ class A { } ''', [ 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 28ab16345c6..f773a8cffdc 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 @@ 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 { 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 991c13b33d0..24ab44da5e9 100644 --- a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart +++ b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart @@ -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 codeAsyncAsIdentifier = messageAsyncAsIdentifier; - -// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. -const MessageCode messageAsyncAsIdentifier = const MessageCode( - "AsyncAsIdentifier", - analyzerCodes: ["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 codeAwaitAsIdentifier = messageAwaitAsIdentifier; 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 db81019bba9..0d0fccb6d92 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 @@ 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); } } } diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml index 42b24b63996..4abb6b24404 100644 --- a/pkg/front_end/messages.yaml +++ b/pkg/front_end/messages.yaml @@ -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 diff --git a/tests/language_2/async_identifier_test.dart b/tests/language_2/async_identifier_test.dart new file mode 100644 index 00000000000..5af272253a7 --- /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 00000000000..a6be0370eb7 --- /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 9c96dc1e2be..0d56f26b787 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 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 f1() async { } Stream 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 f2() async* { } Iterable 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 9e33f0c2fcc..feaee6363ef 100644 --- a/tests/language_2/sync_generator2_test.dart +++ b/tests/language_2/sync_generator2_test.dart @@ -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