Version 2.12.0-259.0.dev
Merge commit 'ac520f984d8e1286250af5fa67630ef6e963fabc' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index eb075b1..3daa83f 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -354,8 +354,9 @@
},
{
"name": "js_runtime",
- "rootUri": "../sdk/lib/_internal/js_runtime",
- "packageUri": "lib/"
+ "rootUri": "../pkg/js_runtime",
+ "packageUri": "lib/",
+ "languageVersion": "2.12"
},
{
"name": "json_rpc_2",
diff --git a/.packages b/.packages
index d31bc9b..badd487 100644
--- a/.packages
+++ b/.packages
@@ -54,7 +54,7 @@
intl:third_party/pkg/intl/lib
js:pkg/js/lib
js_ast:pkg/js_ast/lib
-js_runtime:sdk/lib/_internal/js_runtime/lib
+js_runtime:pkg/js_runtime/lib
json_rpc_2:third_party/pkg/json_rpc_2/lib
kernel:pkg/kernel/lib
linter:third_party/pkg/linter/lib
diff --git a/DEPS b/DEPS
index 2c8fd54..00cb7f7 100644
--- a/DEPS
+++ b/DEPS
@@ -106,7 +106,7 @@
"fixnum_rev": "16d3890c6dc82ca629659da1934e412292508bba",
"file_rev": "0e09370f581ab6388d46fda4cdab66638c0171a1",
"glob_rev": "7c0ef8d4fa086f6b185c4dd724b700e7d7ad8f79",
- "html_rev": "137be8db5d5b7f00530fca1591292849ce6779c9",
+ "html_rev": "7f31979303f916f2aabb9e2091950798abdd9ca1",
"http_io_rev": "2fa188caf7937e313026557713f7feffedd4978b",
"http_multi_server_rev" : "e8c8be7f15b4fb50757ff5bf29766721fbe24fe4",
"http_parser_rev": "5dd4d16693242049dfb43b5efa429fedbf932e98",
diff --git a/pkg/analysis_server/lib/src/computer/computer_highlights.dart b/pkg/analysis_server/lib/src/computer/computer_highlights.dart
index 8b4b43a..717c136 100644
--- a/pkg/analysis_server/lib/src/computer/computer_highlights.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_highlights.dart
@@ -14,6 +14,7 @@
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/source/source_range.dart';
import 'package:analyzer/src/dart/ast/extensions.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart' hide Element;
@@ -109,9 +110,6 @@
if (_addIdentifierRegion_function(node)) {
return;
}
- if (_addIdentifierRegion_functionTypeAlias(node)) {
- return;
- }
if (_addIdentifierRegion_importPrefix(node)) {
return;
}
@@ -127,6 +125,9 @@
if (_addIdentifierRegion_parameter(node)) {
return;
}
+ if (_addIdentifierRegion_typeAlias(node)) {
+ return;
+ }
if (_addIdentifierRegion_typeParameter(node)) {
return;
}
@@ -268,14 +269,6 @@
return _addRegion_node(node, type);
}
- bool _addIdentifierRegion_functionTypeAlias(SimpleIdentifier node) {
- var element = node.writeOrReadElement;
- if (element is! FunctionTypeAliasElement) {
- return false;
- }
- return _addRegion_node(node, HighlightRegionType.FUNCTION_TYPE_ALIAS);
- }
-
bool _addIdentifierRegion_getterSetterDeclaration(SimpleIdentifier node) {
// should be declaration
var parent = node.parent;
@@ -385,6 +378,17 @@
return _addRegion_node(node, type, semanticTokenModifiers: modifiers);
}
+ bool _addIdentifierRegion_typeAlias(SimpleIdentifier node) {
+ var element = node.writeOrReadElement;
+ if (element is TypeAliasElement) {
+ var type = element.aliasedType is FunctionType
+ ? HighlightRegionType.FUNCTION_TYPE_ALIAS
+ : HighlightRegionType.TYPE_ALIAS;
+ return _addRegion_node(node, type);
+ }
+ return false;
+ }
+
bool _addIdentifierRegion_typeParameter(SimpleIdentifier node) {
var element = node.writeOrReadElement;
if (element is! TypeParameterElement) {
@@ -743,13 +747,14 @@
@override
void visitGenericFunctionType(GenericFunctionType node) {
computer._addRegion_token(
- node.functionKeyword, HighlightRegionType.KEYWORD);
+ node.functionKeyword, HighlightRegionType.BUILT_IN);
super.visitGenericFunctionType(node);
}
@override
void visitGenericTypeAlias(GenericTypeAlias node) {
- computer._addRegion_token(node.typedefKeyword, HighlightRegionType.KEYWORD);
+ computer._addRegion_token(
+ node.typedefKeyword, HighlightRegionType.BUILT_IN);
super.visitGenericTypeAlias(node);
}
diff --git a/pkg/analysis_server/test/analysis/notification_highlights2_test.dart b/pkg/analysis_server/test/analysis/notification_highlights2_test.dart
index e276893..3ac8da4 100644
--- a/pkg/analysis_server/test/analysis/notification_highlights2_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_highlights2_test.dart
@@ -22,7 +22,7 @@
@reflectiveTest
class AnalysisNotificationHighlightsTest extends HighlightsTestSupport
- with WithNullSafetyServerAnalysisMixin {
+ with WithNonFunctionTypeAliasesMixin {
Future<void> test_ANNOTATION_hasArguments() async {
addTestFile('''
class AAA {
@@ -186,6 +186,18 @@
assertNoRegion(HighlightRegionType.BUILT_IN, 'factory = 42');
}
+ Future<void> test_BUILT_IN_Function() async {
+ addTestFile('''
+typedef F = void Function();
+
+void f(void Function() a, Function b) {}
+''');
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'Function();');
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'Function() a');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'Function b');
+ }
+
Future<void> test_BUILT_IN_get() async {
addTestFile('''
get aaa => 1;
@@ -380,11 +392,15 @@
Future<void> test_BUILT_IN_typedef() async {
addTestFile('''
typedef A();
+typedef B = void Function();
+typedef C = List<int>;
main() {
var typedef = 42;
}''');
await prepareHighlights();
assertHasRegion(HighlightRegionType.BUILT_IN, 'typedef A();');
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'typedef B =');
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'typedef C =');
assertNoRegion(HighlightRegionType.BUILT_IN, 'typedef = 42');
}
@@ -583,13 +599,15 @@
Future<void> test_FUNCTION_TYPE_ALIAS() async {
addTestFile('''
-typedef FFF(p);
-main(FFF fff) {
-}
+typedef A();
+typedef B = void Function();
+void f(A a, B b) {}
''');
await prepareHighlights();
- assertHasRegion(HighlightRegionType.FUNCTION_TYPE_ALIAS, 'FFF(p)');
- assertHasRegion(HighlightRegionType.FUNCTION_TYPE_ALIAS, 'FFF fff)');
+ assertHasRegion(HighlightRegionType.FUNCTION_TYPE_ALIAS, 'A();');
+ assertHasRegion(HighlightRegionType.FUNCTION_TYPE_ALIAS, 'A a');
+ assertHasRegion(HighlightRegionType.FUNCTION_TYPE_ALIAS, 'B = ');
+ assertHasRegion(HighlightRegionType.FUNCTION_TYPE_ALIAS, 'B b');
}
Future<void> test_GETTER() async {
@@ -1111,6 +1129,26 @@
assertHasRegion(HighlightRegionType.TOP_LEVEL_SETTER_REFERENCE, 'V2 = 3');
}
+ Future<void> test_TYPE_ALIAS_dynamicType() async {
+ addTestFile('''
+typedef A = dynamic;
+void f(A a) {}
+''');
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.TYPE_ALIAS, 'A =');
+ assertHasRegion(HighlightRegionType.TYPE_ALIAS, 'A a');
+ }
+
+ Future<void> test_TYPE_ALIAS_interfaceType() async {
+ addTestFile('''
+typedef A = List<int>;
+void f(A a) {}
+''');
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.TYPE_ALIAS, 'A =');
+ assertHasRegion(HighlightRegionType.TYPE_ALIAS, 'A a');
+ }
+
Future<void> test_TYPE_NAME_DYNAMIC() async {
addTestFile('''
dynamic main() {
diff --git a/pkg/analysis_server/test/analysis_abstract.dart b/pkg/analysis_server/test/analysis_abstract.dart
index adb4cc3..5614cd3 100644
--- a/pkg/analysis_server/test/analysis_abstract.dart
+++ b/pkg/analysis_server/test/analysis_abstract.dart
@@ -228,7 +228,19 @@
}
}
-mixin WithNullSafetyServerAnalysisMixin on AbstractAnalysisTest {
+mixin WithNonFunctionTypeAliasesMixin on AbstractAnalysisTest {
+ @override
+ void createProject({Map<String, String> packageRoots}) {
+ addAnalysisOptionsFile('''
+analyzer:
+ enable-experiment:
+ - nonfunction-type-aliases
+''');
+ super.createProject(packageRoots: packageRoots);
+ }
+}
+
+mixin WithNullSafetyMixin on AbstractAnalysisTest {
@override
void createProject({Map<String, String> packageRoots}) {
addAnalysisOptionsFile('''
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 6130688..2bee3dc 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -559,6 +559,8 @@
HintCode.PACKAGE_IMPORT_CONTAINS_DOT_DOT,
HintCode.RECEIVER_OF_TYPE_NEVER,
HintCode.RETURN_OF_DO_NOT_STORE,
+ HintCode.RETURN_OF_INVALID_TYPE_FROM_CATCH_ERROR,
+ HintCode.RETURN_TYPE_INVALID_FOR_CATCH_ERROR,
HintCode.SDK_VERSION_AS_EXPRESSION_IN_CONST_CONTEXT,
HintCode.SDK_VERSION_ASYNC_EXPORTED_FROM_CORE,
HintCode.SDK_VERSION_BOOL_OPERATOR_IN_CONST_CONTEXT,
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index 3671aa9..c427645 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -1746,6 +1746,27 @@
correction: "Annotate '{1}' with 'doNotStore'.");
/**
+ * Parameters:
+ * 0: the return type as declared in the return statement
+ * 1: the expected return type as defined by the type of the Future
+ */
+ static const HintCode RETURN_OF_INVALID_TYPE_FROM_CATCH_ERROR = HintCode(
+ 'RETURN_OF_INVALID_TYPE_FROM_CATCH_ERROR',
+ "A value of type '{0}' can't be returned by the 'onError' handler because "
+ "it must be assignable to '{1}'.",
+ );
+
+ /**
+ * Parameters:
+ * 0: the return type of the function
+ * 1: the expected return type as defined by the type of the Future
+ */
+ static const HintCode RETURN_TYPE_INVALID_FOR_CATCH_ERROR = HintCode(
+ 'RETURN_TYPE_INVALID_FOR_CATCH_ERROR',
+ "The return type '{0}' isn't assignable to '{1}', as required by "
+ "'Future.catchError'.");
+
+ /**
* No parameters.
*/
// #### Description
diff --git a/pkg/analyzer/lib/src/dart/resolver/type_name_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/type_name_resolver.dart
index fc07690..38e717a 100644
--- a/pkg/analyzer/lib/src/dart/resolver/type_name_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/type_name_resolver.dart
@@ -144,12 +144,7 @@
NullabilitySuffix _getNullability(TypeName node) {
if (isNonNullableByDefault) {
if (node.question != null) {
- if (identical(node, classHierarchy_typeName)) {
- _reportInvalidNullableType(node);
- return NullabilitySuffix.none;
- } else {
- return NullabilitySuffix.question;
- }
+ return NullabilitySuffix.question;
} else {
return NullabilitySuffix.none;
}
@@ -275,33 +270,6 @@
}
}
- /// Given a [typeName] that has a question mark, report an error and return
- /// `true` if it appears in a location where a nullable type is not allowed.
- void _reportInvalidNullableType(TypeName typeName) {
- AstNode parent = typeName.parent;
- if (parent is ExtendsClause || parent is ClassTypeAlias) {
- errorReporter.reportErrorForNode(
- CompileTimeErrorCode.NULLABLE_TYPE_IN_EXTENDS_CLAUSE,
- typeName,
- );
- } else if (parent is ImplementsClause) {
- errorReporter.reportErrorForNode(
- CompileTimeErrorCode.NULLABLE_TYPE_IN_IMPLEMENTS_CLAUSE,
- typeName,
- );
- } else if (parent is OnClause) {
- errorReporter.reportErrorForNode(
- CompileTimeErrorCode.NULLABLE_TYPE_IN_ON_CLAUSE,
- typeName,
- );
- } else if (parent is WithClause) {
- errorReporter.reportErrorForNode(
- CompileTimeErrorCode.NULLABLE_TYPE_IN_WITH_CLAUSE,
- typeName,
- );
- }
- }
-
void _resolveToElement(TypeName node, Element element) {
if (element == null) {
node.type = dynamicType;
@@ -316,7 +284,9 @@
return;
}
- node.type = _instantiateElement(node, element);
+ var type = _instantiateElement(node, element);
+ type = _verifyNullability(node, type);
+ node.type = type;
}
/// We parse `foo.bar` as `prefix.Name` with the expectation that `prefix`
@@ -367,6 +337,42 @@
}
}
+ /// If the [node] appears in a location where a nullable type is not allowed,
+ /// but the [type] is nullable (because the question mark was specified,
+ /// or the type alias is nullable), report an error, and return the
+ /// corresponding non-nullable type.
+ DartType _verifyNullability(TypeName node, DartType type) {
+ if (identical(node, classHierarchy_typeName)) {
+ if (type.nullabilitySuffix == NullabilitySuffix.question) {
+ var parent = node.parent;
+ if (parent is ExtendsClause || parent is ClassTypeAlias) {
+ errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.NULLABLE_TYPE_IN_EXTENDS_CLAUSE,
+ node,
+ );
+ } else if (parent is ImplementsClause) {
+ errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.NULLABLE_TYPE_IN_IMPLEMENTS_CLAUSE,
+ node,
+ );
+ } else if (parent is OnClause) {
+ errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.NULLABLE_TYPE_IN_ON_CLAUSE,
+ node,
+ );
+ } else if (parent is WithClause) {
+ errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.NULLABLE_TYPE_IN_WITH_CLAUSE,
+ node,
+ );
+ }
+ return (type as TypeImpl).withNullability(NullabilitySuffix.none);
+ }
+ }
+
+ return type;
+ }
+
DartType _verifyTypeAliasForContext(
TypeName node,
TypeAliasElement element,
diff --git a/pkg/analyzer/lib/src/error/best_practices_verifier.dart b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
index 4085b7a..cbb6ab5 100644
--- a/pkg/analyzer/lib/src/error/best_practices_verifier.dart
+++ b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
@@ -23,6 +23,7 @@
import 'package:analyzer/src/dart/resolver/body_inference_context.dart';
import 'package:analyzer/src/dart/resolver/exit_detector.dart';
import 'package:analyzer/src/dart/resolver/scope.dart';
+import 'package:analyzer/src/error/catch_error_verifier.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/error/deprecated_member_use_verifier.dart';
import 'package:analyzer/src/error/must_call_super_verifier.dart';
@@ -72,6 +73,8 @@
final MustCallSuperVerifier _mustCallSuperVerifier;
+ final CatchErrorVerifier _catchErrorVerifier;
+
/// The [WorkspacePackage] in which [_currentLibrary] is declared.
final WorkspacePackage _workspacePackage;
@@ -109,6 +112,8 @@
_deprecatedVerifier =
DeprecatedMemberUseVerifier(workspacePackage, _errorReporter),
_mustCallSuperVerifier = MustCallSuperVerifier(_errorReporter),
+ _catchErrorVerifier =
+ CatchErrorVerifier(_errorReporter, typeProvider, typeSystem),
_workspacePackage = workspacePackage {
_deprecatedVerifier.pushInDeprecatedValue(_currentLibrary.hasDeprecated);
_inDoNotStoreMember = _currentLibrary.hasDoNotStore;
@@ -588,6 +593,7 @@
void visitMethodInvocation(MethodInvocation node) {
_deprecatedVerifier.methodInvocation(node);
_checkForNullAwareHints(node, node.operator);
+ _catchErrorVerifier.verifyMethodInvocation(node);
super.visitMethodInvocation(node);
}
diff --git a/pkg/analyzer/lib/src/error/catch_error_verifier.dart b/pkg/analyzer/lib/src/error/catch_error_verifier.dart
new file mode 100644
index 0000000..a9fa26d
--- /dev/null
+++ b/pkg/analyzer/lib/src/error/catch_error_verifier.dart
@@ -0,0 +1,103 @@
+// Copyright (c) 2021, 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 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/dart/element/type_provider.dart';
+import 'package:analyzer/dart/element/type_system.dart';
+import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/error/return_type_verifier.dart';
+import 'package:analyzer/src/generated/error_verifier.dart';
+
+/// Reports on invalid functions passed to [Future.catchError].
+class CatchErrorVerifier {
+ final ErrorReporter _errorReporter;
+
+ final TypeProvider _typeProvider;
+
+ final TypeSystem _typeSystem;
+
+ final ReturnTypeVerifier _returnTypeVerifier;
+
+ CatchErrorVerifier(this._errorReporter, this._typeProvider, this._typeSystem)
+ : _returnTypeVerifier = ReturnTypeVerifier(
+ typeProvider: _typeProvider,
+ typeSystem: _typeSystem,
+ errorReporter: _errorReporter,
+ );
+ void verifyMethodInvocation(MethodInvocation node) {
+ // TODO(https://github.com/dart-lang/sdk/issues/35825): Verify the
+ // parameters of a function passed to `Future.catchError` as well.
+ var target = node.realTarget;
+ if (target == null) {
+ return;
+ }
+ var methodName = node.methodName;
+ if (!(methodName.name == 'catchError' &&
+ target.staticType.isDartAsyncFuture)) {
+ return;
+ }
+ if (node.argumentList.arguments.isEmpty) {
+ return;
+ }
+ var callback = node.argumentList.arguments.first;
+ if (callback is NamedExpression) {
+ // This implies that no positional arguments are passed.
+ return;
+ }
+ var targetType = target.staticType as InterfaceType;
+ var targetFutureType = targetType.typeArguments.first;
+ var expectedReturnType = _typeProvider.futureOrType2(targetFutureType);
+ if (callback is FunctionExpression) {
+ var catchErrorOnErrorExecutable = EnclosingExecutableContext(
+ callback.declaredElement,
+ isAsynchronous: true,
+ catchErrorOnErrorReturnType: expectedReturnType);
+ var returnStatementVerifier =
+ _ReturnStatementVerifier(_returnTypeVerifier);
+ _returnTypeVerifier.enclosingExecutable = catchErrorOnErrorExecutable;
+ callback.body.accept(returnStatementVerifier);
+ } else {
+ var callbackType = callback.staticType;
+ if (callbackType is FunctionType) {
+ _checkReturnType(expectedReturnType, callbackType.returnType, callback);
+ }
+ }
+ }
+
+ void _checkReturnType(
+ DartType expectedType, DartType functionReturnType, Expression callback) {
+ if (!_typeSystem.isAssignableTo(functionReturnType, expectedType)) {
+ _errorReporter.reportErrorForNode(
+ HintCode.RETURN_TYPE_INVALID_FOR_CATCH_ERROR,
+ callback,
+ [functionReturnType, expectedType],
+ );
+ }
+ }
+}
+
+/// Visits a function body, looking for return statements.
+class _ReturnStatementVerifier extends RecursiveAstVisitor<void> {
+ final ReturnTypeVerifier _returnTypeVerifier;
+ _ReturnStatementVerifier(this._returnTypeVerifier);
+ @override
+ void visitExpressionFunctionBody(ExpressionFunctionBody node) {
+ _returnTypeVerifier.verifyExpressionFunctionBody(node);
+ super.visitExpressionFunctionBody(node);
+ }
+
+ @override
+ void visitFunctionExpression(FunctionExpression node) {
+ // Do not visit within [node]. We have no interest in return statements
+ // within.
+ }
+ @override
+ void visitReturnStatement(ReturnStatement node) {
+ _returnTypeVerifier.verifyReturnStatement(node);
+ super.visitReturnStatement(node);
+ }
+}
diff --git a/pkg/analyzer/lib/src/error/return_type_verifier.dart b/pkg/analyzer/lib/src/error/return_type_verifier.dart
index af65202..ce9f2eb 100644
--- a/pkg/analyzer/lib/src/error/return_type_verifier.dart
+++ b/pkg/analyzer/lib/src/error/return_type_verifier.dart
@@ -155,7 +155,13 @@
var S = expression.staticType;
void reportTypeError() {
- if (enclosingExecutable.isClosure) {
+ if (enclosingExecutable.catchErrorOnErrorReturnType != null) {
+ _errorReporter.reportErrorForNode(
+ HintCode.RETURN_OF_INVALID_TYPE_FROM_CATCH_ERROR,
+ expression,
+ [S, T],
+ );
+ } else if (enclosingExecutable.isClosure) {
_errorReporter.reportErrorForNode(
CompileTimeErrorCode.RETURN_OF_INVALID_TYPE_FROM_CLOSURE,
expression,
@@ -256,7 +262,13 @@
var S = expression.staticType;
void reportTypeError() {
- if (enclosingExecutable.isClosure) {
+ if (enclosingExecutable.catchErrorOnErrorReturnType != null) {
+ _errorReporter.reportErrorForNode(
+ HintCode.RETURN_OF_INVALID_TYPE_FROM_CATCH_ERROR,
+ expression,
+ [S, T],
+ );
+ } else if (enclosingExecutable.isClosure) {
_errorReporter.reportErrorForNode(
CompileTimeErrorCode.RETURN_OF_INVALID_TYPE_FROM_CLOSURE,
expression,
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index e54f009..b275202 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -53,6 +53,12 @@
final bool inFactoryConstructor;
final bool inStaticMethod;
+ /// If this [EnclosingExecutableContext] is the first argument in a method
+ /// invocation of [Future.catchError], returns the return type expected for
+ /// `Future<T>.catchError`'s `onError` parameter, which is `FutureOr<T>`,
+ /// otherwise `null`.
+ final InterfaceType catchErrorOnErrorReturnType;
+
/// The return statements that have a value.
final List<ReturnStatement> _returnsWith = [];
@@ -63,8 +69,10 @@
/// for the kind of the function body, e.g. not `Future` for `async`.
bool hasLegalReturnType = true;
- EnclosingExecutableContext(this.element)
- : isAsynchronous = element != null && element.isAsynchronous,
+ EnclosingExecutableContext(this.element,
+ {bool isAsynchronous, this.catchErrorOnErrorReturnType})
+ : isAsynchronous =
+ isAsynchronous ?? (element != null && element.isAsynchronous),
isConstConstructor = element is ConstructorElement && element.isConst,
isGenerativeConstructor =
element is ConstructorElement && !element.isFactory,
@@ -104,7 +112,7 @@
bool get isSynchronous => !isAsynchronous;
- DartType get returnType => element.returnType;
+ DartType get returnType => catchErrorOnErrorReturnType ?? element.returnType;
static bool _inFactoryConstructor(ExecutableElement element) {
if (element is ConstructorElement) {
@@ -747,12 +755,12 @@
void visitFunctionExpression(FunctionExpression node) {
_isInLateLocalVariable.add(false);
- if (node.parent is! FunctionDeclaration) {
+ if (node.parent is FunctionDeclaration) {
+ super.visitFunctionExpression(node);
+ } else {
_withEnclosingExecutable(node.declaredElement, () {
super.visitFunctionExpression(node);
});
- } else {
- super.visitFunctionExpression(node);
}
_isInLateLocalVariable.removeLast();
diff --git a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
index 88fe551..36be56b 100644
--- a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
+++ b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
@@ -43,6 +43,8 @@
throw 0;
}
+ Future<T> catchError(Function onError, {bool test(Object error)});
+
Future<R> then<R>(FutureOr<R> onValue(T value));
Future<T> whenComplete(action());
diff --git a/pkg/analyzer/test/src/diagnostics/nullable_type_in_extends_clause_test.dart b/pkg/analyzer/test/src/diagnostics/nullable_type_in_extends_clause_test.dart
index ccdffe5..aab024e 100644
--- a/pkg/analyzer/test/src/diagnostics/nullable_type_in_extends_clause_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/nullable_type_in_extends_clause_test.dart
@@ -15,7 +15,7 @@
@reflectiveTest
class NullableTypeInExtendsClauseTest extends PubPackageResolutionTest
- with WithNullSafetyMixin {
+ with WithNonFunctionTypeAliasesMixin {
test_class_nonNullable() async {
await assertNoErrorsInCode('''
class A {}
@@ -32,6 +32,26 @@
]);
}
+ test_class_nullable_alias() async {
+ await assertErrorsInCode('''
+class A {}
+typedef B = A;
+class C extends B? {}
+''', [
+ error(CompileTimeErrorCode.NULLABLE_TYPE_IN_EXTENDS_CLAUSE, 42, 2),
+ ]);
+ }
+
+ test_class_nullable_alias2() async {
+ await assertErrorsInCode('''
+class A {}
+typedef B = A?;
+class C extends B {}
+''', [
+ error(CompileTimeErrorCode.NULLABLE_TYPE_IN_EXTENDS_CLAUSE, 43, 1),
+ ]);
+ }
+
test_classAlias_withClass_nonNullable() async {
await assertNoErrorsInCode('''
class A {}
@@ -50,6 +70,28 @@
]);
}
+ test_classAlias_withClass_nullable_alias() async {
+ await assertErrorsInCode('''
+class A {}
+class B {}
+typedef C = A;
+class D = C? with B;
+''', [
+ error(CompileTimeErrorCode.NULLABLE_TYPE_IN_EXTENDS_CLAUSE, 47, 2),
+ ]);
+ }
+
+ test_classAlias_withClass_nullable_alias2() async {
+ await assertErrorsInCode('''
+class A {}
+class B {}
+typedef C = A?;
+class D = C with B;
+''', [
+ error(CompileTimeErrorCode.NULLABLE_TYPE_IN_EXTENDS_CLAUSE, 48, 1),
+ ]);
+ }
+
test_classAlias_withMixin_nonNullable() async {
await assertNoErrorsInCode('''
class A {}
@@ -67,4 +109,26 @@
error(CompileTimeErrorCode.NULLABLE_TYPE_IN_EXTENDS_CLAUSE, 32, 2),
]);
}
+
+ test_classAlias_withMixin_nullable_alias() async {
+ await assertErrorsInCode('''
+class A {}
+mixin B {}
+typedef C = A;
+class D = C? with B;
+''', [
+ error(CompileTimeErrorCode.NULLABLE_TYPE_IN_EXTENDS_CLAUSE, 47, 2),
+ ]);
+ }
+
+ test_classAlias_withMixin_nullable_alias2() async {
+ await assertErrorsInCode('''
+class A {}
+mixin B {}
+typedef C = A?;
+class D = C with B;
+''', [
+ error(CompileTimeErrorCode.NULLABLE_TYPE_IN_EXTENDS_CLAUSE, 48, 1),
+ ]);
+ }
}
diff --git a/pkg/analyzer/test/src/diagnostics/nullable_type_in_implements_clause_test.dart b/pkg/analyzer/test/src/diagnostics/nullable_type_in_implements_clause_test.dart
index 9e9d5a8..2238940 100644
--- a/pkg/analyzer/test/src/diagnostics/nullable_type_in_implements_clause_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/nullable_type_in_implements_clause_test.dart
@@ -15,7 +15,7 @@
@reflectiveTest
class NullableTypeInImplementsClauseTest extends PubPackageResolutionTest
- with WithNullSafetyMixin {
+ with WithNonFunctionTypeAliasesMixin {
test_class_nonNullable() async {
await assertNoErrorsInCode('''
class A {}
@@ -32,6 +32,26 @@
]);
}
+ test_class_nullable_alias() async {
+ await assertErrorsInCode('''
+class A {}
+typedef B = A;
+class C implements B? {}
+''', [
+ error(CompileTimeErrorCode.NULLABLE_TYPE_IN_IMPLEMENTS_CLAUSE, 45, 2),
+ ]);
+ }
+
+ test_class_nullable_alias2() async {
+ await assertErrorsInCode('''
+class A {}
+typedef B = A?;
+class C implements B {}
+''', [
+ error(CompileTimeErrorCode.NULLABLE_TYPE_IN_IMPLEMENTS_CLAUSE, 46, 1),
+ ]);
+ }
+
test_mixin_nonNullable() async {
await assertNoErrorsInCode('''
class A {}
@@ -47,4 +67,24 @@
error(CompileTimeErrorCode.NULLABLE_TYPE_IN_IMPLEMENTS_CLAUSE, 30, 2),
]);
}
+
+ test_mixin_nullable_alias() async {
+ await assertErrorsInCode('''
+class A {}
+typedef B = A;
+mixin C implements B? {}
+''', [
+ error(CompileTimeErrorCode.NULLABLE_TYPE_IN_IMPLEMENTS_CLAUSE, 45, 2),
+ ]);
+ }
+
+ test_mixin_nullable_alias2() async {
+ await assertErrorsInCode('''
+class A {}
+typedef B = A?;
+mixin C implements B {}
+''', [
+ error(CompileTimeErrorCode.NULLABLE_TYPE_IN_IMPLEMENTS_CLAUSE, 46, 1),
+ ]);
+ }
}
diff --git a/pkg/analyzer/test/src/diagnostics/nullable_type_in_on_clause_test.dart b/pkg/analyzer/test/src/diagnostics/nullable_type_in_on_clause_test.dart
index 98a243c..d987fba 100644
--- a/pkg/analyzer/test/src/diagnostics/nullable_type_in_on_clause_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/nullable_type_in_on_clause_test.dart
@@ -15,7 +15,7 @@
@reflectiveTest
class NullableTypeInOnClauseTest extends PubPackageResolutionTest
- with WithNullSafetyMixin {
+ with WithNonFunctionTypeAliasesMixin {
test_nonNullable() async {
await assertNoErrorsInCode('''
class A {}
@@ -31,4 +31,24 @@
error(CompileTimeErrorCode.NULLABLE_TYPE_IN_ON_CLAUSE, 22, 2),
]);
}
+
+ test_nullable_alias() async {
+ await assertErrorsInCode('''
+class A {}
+typedef B = A;
+mixin C on B? {}
+''', [
+ error(CompileTimeErrorCode.NULLABLE_TYPE_IN_ON_CLAUSE, 37, 2),
+ ]);
+ }
+
+ test_nullable_alias2() async {
+ await assertErrorsInCode('''
+class A {}
+typedef B = A?;
+mixin C on B {}
+''', [
+ error(CompileTimeErrorCode.NULLABLE_TYPE_IN_ON_CLAUSE, 38, 1),
+ ]);
+ }
}
diff --git a/pkg/analyzer/test/src/diagnostics/nullable_type_in_with_clause_test.dart b/pkg/analyzer/test/src/diagnostics/nullable_type_in_with_clause_test.dart
index ba235ef..ea7d118 100644
--- a/pkg/analyzer/test/src/diagnostics/nullable_type_in_with_clause_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/nullable_type_in_with_clause_test.dart
@@ -15,7 +15,7 @@
@reflectiveTest
class NullableTypeInWithClauseTest extends PubPackageResolutionTest
- with WithNullSafetyMixin {
+ with WithNonFunctionTypeAliasesMixin {
test_class_nonNullable() async {
await assertNoErrorsInCode('''
class A {}
@@ -32,6 +32,26 @@
]);
}
+ test_class_nullable_alias() async {
+ await assertErrorsInCode('''
+class A {}
+typedef B = A;
+class C with B? {}
+''', [
+ error(CompileTimeErrorCode.NULLABLE_TYPE_IN_WITH_CLAUSE, 39, 2),
+ ]);
+ }
+
+ test_class_nullable_alias2() async {
+ await assertErrorsInCode('''
+class A {}
+typedef B = A?;
+class C with B {}
+''', [
+ error(CompileTimeErrorCode.NULLABLE_TYPE_IN_WITH_CLAUSE, 40, 1),
+ ]);
+ }
+
test_classAlias_withClass_nonNullable() async {
await assertNoErrorsInCode('''
class A {}
@@ -50,6 +70,28 @@
]);
}
+ test_classAlias_withClass_nullable_alias() async {
+ await assertErrorsInCode('''
+class A {}
+class B {}
+typedef C = B;
+class D = A with C?;
+''', [
+ error(CompileTimeErrorCode.NULLABLE_TYPE_IN_WITH_CLAUSE, 54, 2),
+ ]);
+ }
+
+ test_classAlias_withClass_nullable_alias2() async {
+ await assertErrorsInCode('''
+class A {}
+class B {}
+typedef C = B?;
+class D = A with C;
+''', [
+ error(CompileTimeErrorCode.NULLABLE_TYPE_IN_WITH_CLAUSE, 55, 1),
+ ]);
+ }
+
test_classAlias_withMixin_nonNullable() async {
await assertNoErrorsInCode('''
class A {}
@@ -67,4 +109,26 @@
error(CompileTimeErrorCode.NULLABLE_TYPE_IN_WITH_CLAUSE, 39, 2),
]);
}
+
+ test_classAlias_withMixin_nullable_alias() async {
+ await assertErrorsInCode('''
+class A {}
+mixin B {}
+typedef C = B;
+class D = A with C?;
+''', [
+ error(CompileTimeErrorCode.NULLABLE_TYPE_IN_WITH_CLAUSE, 54, 2),
+ ]);
+ }
+
+ test_classAlias_withMixin_nullable_alias2() async {
+ await assertErrorsInCode('''
+class A {}
+mixin B {}
+typedef C = B?;
+class D = A with C;
+''', [
+ error(CompileTimeErrorCode.NULLABLE_TYPE_IN_WITH_CLAUSE, 55, 1),
+ ]);
+ }
}
diff --git a/pkg/analyzer/test/src/diagnostics/return_of_invalid_type_from_catch_error_test.dart b/pkg/analyzer/test/src/diagnostics/return_of_invalid_type_from_catch_error_test.dart
new file mode 100644
index 0000000..51b7617
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/return_of_invalid_type_from_catch_error_test.dart
@@ -0,0 +1,200 @@
+// Copyright (c) 2021, 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 'package:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(ReturnOfInvalidTypeForCatchErrorTest);
+ defineReflectiveTests(ReturnOfInvalidTypeForCatchErrorWithNullSafetyTest);
+ });
+}
+
+@reflectiveTest
+class ReturnOfInvalidTypeForCatchErrorTest extends PubPackageResolutionTest {
+ test_async_okReturnType() async {
+ await assertNoErrorsInCode('''
+void f(Future<int> future) {
+ future.catchError((e, st) async => 0);
+}
+''');
+ }
+
+ test_blockFunctionBody_async_emptyReturn_nonVoid() async {
+ await assertErrorsInCode('''
+void f(Future<int> future) {
+ future.catchError((e, st) async {
+ return;
+ });
+}
+''', [
+ error(CompileTimeErrorCode.RETURN_WITHOUT_VALUE, 69, 6),
+ ]);
+ }
+
+ test_blockFunctionBody_async_emptyReturn_void() async {
+ await assertNoErrorsInCode('''
+void f(Future<void> future) {
+ future.catchError((e, st) async {
+ return;
+ });
+}
+''');
+ }
+
+ test_blockFunctionBody_emptyReturn_dynamic() async {
+ await assertNoErrorsInCode('''
+void f(Future<dynamic> future) {
+ future.catchError((e, st) {
+ return;
+ });
+}
+''');
+ }
+
+ test_blockFunctionBody_emptyReturn_nonVoid() async {
+ await assertErrorsInCode('''
+void f(Future<int> future) {
+ future.catchError((e, st) {
+ return;
+ });
+}
+''', [
+ error(CompileTimeErrorCode.RETURN_WITHOUT_VALUE, 63, 6),
+ ]);
+ }
+
+ test_blockFunctionBody_emptyReturn_void() async {
+ await assertNoErrorsInCode('''
+void f(Future<void> future) {
+ future.catchError((e, st) {
+ return;
+ });
+}
+''');
+ }
+
+ test_blockFunctionBody_invalidReturnType() async {
+ await assertErrorsInCode('''
+void f(Future<int> future) {
+ future.catchError((e, st) {
+ if (1 == 2) {
+ return 7;
+ } else {
+ return 0.5;
+ }
+ });
+}
+''', [
+ error(HintCode.RETURN_OF_INVALID_TYPE_FROM_CATCH_ERROR, 119, 3),
+ ]);
+ }
+
+ test_blockFunctionBody_withLocalFunction_expression_okReturnType() async {
+ await assertNoErrorsInCode('''
+void f(Future<int> future) {
+ future.catchError((e, st) {
+ double g() => 0.5;
+ if (g() == 0.5) return 0;
+ return 1;
+ });
+}
+''');
+ }
+
+ test_blockFunctionBody_withLocalFunction_okReturnType() async {
+ await assertNoErrorsInCode('''
+void f(Future<int> future) {
+ future.catchError((e, st) {
+ double g() {
+ return 0.5;
+ }
+ if (g() == 0.5) return 0;
+ return 1;
+ });
+}
+''');
+ }
+
+ test_expressionFunctionBody_invalidReturnType() async {
+ await assertErrorsInCode('''
+void f(Future<int> future) {
+ future.catchError((e, st) => 'c');
+}
+''', [
+ error(HintCode.RETURN_OF_INVALID_TYPE_FROM_CATCH_ERROR, 60, 3),
+ ]);
+ }
+
+ test_Null_okReturnType() async {
+ await assertNoErrorsInCode('''
+void f(Future<Null> future) {
+ future.catchError((e, st) => null);
+}
+''');
+ }
+
+ test_okReturnType() async {
+ await assertNoErrorsInCode('''
+void f(Future<int> future) {
+ future.catchError((e, st) => 0);
+}
+''');
+ }
+
+ test_void_okReturnType() async {
+ await assertNoErrorsInCode('''
+void f(Future<void> future) {
+ future.catchError((e, st) => 0);
+}
+''');
+ }
+
+ test_voidReturnType() async {
+ await assertErrorsInCode('''
+void f(Future<int> future, void Function() g) {
+ future.catchError((e, st) => g());
+}
+''', [
+ error(HintCode.RETURN_OF_INVALID_TYPE_FROM_CATCH_ERROR, 79, 3),
+ ]);
+ }
+}
+
+@reflectiveTest
+class ReturnOfInvalidTypeForCatchErrorWithNullSafetyTest
+ extends ReturnOfInvalidTypeForCatchErrorTest with WithNullSafetyMixin {
+ test_nullableType_emptyBody() async {
+ await assertNoErrorsInCode('''
+void f(Future<int?> future) {
+ future.catchError((e, st) {});
+}
+''');
+ }
+
+ test_nullableType_emptyReturn() async {
+ await assertErrorsInCode('''
+void f(Future<int?> future) {
+ future.catchError((e, st) {
+ return;
+ });
+}
+''', [
+ error(CompileTimeErrorCode.RETURN_WITHOUT_VALUE, 64, 6),
+ ]);
+ }
+
+ test_nullableType_invalidReturnType() async {
+ await assertErrorsInCode('''
+void f(Future<int?> future) {
+ future.catchError((e, st) => '');
+}
+''', [
+ error(HintCode.RETURN_OF_INVALID_TYPE_FROM_CATCH_ERROR, 61, 2),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/return_type_invalid_for_catch_error_test.dart b/pkg/analyzer/test/src/diagnostics/return_type_invalid_for_catch_error_test.dart
new file mode 100644
index 0000000..ddd5ed2
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/return_type_invalid_for_catch_error_test.dart
@@ -0,0 +1,100 @@
+// Copyright (c) 2021, 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 'package:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(ReturnTypeInvalidForCatchErrorTest);
+ defineReflectiveTests(ReturnTypeInvalidForCatchErrorWithNullSafetyTest);
+ });
+}
+
+@reflectiveTest
+class ReturnTypeInvalidForCatchErrorTest extends PubPackageResolutionTest {
+ test_dynamic_returnTypeIsUnrelatedFuture() async {
+ await assertNoErrorsInCode('''
+void f(
+ Future<dynamic> future, Future<String> Function(dynamic, StackTrace) cb) {
+ future.catchError(cb);
+}
+''');
+ }
+
+ test_dynamic_unrelatedReturnType() async {
+ await assertNoErrorsInCode('''
+void f(Future<dynamic> future, String Function(dynamic, StackTrace) cb) {
+ future.catchError(cb);
+}
+''');
+ }
+
+ test_invalidReturnType() async {
+ await assertErrorsInCode('''
+void f(Future<int> future, String Function(dynamic, StackTrace) cb) {
+ future.catchError(cb);
+}
+''', [
+ error(HintCode.RETURN_TYPE_INVALID_FOR_CATCH_ERROR, 90, 2),
+ ]);
+ }
+
+ test_returnTypeIsFuture() async {
+ await assertNoErrorsInCode('''
+void f(Future<int> future, Future<int> Function(dynamic, StackTrace) cb) {
+ future.catchError(cb);
+}
+''');
+ }
+
+ test_returnTypeIsFutureOr() async {
+ await assertNoErrorsInCode('''
+import 'dart:async';
+void f(Future<int> future, FutureOr<int> Function(dynamic, StackTrace) cb) {
+ future.catchError(cb);
+}
+''');
+ }
+
+ test_sameReturnType() async {
+ await assertNoErrorsInCode('''
+void f(Future<int> future, int Function(dynamic, StackTrace) cb) {
+ future.catchError(cb);
+}
+''');
+ }
+
+ test_void_returnTypeIsUnrelatedFuture() async {
+ await assertNoErrorsInCode('''
+void f(Future<void> future, Future<String> Function(dynamic, StackTrace) cb) {
+ future.catchError(cb);
+}
+''');
+ }
+
+ test_void_unrelatedReturnType() async {
+ await assertNoErrorsInCode('''
+void f(Future<void> future, String Function(dynamic, StackTrace) cb) {
+ future.catchError(cb);
+}
+''');
+ }
+}
+
+@reflectiveTest
+class ReturnTypeInvalidForCatchErrorWithNullSafetyTest
+ extends ReturnTypeInvalidForCatchErrorTest with WithNullSafetyMixin {
+ test_nullableReturnType() async {
+ await assertErrorsInCode('''
+void f(Future<int> future, String? Function(dynamic, StackTrace) cb) {
+ future.catchError(cb);
+}
+''', [
+ error(HintCode.RETURN_TYPE_INVALID_FOR_CATCH_ERROR, 91, 2),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/return_without_value_test.dart b/pkg/analyzer/test/src/diagnostics/return_without_value_test.dart
index 6d33a0d..9a31d66 100644
--- a/pkg/analyzer/test/src/diagnostics/return_without_value_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/return_without_value_test.dart
@@ -36,6 +36,16 @@
]);
}
+ test_catchError_futureOfVoid() async {
+ await assertNoErrorsInCode('''
+void f(Future<void> future) {
+ future.catchError((e) {
+ return;
+ });
+}
+''');
+ }
+
test_factoryConstructor() async {
await assertErrorsInCode('''
class A {
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 58ee594..6d808e0 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -536,7 +536,11 @@
as return_in_generative_constructor;
import 'return_in_generator_test.dart' as return_in_generator;
import 'return_of_do_not_store_test.dart' as return_of_do_not_store;
+import 'return_of_invalid_type_from_catch_error_test.dart'
+ as return_of_invalid_type_from_catch_error;
import 'return_of_invalid_type_test.dart' as return_of_invalid_type;
+import 'return_type_invalid_for_catch_error_test.dart'
+ as return_type_invalid_for_catch_error;
import 'return_without_value_test.dart' as return_without_value;
import 'sdk_version_as_expression_in_const_context_test.dart'
as sdk_version_as_expression_in_const_context;
@@ -1012,7 +1016,9 @@
return_in_generative_constructor.main();
return_in_generator.main();
return_of_do_not_store.main();
+ return_of_invalid_type_from_catch_error.main();
return_of_invalid_type.main();
+ return_type_invalid_for_catch_error.main();
return_without_value.main();
set_element_from_deferred_library.main();
sdk_version_as_expression_in_const_context.main();
diff --git a/pkg/analyzer_plugin/doc/tutorial/assists.md b/pkg/analyzer_plugin/doc/tutorial/assists.md
index dd38b78..2be0e4d 100644
--- a/pkg/analyzer_plugin/doc/tutorial/assists.md
+++ b/pkg/analyzer_plugin/doc/tutorial/assists.md
@@ -102,7 +102,7 @@
// ...
@override
- List<AssistContributor> getAssistContributors(AnalysisDriver driver) {
+ List<AssistContributor> getAssistContributors(String path) {
return <AssistContributor>[MyAssistContributor()];
}
}
diff --git a/pkg/analyzer_plugin/doc/tutorial/fixes.md b/pkg/analyzer_plugin/doc/tutorial/fixes.md
index efe2537..b77e517 100644
--- a/pkg/analyzer_plugin/doc/tutorial/fixes.md
+++ b/pkg/analyzer_plugin/doc/tutorial/fixes.md
@@ -117,8 +117,7 @@
// ...
@override
- List<FixContributor> getFixContributors(
- AnalysisDriverGeneric driver) {
+ List<FixContributor> getFixContributors(String path) {
return <FixContributor>[MyFixContributor()];
}
}
diff --git a/pkg/analyzer_plugin/doc/tutorial/package_structure.md b/pkg/analyzer_plugin/doc/tutorial/package_structure.md
index 1963892..c2443ec 100644
--- a/pkg/analyzer_plugin/doc/tutorial/package_structure.md
+++ b/pkg/analyzer_plugin/doc/tutorial/package_structure.md
@@ -56,7 +56,7 @@
If a listed host package can be found (via the `.packages` file associated with
the target package), then the tool looks in the host package for the folder
-`<host_package>/tools/analysis_plugin`. If that directory exists and contains a
+`<host_package>/tools/analyzer_plugin`. If that directory exists and contains a
valid bootstrap package, then the bootstrap package is run as a plugin.
## Bootstrap Package Structure
diff --git a/pkg/analyzer_plugin/lib/plugin/plugin.dart b/pkg/analyzer_plugin/lib/plugin/plugin.dart
index 9759368..cdf8829 100644
--- a/pkg/analyzer_plugin/lib/plugin/plugin.dart
+++ b/pkg/analyzer_plugin/lib/plugin/plugin.dart
@@ -95,7 +95,8 @@
/// Return the SDK manager used to manage SDKs.
DartSdkManager get sdkManager => _sdkManager;
- /// Return the version number of this plugin, encoded as a string.
+ /// Return the version number of the plugin spec required by this plugin,
+ /// encoded as a string.
String get version;
/// Handle the fact that the file with the given [path] has been modified.
diff --git a/pkg/compiler/pubspec.yaml b/pkg/compiler/pubspec.yaml
index 8a61bf9..0f826c1 100644
--- a/pkg/compiler/pubspec.yaml
+++ b/pkg/compiler/pubspec.yaml
@@ -26,7 +26,7 @@
js_ast:
path: ../js_ast
js_runtime:
- path: ../../sdk/lib/_internal/js_runtime
+ path: ../js_runtime
dev_dependencies:
# Published packages - repo version ensured via dependency_overrides
diff --git a/pkg/dartdev/lib/src/commands/compile.dart b/pkg/dartdev/lib/src/commands/compile.dart
index f3f6e63..021db07 100644
--- a/pkg/dartdev/lib/src/commands/compile.dart
+++ b/pkg/dartdev/lib/src/commands/compile.dart
@@ -157,7 +157,16 @@
commonOptions['outputFile'].flag,
help: commonOptions['outputFile'].help,
abbr: commonOptions['outputFile'].abbr,
+ )
+ ..addOption(
+ commonOptions['verbosity'].flag,
+ help: commonOptions['verbosity'].help,
+ abbr: commonOptions['verbosity'].abbr,
+ defaultsTo: commonOptions['verbosity'].defaultsTo,
+ allowed: commonOptions['verbosity'].allowed,
+ allowedHelp: commonOptions['verbosity'].allowedHelp,
);
+
addExperimentalFlags(argParser, verbose);
}
@@ -189,6 +198,10 @@
List<String> args = [];
args.add('--snapshot-kind=$formatName');
args.add('--snapshot=${path.canonicalize(outputFile)}');
+
+ String verbosity = argResults[commonOptions['verbosity'].flag];
+ args.add('--verbosity=$verbosity');
+
if (enabledExperiments.isNotEmpty) {
args.add("--enable-experiment=${enabledExperiments.join(',')}");
}
diff --git a/pkg/dartdev/lib/src/commands/run.dart b/pkg/dartdev/lib/src/commands/run.dart
index 80ca891..2825b49 100644
--- a/pkg/dartdev/lib/src/commands/run.dart
+++ b/pkg/dartdev/lib/src/commands/run.dart
@@ -8,6 +8,8 @@
import 'dart:io';
import 'package:args/args.dart';
+import 'package:front_end/src/api_prototype/compiler_options.dart'
+ show Verbosity;
import 'package:path/path.dart';
import 'package:pub/pub.dart';
@@ -91,6 +93,13 @@
..addFlag(
'enable-asserts',
help: 'Enable assert statements.',
+ )
+ ..addOption(
+ 'verbosity',
+ help: 'Sets the verbosity level of the compilation.',
+ defaultsTo: Verbosity.defaultValue,
+ allowed: Verbosity.allowedValues,
+ allowedHelp: Verbosity.allowedValuesHelp,
);
if (verbose) {
diff --git a/pkg/dartdev/test/commands/compile_test.dart b/pkg/dartdev/test/commands/compile_test.dart
index 5aaf14c..61ebc76 100644
--- a/pkg/dartdev/test/commands/compile_test.dart
+++ b/pkg/dartdev/test/commands/compile_test.dart
@@ -236,7 +236,7 @@
reason: 'File not found: $outFile');
});
- test('Compile exe with warning', () {
+ test('Compile exe with warnings', () {
final p = project(mainSrc: '''
void main() {
int i = 0;
@@ -334,6 +334,33 @@
reason: 'File not found: $outFile');
});
+ test('Compile exe without warnings', () {
+ final p = project(mainSrc: '''
+void main() {
+ int i = 0;
+ i?.isEven;
+}
+''');
+ final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
+ final outFile = path.canonicalize(path.join(p.dirPath, 'myexe'));
+
+ var result = p.runSync(
+ [
+ 'compile',
+ 'exe',
+ '--verbosity=error',
+ '-o',
+ outFile,
+ inFile,
+ ],
+ );
+
+ expect(result.stdout,
+ predicate((o) => !'$o'.contains(soundNullSafetyMessage)));
+ expect(result.stderr, isEmpty);
+ expect(result.exitCode, 0);
+ });
+
test('Compile JS with sound null safety', () {
final p = project(mainSrc: '''void main() {}''');
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
@@ -405,6 +432,33 @@
reason: 'File not found: $outFile');
});
+ test('Compile JS without warnings', () {
+ final p = project(mainSrc: '''
+void main() {
+ int i = 0;
+ i?.isEven;
+}
+''');
+ final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
+ final outFile = path.canonicalize(path.join(p.dirPath, 'myjs'));
+
+ var result = p.runSync(
+ [
+ 'compile',
+ 'js',
+ '--verbosity=error',
+ '-o',
+ outFile,
+ inFile,
+ ],
+ );
+
+ expect(result.stdout,
+ predicate((o) => !'$o'.contains(soundNullSafetyMessage)));
+ expect(result.stderr, isEmpty);
+ expect(result.exitCode, 0);
+ });
+
test('Compile AOT snapshot with sound null safety', () {
final p = project(mainSrc: '''void main() {}''');
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
@@ -476,6 +530,61 @@
reason: 'File not found: $outFile');
});
+ test('Compile AOT snapshot without warnings', () {
+ final p = project(mainSrc: '''
+void main() {
+ int i = 0;
+ i?.isEven;
+}
+''');
+ final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
+ final outFile = path.canonicalize(path.join(p.dirPath, 'myaot'));
+
+ var result = p.runSync(
+ [
+ 'compile',
+ 'aot-snapshot',
+ '--verbosity=error',
+ '-o',
+ outFile,
+ inFile,
+ ],
+ );
+
+ expect(result.stdout,
+ predicate((o) => !'$o'.contains(soundNullSafetyMessage)));
+ expect(result.stderr, isEmpty);
+ expect(result.exitCode, 0);
+ });
+
+ test('Compile AOT snapshot with warnings', () {
+ final p = project(mainSrc: '''
+void main() {
+ int i = 0;
+ i?.isEven;
+}
+''');
+ final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
+ final outFile = path.canonicalize(path.join(p.dirPath, 'myaot'));
+
+ var result = p.runSync(
+ [
+ 'compile',
+ 'aot-snapshot',
+ '--verbosity=warning',
+ '-o',
+ outFile,
+ inFile,
+ ],
+ );
+
+ expect(result.stdout,
+ predicate((o) => !'$o'.contains(soundNullSafetyMessage)));
+ expect(result.stdout, contains('Warning: '));
+ expect(result.stderr, isEmpty);
+ expect(result.exitCode, 0);
+ });
+
test('Compile kernel with sound null safety', () {
final p = project(mainSrc: '''void main() {}''');
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
@@ -523,6 +632,82 @@
reason: 'File not found: $outFile');
});
+ test('Compile kernel without info', () {
+ final p = project(mainSrc: '''void main() {}''');
+ final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
+ final outFile = path.canonicalize(path.join(p.dirPath, 'mydill'));
+
+ var result = p.runSync(
+ [
+ 'compile',
+ 'kernel',
+ '--verbosity=warning',
+ '-o',
+ outFile,
+ inFile,
+ ],
+ );
+
+ expect(result.stdout,
+ predicate((o) => !'$o'.contains(soundNullSafetyMessage)));
+ expect(result.stderr, isEmpty);
+ expect(result.exitCode, 0);
+ expect(File(outFile).existsSync(), true,
+ reason: 'File not found: $outFile');
+ });
+
+ test('Compile kernel without warning', () {
+ final p = project(mainSrc: '''
+void main() {
+ int i;
+ i?.isEven;
+}''');
+ final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
+ final outFile = path.canonicalize(path.join(p.dirPath, 'mydill'));
+
+ var result = p.runSync(
+ [
+ 'compile',
+ 'kernel',
+ '--verbosity=error',
+ '-o',
+ outFile,
+ inFile,
+ ],
+ );
+
+ expect(result.stdout,
+ predicate((o) => !'$o'.contains(soundNullSafetyMessage)));
+ expect(result.stderr, contains('must be assigned before it can be used'));
+ expect(result.exitCode, 254);
+ });
+
+ test('Compile kernel with warnings', () {
+ final p = project(mainSrc: '''
+void main() {
+ int i = 0;
+ i?.isEven;
+}''');
+ final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
+ final outFile = path.canonicalize(path.join(p.dirPath, 'mydill'));
+
+ var result = p.runSync(
+ [
+ 'compile',
+ 'kernel',
+ '--verbosity=warning',
+ '-o',
+ outFile,
+ inFile,
+ ],
+ );
+
+ expect(result.stdout,
+ predicate((o) => !'$o'.contains(soundNullSafetyMessage)));
+ expect(result.stderr, contains('Warning:'));
+ expect(result.exitCode, 0);
+ });
+
test('Compile JIT snapshot with sound null safety', () {
final p = project(mainSrc: '''void main() {}''');
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
@@ -569,4 +754,80 @@
expect(File(outFile).existsSync(), true,
reason: 'File not found: $outFile');
});
+
+ test('Compile JIT snapshot without info', () {
+ final p = project(mainSrc: '''void main() {}''');
+ final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
+ final outFile = path.canonicalize(path.join(p.dirPath, 'myjit'));
+
+ var result = p.runSync(
+ [
+ 'compile',
+ 'jit-snapshot',
+ '--verbosity=warning',
+ '-o',
+ outFile,
+ inFile,
+ ],
+ );
+
+ expect(result.stdout,
+ predicate((o) => !'$o'.contains(soundNullSafetyMessage)));
+ expect(result.stderr, isEmpty);
+ expect(result.exitCode, 0);
+ expect(File(outFile).existsSync(), true,
+ reason: 'File not found: $outFile');
+ });
+
+ test('Compile JIT snapshot without warnings', () {
+ final p = project(mainSrc: '''
+void main() {
+ int i;
+ i?.isEven;
+}''');
+ final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
+ final outFile = path.canonicalize(path.join(p.dirPath, 'myjit'));
+
+ var result = p.runSync(
+ [
+ 'compile',
+ 'jit-snapshot',
+ '--verbosity=error',
+ '-o',
+ outFile,
+ inFile,
+ ],
+ );
+
+ expect(result.stdout,
+ predicate((o) => !'$o'.contains(soundNullSafetyMessage)));
+ expect(result.stderr, contains('must be assigned before it can be used'));
+ expect(result.exitCode, 254);
+ });
+
+ test('Compile JIT snapshot with warnings', () {
+ final p = project(mainSrc: '''
+void main() {
+ int i = 0;
+ i?.isEven;
+}''');
+ final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
+ final outFile = path.canonicalize(path.join(p.dirPath, 'myjit'));
+
+ var result = p.runSync(
+ [
+ 'compile',
+ 'jit-snapshot',
+ '--verbosity=warning',
+ '-o',
+ outFile,
+ inFile,
+ ],
+ );
+
+ expect(result.stdout,
+ predicate((o) => !'$o'.contains(soundNullSafetyMessage)));
+ expect(result.stderr, contains('Warning:'));
+ expect(result.exitCode, 0);
+ });
}
diff --git a/pkg/dartdev/test/commands/run_test.dart b/pkg/dartdev/test/commands/run_test.dart
index 59bffba..12c07d3 100644
--- a/pkg/dartdev/test/commands/run_test.dart
+++ b/pkg/dartdev/test/commands/run_test.dart
@@ -9,6 +9,8 @@
import '../utils.dart';
+const String soundNullSafetyMessage = 'Info: Compiling with sound null safety';
+
void main() {
group('run', run, timeout: longTimeout);
}
@@ -279,4 +281,21 @@
expect(result.stderr, isEmpty);
expect(result.exitCode, 0);
});
+
+ test('without verbose CFE info', () {
+ final p = project(mainSrc: '''void main() {}''');
+
+ var result = p.runSync(
+ [
+ 'run',
+ '--verbosity=warning',
+ p.relativeFilePath,
+ ],
+ );
+
+ expect(result.stdout,
+ predicate((o) => !'$o'.contains(soundNullSafetyMessage)));
+ expect(result.stderr, isEmpty);
+ expect(result.exitCode, 0);
+ });
}
diff --git a/pkg/js_runtime/README.md b/pkg/js_runtime/README.md
new file mode 100644
index 0000000..5f60952
--- /dev/null
+++ b/pkg/js_runtime/README.md
@@ -0,0 +1,9 @@
+# Package `js_runtime`:
+
+This package contains code that is shared between the dart2js compiler and the
+dart2js runtime libraries.
+
+*Important*: all code under the `lib/shared/` must be kept in sync with the
+runtime at all times (in `sdk/lib/_internal/js_runtime/lib/shared`). The
+`test/in_sync_test.dart` test verifies this.
+
diff --git a/pkg/js_runtime/lib/shared/async_await_error_codes.dart b/pkg/js_runtime/lib/shared/async_await_error_codes.dart
new file mode 100644
index 0000000..f87406b
--- /dev/null
+++ b/pkg/js_runtime/lib/shared/async_await_error_codes.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2015, 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.
+
+/// Contains error codes that transformed async/async* functions use to
+/// communicate with js_helper functions.
+
+const int SUCCESS = 0;
+const int ERROR = 1;
+const int STREAM_WAS_CANCELED = 2;
diff --git a/pkg/js_runtime/lib/shared/embedded_names.dart b/pkg/js_runtime/lib/shared/embedded_names.dart
new file mode 100644
index 0000000..e80fb6a
--- /dev/null
+++ b/pkg/js_runtime/lib/shared/embedded_names.dart
@@ -0,0 +1,281 @@
+// Copyright (c) 2014, 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.
+
+/// Contains the names of globals that are embedded into the output by the
+/// compiler.
+///
+/// Variables embedded this way should be access with `JS_EMBEDDED_GLOBAL` from
+/// the `_foreign_helper` library.
+///
+/// This library is shared between the compiler and the runtime system.
+library dart2js._embedded_names;
+
+/// The name of the property that is used to find the native superclass of
+/// an extended class.
+///
+/// Every class that extends a native class has this property set on its
+/// native class.
+const NATIVE_SUPERCLASS_TAG_NAME = r"$nativeSuperclassTag";
+
+/// The name of the static-function property name.
+///
+/// This property is set for all tear-offs of static functions, and provides
+/// the static function's unique (potentially minified) name.
+const STATIC_FUNCTION_NAME_PROPERTY_NAME = r'$static_name';
+
+/// The name of a property on the constructor function of Dart Object
+/// and interceptor types, used for caching Rti types.
+const CONSTRUCTOR_RTI_CACHE_PROPERTY_NAME = r'$ccache';
+
+/// The name of the embedded global for metadata.
+///
+/// Use [JsBuiltin.getMetadata] instead of directly accessing this embedded
+/// global.
+const METADATA = 'metadata';
+
+/// A list of types used in the program e.g. for reflection or encoding of
+/// function types.
+///
+/// Use [JsBuiltin.getType] instead of directly accessing this embedded global.
+const TYPES = 'types';
+
+/// Returns a function that maps a name of a class to its type.
+///
+/// This embedded global is used by the runtime when computing the internal
+/// runtime-type-information (rti) object.
+const GET_TYPE_FROM_NAME = 'getTypeFromName';
+
+/// A JS map from mangled global names to their unmangled names.
+///
+/// If the program does not use reflection, this embedded global may be empty
+/// (but not null or undefined).
+const MANGLED_GLOBAL_NAMES = 'mangledGlobalNames';
+
+/// A JS map from mangled instance names to their unmangled names.
+///
+/// This embedded global is mainly used for reflection, but is also used to
+/// map const-symbols (`const Symbol('x')`) to the mangled instance names.
+///
+/// This embedded global may be empty (but not null or undefined).
+const MANGLED_NAMES = 'mangledNames';
+
+/// A JS map from dispatch tags (usually constructor names of DOM classes) to
+/// interceptor class. This map is used to find the correct interceptor for
+/// native classes.
+///
+/// This embedded global is used for natives.
+const INTERCEPTORS_BY_TAG = 'interceptorsByTag';
+
+/// A JS map from dispatch tags (usually constructor names of DOM classes) to
+/// booleans. Every tag entry of [INTERCEPTORS_BY_TAG] has a corresponding
+/// entry in the leaf-tags map.
+///
+/// A tag-entry is true, when a class can be treated as leaf class in the
+/// hierarchy. That is, even though it might have subclasses, all subclasses
+/// have the same code for the used methods.
+///
+/// This embedded global is used for natives.
+const LEAF_TAGS = 'leafTags';
+
+/// A JS function that returns the isolate tag for a given name.
+///
+/// This function uses the [ISOLATE_TAG] (below) to construct a name that is
+/// unique per isolate.
+///
+/// This embedded global is used for natives.
+// TODO(floitsch): should we rename this variable to avoid confusion with
+// [INTERCEPTORS_BY_TAG] and [LEAF_TAGS].
+const GET_ISOLATE_TAG = 'getIsolateTag';
+
+/// A string that is different for each running isolate.
+///
+/// When this embedded global is initialized a global variable is used to
+/// ensure that no other running isolate uses the same isolate-tag string.
+///
+/// This embedded global is used for natives.
+// TODO(floitsch): should we rename this variable to avoid confusion with
+// [INTERCEPTORS_BY_TAG] and [LEAF_TAGS].
+const ISOLATE_TAG = 'isolateTag';
+
+/// An embedded global that contains the property used to store type information
+/// on JavaScript Array instances. This is a Symbol (except for IE11, where is
+/// is a String).
+const ARRAY_RTI_PROPERTY = 'arrayRti';
+
+/// This embedded global (a function) returns the isolate-specific dispatch-tag
+/// that is used to accelerate interceptor calls.
+const DISPATCH_PROPERTY_NAME = "dispatchPropertyName";
+
+/// An embedded global that maps a [Type] to the [Interceptor] and constructors
+/// for that type.
+///
+/// More documentation can be found in the interceptors library (close to its
+/// use).
+const TYPE_TO_INTERCEPTOR_MAP = "typeToInterceptorMap";
+
+/// The current script's URI when the program was loaded.
+///
+/// This embedded global is set at startup, just before invoking `main`.
+const CURRENT_SCRIPT = 'currentScript';
+
+/// Contains a map from load-ids to lists of part indexes.
+///
+/// To load the deferred library that is represented by the load-id, the runtime
+/// must load all associated URIs (named in DEFERRED_PART_URIS) and initialize
+/// all the loaded hunks (DEFERRED_PART_HASHES).
+///
+/// This embedded global is only used for deferred loading.
+const DEFERRED_LIBRARY_PARTS = 'deferredLibraryParts';
+
+/// Contains a list of URIs (Strings), indexed by part.
+///
+/// The lists in the DEFERRED_LIBRARY_PARTS map contain indexes into this list.
+///
+/// This embedded global is only used for deferred loading.
+const DEFERRED_PART_URIS = 'deferredPartUris';
+
+/// Contains a list of hashes, indexed by part.
+///
+/// The lists in the DEFERRED_LIBRARY_PARTS map contain indexes into this list.
+///
+/// The hashes are associated with the URIs of the load-ids (see
+/// [DEFERRED_PART_URIS]). They are SHA1 (or similar) hashes of the code that
+/// must be loaded. By using cryptographic hashes we can (1) handle loading in
+/// the same web page the parts from multiple Dart applications (2) avoid
+/// loading similar code multiple times.
+///
+/// This embedded global is only used for deferred loading.
+const DEFERRED_PART_HASHES = 'deferredPartHashes';
+
+/// Initialize a loaded hunk.
+///
+/// Once a hunk (the code from a deferred URI) has been loaded it must be
+/// initialized. Calling this function with the corresponding hash (see
+/// [DEFERRED_LIBRARY_HASHES]) initializes the code.
+///
+/// This embedded global is only used for deferred loading.
+const INITIALIZE_LOADED_HUNK = 'initializeLoadedHunk';
+
+/// Returns, whether a hunk (identified by its hash) has already been loaded.
+///
+/// This embedded global is only used for deferred loading.
+const IS_HUNK_LOADED = 'isHunkLoaded';
+
+/// Returns, whether a hunk (identified by its hash) has already been
+/// initialized.
+///
+/// This embedded global is only used for deferred loading.
+const IS_HUNK_INITIALIZED = 'isHunkInitialized';
+
+/// A set (implemented as map to booleans) of hunks (identified by hashes) that
+/// have already been initialized.
+///
+/// This embedded global is only used for deferred loading.
+///
+/// This global is an emitter-internal embedded global, and not used by the
+/// runtime. The constant remains in this file to make sure that other embedded
+/// globals don't clash with it.
+const DEFERRED_INITIALIZED = 'deferredInitialized';
+
+/// A 'Universe' object used by 'dart:_rti'.
+///
+/// This embedded global is used for --experiment-new-rti.
+const RTI_UNIVERSE = 'typeUniverse';
+
+/// Names that are supported by [JS_GET_NAME].
+// TODO(herhut): Make entries lower case (as in fields) and find a better name.
+enum JsGetName {
+ GETTER_PREFIX,
+ SETTER_PREFIX,
+ CALL_PREFIX,
+ CALL_PREFIX0,
+ CALL_PREFIX1,
+ CALL_PREFIX2,
+ CALL_PREFIX3,
+ CALL_PREFIX4,
+ CALL_PREFIX5,
+ CALL_CATCH_ALL,
+ REQUIRED_PARAMETER_PROPERTY,
+ DEFAULT_VALUES_PROPERTY,
+ CALL_NAME_PROPERTY,
+ DEFERRED_ACTION_PROPERTY,
+
+ /// Prefix used for generated type argument substitutions on classes.
+ OPERATOR_AS_PREFIX,
+
+ /// Prefix used for generated type test property on classes.
+ OPERATOR_IS_PREFIX,
+
+ /// Name used for generated function types on classes and methods.
+ SIGNATURE_NAME,
+
+ /// Name of JavaScript property used to store runtime-type information on
+ /// instances of parameterized classes.
+ RTI_NAME,
+
+ /// String representation of the type of the Future class.
+ FUTURE_CLASS_TYPE_NAME,
+
+ /// Field name used for determining if an object or its interceptor has
+ /// JavaScript indexing behavior.
+ IS_INDEXABLE_FIELD_NAME,
+
+ /// String representation of the type of the null class.
+ NULL_CLASS_TYPE_NAME,
+
+ /// String representation of the type of the object class.
+ OBJECT_CLASS_TYPE_NAME,
+
+ /// Property name for Rti._as field.
+ RTI_FIELD_AS,
+
+ /// Property name for Rti._is field.
+ RTI_FIELD_IS,
+}
+
+enum JsBuiltin {
+ /// Returns the JavaScript constructor function for Dart's Object class.
+ /// This can be used for type tests, as in
+ ///
+ /// var constructor = JS_BUILTIN('', JsBuiltin.dartObjectConstructor);
+ /// if (JS('bool', '# instanceof #', obj, constructor))
+ /// ...
+ dartObjectConstructor,
+
+ /// Returns the JavaScript constructor function for the runtime's Closure
+ /// class, the base class of all closure objects. This can be used for type
+ /// tests, as in
+ ///
+ /// var constructor = JS_BUILTIN('', JsBuiltin.dartClosureConstructor);
+ /// if (JS('bool', '# instanceof #', obj, constructor))
+ /// ...
+ dartClosureConstructor,
+
+ /// Returns true if the given type is a type argument of a js-interop class
+ /// or a supertype of a js-interop class.
+ ///
+ /// JS_BUILTIN('bool', JsBuiltin.isJsInteropTypeArgument, o)
+ isJsInteropTypeArgument,
+
+ /// Returns the metadata of the given [index].
+ ///
+ /// JS_BUILTIN('returns:var;effects:none;depends:none',
+ /// JsBuiltin.getMetadata, index);
+ getMetadata,
+
+ /// Returns the type of the given [index].
+ ///
+ /// JS_BUILTIN('returns:var;effects:none;depends:none',
+ /// JsBuiltin.getType, index);
+ getType,
+}
+
+/// Names of fields of the Rti Universe object.
+class RtiUniverseFieldNames {
+ static String evalCache = 'eC';
+ static String typeRules = 'tR';
+ static String erasedTypes = 'eT';
+ static String typeParameterVariances = 'tPV';
+ static String sharedEmptyArray = 'sEA';
+}
diff --git a/pkg/js_runtime/lib/shared/recipe_syntax.dart b/pkg/js_runtime/lib/shared/recipe_syntax.dart
new file mode 100644
index 0000000..c183861
--- /dev/null
+++ b/pkg/js_runtime/lib/shared/recipe_syntax.dart
@@ -0,0 +1,237 @@
+// 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.
+
+/// Constants and predicates used for encoding and decoding type recipes.
+///
+/// This library is shared between the compiler and the runtime system.
+library dart2js._recipe_syntax;
+
+abstract class Recipe {
+ Recipe._();
+
+ // Operators.
+
+ static const int separator = _comma;
+ static const String separatorString = _commaString;
+
+ static const int toType = _semicolon;
+ static const String toTypeString = _semicolonString;
+
+ static const int pushErased = _hash;
+ static const String pushErasedString = _hashString;
+ static const int pushDynamic = _at;
+ static const String pushDynamicString = _atString;
+ static const int pushVoid = _tilde;
+ static const String pushVoidString = _tildeString;
+
+ static const int wrapStar = _asterisk;
+ static const String wrapStarString = _asteriskString;
+ static const int wrapQuestion = _question;
+ static const String wrapQuestionString = _questionString;
+ static const int wrapFutureOr = _slash;
+ static const String wrapFutureOrString = _slashString;
+
+ static const int startTypeArguments = _lessThan;
+ static const String startTypeArgumentsString = _lessThanString;
+ static const int endTypeArguments = _greaterThan;
+ static const String endTypeArgumentsString = _greaterThanString;
+
+ static const int startFunctionArguments = _leftParen;
+ static const String startFunctionArgumentsString = _leftParenString;
+ static const int endFunctionArguments = _rightParen;
+ static const String endFunctionArgumentsString = _rightParenString;
+ static const int startOptionalGroup = _leftBracket;
+ static const String startOptionalGroupString = _leftBracketString;
+ static const int endOptionalGroup = _rightBracket;
+ static const String endOptionalGroupString = _rightBracketString;
+ static const int startNamedGroup = _leftBrace;
+ static const String startNamedGroupString = _leftBraceString;
+ static const int endNamedGroup = _rightBrace;
+ static const String endNamedGroupString = _rightBraceString;
+ static const int nameSeparator = _colon;
+ static const String nameSeparatorString = _colonString;
+ static const int requiredNameSeparator = _exclamation;
+ static const String requiredNameSeparatorString = _exclamationString;
+
+ static const int genericFunctionTypeParameterIndex = _circumflex;
+ static const String genericFunctionTypeParameterIndexString =
+ _circumflexString;
+
+ static const int extensionOp = _ampersand;
+ static const String extensionOpString = _ampersandString;
+ static const int pushNeverExtension = 0;
+ static const String pushNeverExtensionString = '$pushNeverExtension';
+ static const int pushAnyExtension = 1;
+ static const String pushAnyExtensionString = '$pushAnyExtension';
+
+ // Number and name components.
+
+ static bool isDigit(int code) => code >= _digit0 && code <= _digit9;
+ static int digitValue(int code) => code - _digit0;
+
+ static bool isIdentifierStart(int ch) =>
+ (((ch | 32) - _lowercaseA) & 0xffff) < 26 ||
+ (ch == _underscore) ||
+ (ch == _dollar);
+
+ static const int period = _period;
+
+ // Private names.
+
+ static const int _formfeed = 0x0C;
+ static const String _formfeedString = '\f';
+
+ static const int _space = 0x20;
+ static const String _spaceString = ' ';
+ static const int _exclamation = 0x21;
+ static const String _exclamationString = '!';
+ static const int _hash = 0x23;
+ static const String _hashString = '#';
+ static const int _dollar = 0x24;
+ static const String _dollarString = r'$';
+ static const int _percent = 0x25;
+ static const String _percentString = '%';
+ static const int _ampersand = 0x26;
+ static const String _ampersandString = '&';
+ static const int _apostrophe = 0x27;
+ static const String _apostropheString = "'";
+ static const int _leftParen = 0x28;
+ static const String _leftParenString = '(';
+ static const int _rightParen = 0x29;
+ static const String _rightParenString = ')';
+ static const int _asterisk = 0x2A;
+ static const String _asteriskString = '*';
+ static const int _plus = 0x2B;
+ static const String _plusString = '+';
+ static const int _comma = 0x2C;
+ static const String _commaString = ',';
+ static const int _minus = 0x2D;
+ static const String _minusString = '-';
+ static const int _period = 0x2E;
+ static const String _periodString = '.';
+ static const int _slash = 0x2F;
+ static const String _slashString = '/';
+
+ static const int _digit0 = 0x30;
+ static const int _digit9 = 0x39;
+
+ static const int _colon = 0x3A;
+ static const String _colonString = ':';
+ static const int _semicolon = 0x3B;
+ static const String _semicolonString = ';';
+ static const int _lessThan = 0x3C;
+ static const String _lessThanString = '<';
+ static const int _equals = 0x3D;
+ static const String _equalsString = '=';
+ static const int _greaterThan = 0x3E;
+ static const String _greaterThanString = '>';
+ static const int _question = 0x3F;
+ static const String _questionString = '?';
+ static const int _at = 0x40;
+ static const String _atString = '@';
+
+ static const int _uppercaseA = 0x41;
+ static const int _uppercaseZ = 0x5A;
+
+ static const int _leftBracket = 0x5B;
+ static const String _leftBracketString = '[';
+ static const int _backslash = 0x5C;
+ static const String _backslashString = r'\';
+ static const int _rightBracket = 0x5D;
+ static const String _rightBracketString = ']';
+ static const int _circumflex = 0x5E;
+ static const String _circumflexString = '^';
+ static const int _underscore = 0x5F;
+ static const String _underscoreString = '_';
+ static const int _backtick = 0x60;
+ static const String _backtickString = '`';
+
+ static const int _lowercaseA = 0x61;
+ static const int _lowercaseZ = 0x7A;
+
+ static const int _leftBrace = 0x7B;
+ static const String _leftBraceString = '{';
+ static const int _vertical = 0x7C;
+ static const String _verticalString = '|';
+ static const int _rightBrace = 0x7D;
+ static const String _rightBraceString = '}';
+ static const int _tilde = 0x7E;
+ static const String _tildeString = '~';
+
+ static void testEquivalence() {
+ void test(String label, int charCode, String str) {
+ if (String.fromCharCode(charCode) != str) {
+ throw StateError("$label: String.fromCharCode($charCode) != $str");
+ }
+ }
+
+ void testExtension(String label, int op, String str) {
+ if ('$op' != str) {
+ throw StateError("$label: $op.toString() != $str");
+ }
+ }
+
+ test("separator", separator, separatorString);
+ test("toType", toType, toTypeString);
+ test("pushErased", pushErased, pushErasedString);
+ test("pushDynamic", pushDynamic, pushDynamicString);
+ test("pushVoid", pushVoid, pushVoidString);
+ test("wrapStar", wrapStar, wrapStarString);
+ test("wrapQuestion", wrapQuestion, wrapQuestionString);
+ test("wrapFutureOr", wrapFutureOr, wrapFutureOrString);
+ test("startTypeArguments", startTypeArguments, startTypeArgumentsString);
+ test("endTypeArguments", endTypeArguments, endTypeArgumentsString);
+ test("startFunctionArguments", startFunctionArguments,
+ startFunctionArgumentsString);
+ test("endFunctionArguments", endFunctionArguments,
+ endFunctionArgumentsString);
+ test("startOptionalGroup", startOptionalGroup, startOptionalGroupString);
+ test("endOptionalGroup", endOptionalGroup, endOptionalGroupString);
+ test("startNamedGroup", startNamedGroup, startNamedGroupString);
+ test("endNamedGroup", endNamedGroup, endNamedGroupString);
+ test("nameSeparator", nameSeparator, nameSeparatorString);
+ test("requiredNameSeparator", requiredNameSeparator,
+ requiredNameSeparatorString);
+ test("genericFunctionTypeParameterIndex", genericFunctionTypeParameterIndex,
+ genericFunctionTypeParameterIndexString);
+ test("extensionOp", extensionOp, extensionOpString);
+ testExtension(
+ "pushNeverExtension", pushNeverExtension, pushNeverExtensionString);
+ testExtension("pushAnyExtension", pushAnyExtension, pushAnyExtensionString);
+
+ test("_formfeed", _formfeed, _formfeedString);
+ test("_space", _space, _spaceString);
+ test("_exclamation", _exclamation, _exclamationString);
+ test("_hash", _hash, _hashString);
+ test("_dollar", _dollar, _dollarString);
+ test("_percent", _percent, _percentString);
+ test("_ampersand", _ampersand, _ampersandString);
+ test("_apostrophe", _apostrophe, _apostropheString);
+ test("_leftParen", _leftParen, _leftParenString);
+ test("_rightParen", _rightParen, _rightParenString);
+ test("_asterisk", _asterisk, _asteriskString);
+ test("_plus", _plus, _plusString);
+ test("_comma", _comma, _commaString);
+ test("_minus", _minus, _minusString);
+ test("_period", _period, _periodString);
+ test("_slash", _slash, _slashString);
+ test("_colon", _colon, _colonString);
+ test("_semicolon", _semicolon, _semicolonString);
+ test("_lessThan", _lessThan, _lessThanString);
+ test("_equals", _equals, _equalsString);
+ test("_greaterThan", _greaterThan, _greaterThanString);
+ test("_question", _question, _questionString);
+ test("_at", _at, _atString);
+ test("_leftBracket", _leftBracket, _leftBracketString);
+ test("_backslash", _backslash, _backslashString);
+ test("_rightBracket", _rightBracket, _rightBracketString);
+ test("_circumflex", _circumflex, _circumflexString);
+ test("_underscore", _underscore, _underscoreString);
+ test("_backtick", _backtick, _backtickString);
+ test("_leftBrace", _leftBrace, _leftBraceString);
+ test("_vertical", _vertical, _verticalString);
+ test("_rightBrace", _rightBrace, _rightBraceString);
+ test("_tilde", _tilde, _tildeString);
+ }
+}
diff --git a/pkg/js_runtime/pubspec.yaml b/pkg/js_runtime/pubspec.yaml
new file mode 100644
index 0000000..e707d77
--- /dev/null
+++ b/pkg/js_runtime/pubspec.yaml
@@ -0,0 +1,12 @@
+name: js_runtime
+# This package is not intended for consumption on pub.dev. DO NOT publish.
+publish_to: none
+
+environment:
+ sdk: '>=2.12.0 <3.0.0'
+
+dev_dependencies:
+ expect:
+ path: ../expect
+ _fe_analyzer_shared:
+ path: ../_fe_analyzer_shared
diff --git a/pkg/js_runtime/test/in_sync_test.dart b/pkg/js_runtime/test/in_sync_test.dart
new file mode 100644
index 0000000..4dbef635
--- /dev/null
+++ b/pkg/js_runtime/test/in_sync_test.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2020, 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.
+
+// @dart = 2.9
+
+/// Test to verify that this package is in-sync with dart2js runtime libraries.
+import 'dart:io';
+
+import 'package:_fe_analyzer_shared/src/util/relativize.dart';
+import 'package:expect/expect.dart';
+
+void main(List<String> argv) {
+ var packageDir = Platform.script.resolve('../lib/shared/');
+ var sdkDir = Platform.script
+ .resolve('../../../sdk/lib/_internal/js_runtime/lib/shared/');
+ var rPackageDir =
+ relativizeUri(Directory.current.uri, packageDir, Platform.isWindows);
+ var rSdkDir =
+ relativizeUri(Directory.current.uri, sdkDir, Platform.isWindows);
+
+ for (var file in Directory.fromUri(sdkDir).listSync()) {
+ if (file is File) {
+ var filename = file.uri.pathSegments.last;
+ var packageFile = File.fromUri(packageDir.resolve(filename));
+ Expect.isTrue(
+ packageFile.existsSync(),
+ "$filename not in sync. Please update it by running:\n"
+ " cp $rSdkDir$filename $rPackageDir$filename");
+ var original = file.readAsBytesSync();
+ var copy = packageFile.readAsBytesSync();
+ Expect.listEquals(
+ original,
+ copy,
+ "$filename not in sync. Please update it by running:\n"
+ " cp $rSdkDir$filename $rPackageDir$filename");
+ }
+ }
+}
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 6b93319..da7fa09 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -173,6 +173,7 @@
dev_compiler/test/options/*: SkipByDesign
front_end/test/hot_reload_e2e_test: Skip
frontend_server/test/*: SkipByDesign # Only meant to run on vm
+js_runtime/test/*: SkipByDesign # Only meant to run on vm
vm/test/*: SkipByDesign # Only meant to run on vm
vm_service/test/*: SkipByDesign # Uses dart:io
vm_snapshot_analysis/test/*: SkipByDesign # Only meant to run on vm
diff --git a/pkg/vm/bin/kernel_service.dart b/pkg/vm/bin/kernel_service.dart
index 2a57c7b..a558085 100644
--- a/pkg/vm/bin/kernel_service.dart
+++ b/pkg/vm/bin/kernel_service.dart
@@ -89,7 +89,6 @@
CompilerOptions setupCompilerOptions(
FileSystem fileSystem,
Uri platformKernelPath,
- bool suppressWarnings,
bool enableAsserts,
int nullSafety,
List<String> experimentalFlags,
@@ -132,10 +131,10 @@
errors.addAll(message.plainTextFormatted);
break;
case Severity.warning:
- printToStdErr = !suppressWarnings;
+ printToStdErr = true;
break;
case Severity.info:
- printToStdOut = !suppressWarnings;
+ printToStdOut = true;
break;
case Severity.context:
case Severity.ignored:
@@ -157,7 +156,6 @@
final int isolateId;
final FileSystem fileSystem;
final Uri platformKernelPath;
- final bool suppressWarnings;
final bool enableAsserts;
final int nullSafety;
final List<String> experimentalFlags;
@@ -175,8 +173,7 @@
CompilerOptions options;
Compiler(this.isolateId, this.fileSystem, this.platformKernelPath,
- {this.suppressWarnings: false,
- this.enableAsserts: false,
+ {this.enableAsserts: false,
this.nullSafety: kNullSafetyOptionUnspecified,
this.experimentalFlags: null,
this.supportCodeCoverage: false,
@@ -201,7 +198,6 @@
options = setupCompilerOptions(
fileSystem,
platformKernelPath,
- suppressWarnings,
enableAsserts,
nullSafety,
experimentalFlags,
@@ -294,15 +290,13 @@
IncrementalCompilerWrapper(
int isolateId, FileSystem fileSystem, Uri platformKernelPath,
- {bool suppressWarnings: false,
- bool enableAsserts: false,
+ {bool enableAsserts: false,
int nullSafety: kNullSafetyOptionUnspecified,
List<String> experimentalFlags: null,
String packageConfig: null,
String invocationModes: '',
String verbosityLevel: Verbosity.defaultValue})
: super(isolateId, fileSystem, platformKernelPath,
- suppressWarnings: suppressWarnings,
enableAsserts: enableAsserts,
nullSafety: nullSafety,
experimentalFlags: experimentalFlags,
@@ -317,14 +311,12 @@
int isolateId,
FileSystem fileSystem,
Uri platformKernelPath,
- {bool suppressWarnings: false,
- bool enableAsserts: false,
+ {bool enableAsserts: false,
List<String> experimentalFlags: null,
String packageConfig: null,
String invocationModes: ''}) {
IncrementalCompilerWrapper result = IncrementalCompilerWrapper(
isolateId, fileSystem, platformKernelPath,
- suppressWarnings: suppressWarnings,
enableAsserts: enableAsserts,
experimentalFlags: experimentalFlags,
packageConfig: packageConfig,
@@ -353,7 +345,6 @@
Future<IncrementalCompilerWrapper> clone(int isolateId) async {
IncrementalCompilerWrapper clone = IncrementalCompilerWrapper(
isolateId, fileSystem, platformKernelPath,
- suppressWarnings: suppressWarnings,
enableAsserts: enableAsserts,
nullSafety: nullSafety,
experimentalFlags: experimentalFlags,
@@ -384,7 +375,6 @@
SingleShotCompilerWrapper(
int isolateId, FileSystem fileSystem, Uri platformKernelPath,
{this.requireMain: false,
- bool suppressWarnings: false,
bool enableAsserts: false,
int nullSafety: kNullSafetyOptionUnspecified,
List<String> experimentalFlags: null,
@@ -392,7 +382,6 @@
String invocationModes: '',
String verbosityLevel: Verbosity.defaultValue})
: super(isolateId, fileSystem, platformKernelPath,
- suppressWarnings: suppressWarnings,
enableAsserts: enableAsserts,
nullSafety: nullSafety,
experimentalFlags: experimentalFlags,
@@ -428,8 +417,7 @@
Future<Compiler> lookupOrBuildNewIncrementalCompiler(int isolateId,
List sourceFiles, Uri platformKernelPath, List<int> platformKernel,
- {bool suppressWarnings: false,
- bool enableAsserts: false,
+ {bool enableAsserts: false,
int nullSafety: kNullSafetyOptionUnspecified,
List<String> experimentalFlags: null,
String packageConfig: null,
@@ -461,7 +449,6 @@
// isolate was shut down. Message should be handled here in this script.
compiler = new IncrementalCompilerWrapper(
isolateId, fileSystem, platformKernelPath,
- suppressWarnings: suppressWarnings,
enableAsserts: enableAsserts,
nullSafety: nullSafety,
experimentalFlags: experimentalFlags,
@@ -516,10 +503,9 @@
final bool isStatic = request[9];
final List dillData = request[10];
final int blobLoadCount = request[11];
- final bool suppressWarnings = request[12];
- final bool enableAsserts = request[13];
+ final bool enableAsserts = request[12];
final List<String> experimentalFlags =
- request[14] != null ? request[14].cast<String>() : null;
+ request[13] != null ? request[13].cast<String>() : null;
IncrementalCompilerWrapper compiler = isolateCompilers[isolateId];
@@ -599,7 +585,6 @@
try {
compiler = new IncrementalCompilerWrapper.forExpressionCompilationOnly(
component, isolateId, fileSystem, null,
- suppressWarnings: suppressWarnings,
enableAsserts: enableAsserts,
experimentalFlags: experimentalFlags,
packageConfig: dotPackagesFile);
@@ -761,17 +746,14 @@
final bool snapshot = request[5];
final int nullSafety = request[6];
final List sourceFiles = request[8];
- final bool suppressWarnings = request[9];
- final bool enableAsserts = request[10];
+ final bool enableAsserts = request[9];
final List<String> experimentalFlags =
- request[11] != null ? request[11].cast<String>() : null;
- final String packageConfig = request[12];
- final String multirootFilepaths = request[13];
- final String multirootScheme = request[14];
- final String workingDirectory = request[15];
- // TODO(johnniwinther,bkonyi): Pass verbosity from command line arguments.
- final String verbosityLevel = Verbosity.defaultValue;
-
+ request[10] != null ? request[10].cast<String>() : null;
+ final String packageConfig = request[11];
+ final String multirootFilepaths = request[12];
+ final String multirootScheme = request[13];
+ final String workingDirectory = request[14];
+ final String verbosityLevel = request[15];
Uri platformKernelPath = null;
List<int> platformKernel = null;
if (request[3] is String) {
@@ -834,7 +816,6 @@
fileSystem,
platformKernelPath,
false,
- false,
nullSafety,
experimentalFlags,
packagesUri,
@@ -860,7 +841,6 @@
if (incremental) {
compiler = await lookupOrBuildNewIncrementalCompiler(
isolateId, sourceFiles, platformKernelPath, platformKernel,
- suppressWarnings: suppressWarnings,
enableAsserts: enableAsserts,
nullSafety: nullSafety,
experimentalFlags: experimentalFlags,
@@ -875,7 +855,6 @@
compiler = new SingleShotCompilerWrapper(
isolateId, fileSystem, platformKernelPath,
requireMain: false,
- suppressWarnings: suppressWarnings,
enableAsserts: enableAsserts,
nullSafety: nullSafety,
experimentalFlags: experimentalFlags,
@@ -1029,13 +1008,13 @@
kNullSafetyOptionUnspecified /* null safety */,
1 /* isolateId chosen randomly */,
[] /* source files */,
- false /* suppress warnings */,
false /* enable asserts */,
null /* experimental_flags */,
null /* package_config */,
null /* multirootFilepaths */,
null /* multirootScheme */,
null /* original working directory */,
+ 'all' /* CFE logging mode */,
];
await _processLoadRequest(request);
}
diff --git a/runtime/bin/dfe.cc b/runtime/bin/dfe.cc
index 0a6bc48..6935447 100644
--- a/runtime/bin/dfe.cc
+++ b/runtime/bin/dfe.cc
@@ -191,7 +191,7 @@
return Dart_CompileToKernel(sanitized_uri, platform_strong_dill,
platform_strong_dill_size, incremental, snapshot,
- package_config);
+ package_config, verbosity());
}
void DFE::CompileAndReadScript(const char* script_uri,
diff --git a/runtime/bin/dfe.h b/runtime/bin/dfe.h
index 0c38270..b381f9c 100644
--- a/runtime/bin/dfe.h
+++ b/runtime/bin/dfe.h
@@ -42,6 +42,11 @@
}
bool use_incremental_compiler() const { return use_incremental_compiler_; }
+ void set_verbosity(Dart_KernelCompilationVerbosityLevel verbosity) {
+ verbosity_ = verbosity;
+ }
+ Dart_KernelCompilationVerbosityLevel verbosity() const { return verbosity_; }
+
// Returns the platform binary file name if the path to
// kernel binaries was set using SetKernelBinaries.
const char* GetPlatformBinaryFilename();
@@ -115,6 +120,8 @@
bool use_dfe_;
bool use_incremental_compiler_;
char* frontend_filename_;
+ Dart_KernelCompilationVerbosityLevel verbosity_ =
+ Dart_KernelCompilationVerbosityLevel_All;
// Kernel binary specified on the cmd line.
uint8_t* application_kernel_buffer_;
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 12e64808..cddacb8 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -1283,6 +1283,7 @@
#if !defined(DART_PRECOMPILED_RUNTIME)
// Load vm_platform_strong.dill for dart:* source support.
dfe.Init();
+ dfe.set_verbosity(Options::verbosity_level());
if (script_name != nullptr) {
uint8_t* application_kernel_buffer = NULL;
intptr_t application_kernel_buffer_size = 0;
diff --git a/runtime/bin/main_options.cc b/runtime/bin/main_options.cc
index d019ce4..517029d 100644
--- a/runtime/bin/main_options.cc
+++ b/runtime/bin/main_options.cc
@@ -34,7 +34,13 @@
NULL,
};
+// These strings must match the enum VerbosityLevel in main_options.h.
+static const char* kVerbosityLevelNames[] = {
+ "error", "warning", "info", "all", nullptr,
+};
+
SnapshotKind Options::gen_snapshot_kind_ = kNone;
+VerbosityLevel Options::verbosity_ = kAll;
bool Options::enable_vm_service_ = false;
#define OPTION_FIELD(variable) Options::variable##_
diff --git a/runtime/bin/main_options.h b/runtime/bin/main_options.h
index 2ab8598..adec23c 100644
--- a/runtime/bin/main_options.h
+++ b/runtime/bin/main_options.h
@@ -63,7 +63,9 @@
// In main_options.cc there must be a list of strings that matches the enum
// called k{enum_type}Names. The field is not automatically declared in
// main_options.cc. It must be explicitly declared.
-#define ENUM_OPTIONS_LIST(V) V(snapshot_kind, SnapshotKind, gen_snapshot_kind)
+#define ENUM_OPTIONS_LIST(V) \
+ V(snapshot_kind, SnapshotKind, gen_snapshot_kind) \
+ V(verbosity, VerbosityLevel, verbosity)
// Callbacks passed to DEFINE_CB_OPTION().
#define CB_OPTIONS_LIST(V) \
@@ -79,6 +81,14 @@
kAppJIT,
};
+// This enum must match the strings in kVerbosityLevelNames in main_options.cc.
+enum VerbosityLevel {
+ kError,
+ kWarning,
+ kInfo,
+ kAll,
+};
+
static constexpr const char* DEFAULT_VM_SERVICE_SERVER_IP = "localhost";
static constexpr int DEFAULT_VM_SERVICE_SERVER_PORT = 8181;
static constexpr int INVALID_VM_SERVICE_SERVER_PORT = -1;
@@ -131,6 +141,9 @@
static const char* vm_service_server_ip() { return vm_service_server_ip_; }
static int vm_service_server_port() { return vm_service_server_port_; }
+ static Dart_KernelCompilationVerbosityLevel verbosity_level() {
+ return VerbosityLevelToDartAPI(verbosity_);
+ }
#if !defined(DART_PRECOMPILED_RUNTIME)
static DFE* dfe() { return dfe_; }
static void set_dfe(DFE* dfe) { dfe_ = dfe; }
@@ -169,6 +182,22 @@
static DFE* dfe_;
#endif // !defined(DART_PRECOMPILED_RUNTIME)
+ static Dart_KernelCompilationVerbosityLevel VerbosityLevelToDartAPI(
+ VerbosityLevel level) {
+ switch (level) {
+ case kError:
+ return Dart_KernelCompilationVerbosityLevel_Error;
+ case kWarning:
+ return Dart_KernelCompilationVerbosityLevel_Warning;
+ case kInfo:
+ return Dart_KernelCompilationVerbosityLevel_Info;
+ case kAll:
+ return Dart_KernelCompilationVerbosityLevel_All;
+ default:
+ UNREACHABLE();
+ }
+ }
+
// VM Service argument processing.
static const char* vm_service_server_ip_;
static bool enable_vm_service_;
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index aae9199..b4415cf 100644
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -3525,6 +3525,13 @@
intptr_t kernel_size;
} Dart_KernelCompilationResult;
+typedef enum {
+ Dart_KernelCompilationVerbosityLevel_Error = 0,
+ Dart_KernelCompilationVerbosityLevel_Warning,
+ Dart_KernelCompilationVerbosityLevel_Info,
+ Dart_KernelCompilationVerbosityLevel_All,
+} Dart_KernelCompilationVerbosityLevel;
+
DART_EXPORT bool Dart_IsKernelIsolate(Dart_Isolate isolate);
DART_EXPORT bool Dart_KernelIsolateIsRunning();
DART_EXPORT Dart_Port Dart_KernelPort();
@@ -3541,6 +3548,9 @@
* This is used by the frontend to determine if compilation related information
* should be printed to console (e.g., null safety mode).
*
+ * \param verbosity Specifies the logging behavior of the kernel compilation
+ * service.
+ *
* \return Returns the result of the compilation.
*
* On a successful compilation the returned [Dart_KernelCompilationResult] has
@@ -3559,7 +3569,8 @@
const intptr_t platform_kernel_size,
bool incremental_compile,
bool snapshot_compile,
- const char* package_config);
+ const char* package_config,
+ Dart_KernelCompilationVerbosityLevel verbosity);
typedef struct {
const char* uri;
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 2f53e5d..1cc6888 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -6095,7 +6095,8 @@
intptr_t platform_kernel_size,
bool incremental_compile,
bool snapshot_compile,
- const char* package_config) {
+ const char* package_config,
+ Dart_KernelCompilationVerbosityLevel verbosity) {
API_TIMELINE_DURATION(Thread::Current());
Dart_KernelCompilationResult result = {};
@@ -6105,7 +6106,8 @@
#else
result = KernelIsolate::CompileToKernel(
script_uri, platform_kernel, platform_kernel_size, 0, NULL,
- incremental_compile, snapshot_compile, package_config);
+ incremental_compile, snapshot_compile, package_config, NULL, NULL,
+ verbosity);
if (result.status == Dart_KernelCompilationStatus_Ok) {
Dart_KernelCompilationResult accept_result =
KernelIsolate::AcceptCompilation();
diff --git a/runtime/vm/kernel_isolate.cc b/runtime/vm/kernel_isolate.cc
index 36bfb1b..168cb76 100644
--- a/runtime/vm/kernel_isolate.cc
+++ b/runtime/vm/kernel_isolate.cc
@@ -31,10 +31,6 @@
#define Z (T->zone())
DEFINE_FLAG(bool, trace_kernel, false, "Trace Kernel service requests.");
-DEFINE_FLAG(bool,
- suppress_fe_warnings,
- false,
- "Suppress warnings from the FE.");
DEFINE_FLAG(charp,
kernel_multiroot_filepaths,
NULL,
@@ -621,10 +617,6 @@
num_blob_loads.type = Dart_CObject_kInt64;
num_blob_loads.value.as_int64 = source->num_blob_loads_;
- Dart_CObject suppress_warnings;
- suppress_warnings.type = Dart_CObject_kBool;
- suppress_warnings.value.as_bool = FLAG_suppress_fe_warnings;
-
Dart_CObject enable_asserts;
enable_asserts.type = Dart_CObject_kBool;
enable_asserts.value.as_bool = isolate_group->asserts();
@@ -656,7 +648,6 @@
&is_static_object,
&dills_object,
&num_blob_loads,
- &suppress_warnings,
&enable_asserts,
&experimental_flags_object};
message.value.as_array.values = message_arr;
@@ -713,7 +704,8 @@
const char* multiroot_filepaths,
const char* multiroot_scheme,
const MallocGrowableArray<char*>* experimental_flags,
- const char* original_working_directory) {
+ const char* original_working_directory,
+ Dart_KernelCompilationVerbosityLevel verbosity) {
// Build the message for the Kernel isolate.
// tag is used to specify which operation the frontend should perform.
Dart_CObject tag;
@@ -780,10 +772,6 @@
Dart_CObject files = BuildFilesPairs(source_files_count, source_files);
- Dart_CObject suppress_warnings;
- suppress_warnings.type = Dart_CObject_kBool;
- suppress_warnings.value.as_bool = FLAG_suppress_fe_warnings;
-
Dart_CObject enable_asserts;
enable_asserts.type = Dart_CObject_kBool;
enable_asserts.value.as_bool = isolate_group != nullptr
@@ -857,6 +845,11 @@
}
}
+ Dart_CObject verbosity_str;
+ verbosity_str.type = Dart_CObject_kString;
+ verbosity_str.value.as_string =
+ const_cast<char*>(KernelCompilationVerbosityLevelToString(verbosity));
+
Dart_CObject* message_arr[] = {&tag,
&send_port,
&uri,
@@ -866,13 +859,13 @@
&null_safety,
&isolate_id,
&files,
- &suppress_warnings,
&enable_asserts,
&experimental_flags_object,
&package_config_uri,
&multiroot_filepaths_object,
&multiroot_scheme_object,
- &original_working_directory_object};
+ &original_working_directory_object,
+ &verbosity_str};
message.value.as_array.values = message_arr;
message.value.as_array.length = ARRAY_SIZE(message_arr);
// Send the message.
@@ -987,6 +980,22 @@
return NULL;
}
+ static const char* KernelCompilationVerbosityLevelToString(
+ Dart_KernelCompilationVerbosityLevel verbosity) {
+ switch (verbosity) {
+ case Dart_KernelCompilationVerbosityLevel_Error:
+ return "error";
+ case Dart_KernelCompilationVerbosityLevel_Warning:
+ return "warning";
+ case Dart_KernelCompilationVerbosityLevel_Info:
+ return "info";
+ case Dart_KernelCompilationVerbosityLevel_All:
+ return "all";
+ default:
+ UNREACHABLE();
+ }
+ }
+
// This monitor must be held whenever linked list of requests is accessed.
static Monitor* requests_monitor_;
@@ -1017,7 +1026,8 @@
bool snapshot_compile,
const char* package_config,
const char* multiroot_filepaths,
- const char* multiroot_scheme) {
+ const char* multiroot_scheme,
+ Dart_KernelCompilationVerbosityLevel verbosity) {
// Start the kernel Isolate if it is not already running.
if (!Start()) {
Dart_KernelCompilationResult result = {};
@@ -1041,7 +1051,8 @@
kCompileTag, kernel_port, script_uri, platform_kernel,
platform_kernel_size, source_file_count, source_files,
incremental_compile, snapshot_compile, package_config,
- multiroot_filepaths, multiroot_scheme, experimental_flags_, NULL);
+ multiroot_filepaths, multiroot_scheme, experimental_flags_, NULL,
+ verbosity);
}
bool KernelIsolate::DetectNullSafety(const char* script_uri,
@@ -1060,7 +1071,7 @@
Dart_KernelCompilationResult result = request.SendAndWaitForResponse(
kDetectNullabilityTag, kernel_port, script_uri, nullptr, -1, 0, nullptr,
false, false, package_config, nullptr, nullptr, experimental_flags_,
- original_working_directory);
+ original_working_directory, Dart_KernelCompilationVerbosityLevel_Error);
return result.null_safety;
}
@@ -1074,9 +1085,10 @@
}
KernelCompilationRequest request;
- return request.SendAndWaitForResponse(kListDependenciesTag, kernel_port, NULL,
- NULL, 0, 0, NULL, false, false, NULL,
- NULL, NULL, experimental_flags_, NULL);
+ return request.SendAndWaitForResponse(
+ kListDependenciesTag, kernel_port, NULL, NULL, 0, 0, NULL, false, false,
+ NULL, NULL, NULL, experimental_flags_, NULL,
+ Dart_KernelCompilationVerbosityLevel_Error);
}
Dart_KernelCompilationResult KernelIsolate::AcceptCompilation() {
@@ -1091,9 +1103,10 @@
}
KernelCompilationRequest request;
- return request.SendAndWaitForResponse(kAcceptTag, kernel_port, NULL, NULL, 0,
- 0, NULL, true, false, NULL, NULL, NULL,
- experimental_flags_, NULL);
+ return request.SendAndWaitForResponse(
+ kAcceptTag, kernel_port, NULL, NULL, 0, 0, NULL, true, false, NULL, NULL,
+ NULL, experimental_flags_, NULL,
+ Dart_KernelCompilationVerbosityLevel_Error);
}
Dart_KernelCompilationResult KernelIsolate::CompileExpressionToKernel(
@@ -1138,7 +1151,8 @@
KernelCompilationRequest request;
return request.SendAndWaitForResponse(
kUpdateSourcesTag, kernel_port, NULL, NULL, 0, source_files_count,
- source_files, true, false, NULL, NULL, NULL, experimental_flags_, NULL);
+ source_files, true, false, NULL, NULL, NULL, experimental_flags_, NULL,
+ Dart_KernelCompilationVerbosityLevel_Error);
}
void KernelIsolate::NotifyAboutIsolateShutdown(const Isolate* isolate) {
diff --git a/runtime/vm/kernel_isolate.h b/runtime/vm/kernel_isolate.h
index f312aee..438e883 100644
--- a/runtime/vm/kernel_isolate.h
+++ b/runtime/vm/kernel_isolate.h
@@ -54,7 +54,9 @@
bool snapshot_compile = false,
const char* package_config = NULL,
const char* multiroot_filepaths = NULL,
- const char* multiroot_scheme = NULL);
+ const char* multiroot_scheme = NULL,
+ Dart_KernelCompilationVerbosityLevel verbosity =
+ Dart_KernelCompilationVerbosityLevel_All);
static bool DetectNullSafety(const char* script_uri,
const char* package_config,
diff --git a/tools/VERSION b/tools/VERSION
index 881e000..d2409964 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 12
PATCH 0
-PRERELEASE 258
+PRERELEASE 259
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index 2bf93261..f3980bc 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -2205,6 +2205,13 @@
]
},
{
+ "name": "js_runtime unit tests",
+ "arguments": [
+ "-nunittest-asserts-no-sdk-linux",
+ "pkg//js_runtime/"
+ ]
+ },
+ {
"name": "dart2js unit tests",
"arguments": [
"-nunittest-asserts-no-sdk-linux",
@@ -3218,7 +3225,7 @@
"name": "package unit tests",
"arguments": [
"-nunittest-asserts-${mode}-${system}",
- "pkg/pkg/(?!(analyzer*|analysis_server|compiler|front_end|kernel|nnbd_migration)/)"
+ "pkg/pkg/(?!(analyzer*|analysis_server|compiler|js_runtime|front_end|kernel|nnbd_migration)/)"
]
},
{
@@ -3256,7 +3263,7 @@
"name": "package unit tests",
"arguments": [
"-nunittest-asserts-${mode}-${system}",
- "pkg/pkg/(?!(analyzer*|analysis_server|compiler|front_end|kernel|nnbd_migration)/)"
+ "pkg/pkg/(?!(analyzer*|analysis_server|compiler|js_runtime|front_end|kernel|nnbd_migration)/)"
]
},
{