Version 2.14.0-270.0.dev
Merge commit '46222a174363297a376fc6a6e026fb56edf948e4' into 'dev'
diff --git a/DEPS b/DEPS
index 47bfafb..32a48b1 100644
--- a/DEPS
+++ b/DEPS
@@ -73,7 +73,7 @@
# Revisions of /third_party/* dependencies.
"args_rev": "d8fea36c10ef96797be02e3d132d572445cd86f4",
- "async_rev": "92e7119aa068bfb86a6a9519d44037ffff5eece8",
+ "async_rev": "8193eac211905cf33ae1f514022fdbd843836be5",
"bazel_worker_rev": "0885637b037979afbf5bcd05fd748b309fd669c0",
"benchmark_harness_rev": "c546dbd9f639f75cd2f75de8df2eb9f8ea15e8e7",
"boolean_selector_rev": "665e6921ab246569420376f827bff4585dff0b14",
@@ -85,7 +85,7 @@
"chrome_rev" : "19997",
"cli_util_rev" : "8c504de5deb08fe32ecf51f9662bb37d8c708e57",
"clock_rev" : "a494269254ba978e7ef8f192c5f7fec3fc05b9d3",
- "collection_rev": "9967dcd3d7645db6de48d5abfab3018bb0c84236",
+ "collection_rev": "75a7a5510979a3cd70143af85bcc1667ee233674",
"convert_rev": "413f591577419d8a8b95d445094a82c926650bd1",
"crypto_rev": "1c8ccc07b83b100216dc6dede767371043385648",
"csslib_rev": "e411d862fd8cc50415c1badf2632e017373b3f47",
@@ -105,7 +105,7 @@
# For more details, see https://github.com/dart-lang/sdk/issues/30164
"dart_style_rev": "f17c23e0eea9a870601c19d904e2a9c1a7c81470",
- "dartdoc_rev" : "b86cddcedf0737763d2e337c7474ad18d973fd4a",
+ "dartdoc_rev" : "c9621b92c738ec21a348cc2de032858276e9c774",
"devtools_rev" : "64cffbed6366329ad05e44d48fa2298367643bb6",
"jsshell_tag": "version:88.0",
"ffi_rev": "4dd32429880a57b64edaf54c9d5af8a9fa9a4ffb",
diff --git a/pkg/analysis_server/lib/src/lsp/constants.dart b/pkg/analysis_server/lib/src/lsp/constants.dart
index b5c3a27..9f46f71 100644
--- a/pkg/analysis_server/lib/src/lsp/constants.dart
+++ b/pkg/analysis_server/lib/src/lsp/constants.dart
@@ -58,11 +58,13 @@
static const serverSupportedCommands = [
sortMembers,
organizeImports,
+ fixAll,
sendWorkspaceEdit,
performRefactor,
];
static const sortMembers = 'edit.sortMembers';
static const organizeImports = 'edit.organizeImports';
+ static const fixAll = 'edit.fixAll';
static const sendWorkspaceEdit = 'edit.sendWorkspaceEdit';
static const performRefactor = 'refactor.perform';
}
@@ -171,11 +173,16 @@
CodeActionKind.Source,
// We have to explicitly list this for the client to enable built-in command.
CodeActionKind.SourceOrganizeImports,
+ FixAll,
SortMembers,
CodeActionKind.QuickFix,
CodeActionKind.Refactor,
];
static const SortMembers = CodeActionKind('source.sortMembers');
+ // TODO(dantup): Once this PR is merged into LSP and released, regenerated the
+ // LSP protocol code and swap this code CodeActionKind.SourceFixAll
+ // https://github.com/microsoft/language-server-protocol/pull/1308
+ static const FixAll = CodeActionKind('source.fixAll');
}
abstract class ServerErrorCodes {
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/commands/fix_all.dart b/pkg/analysis_server/lib/src/lsp/handlers/commands/fix_all.dart
new file mode 100644
index 0000000..784e2fe
--- /dev/null
+++ b/pkg/analysis_server/lib/src/lsp/handlers/commands/fix_all.dart
@@ -0,0 +1,73 @@
+// 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:analysis_server/lsp_protocol/protocol_generated.dart';
+import 'package:analysis_server/lsp_protocol/protocol_special.dart';
+import 'package:analysis_server/src/lsp/constants.dart';
+import 'package:analysis_server/src/lsp/handlers/commands/simple_edit_handler.dart';
+import 'package:analysis_server/src/lsp/handlers/handlers.dart';
+import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
+import 'package:analysis_server/src/lsp/mapping.dart';
+import 'package:analysis_server/src/lsp/progress.dart';
+import 'package:analysis_server/src/services/correction/bulk_fix_processor.dart';
+import 'package:analysis_server/src/services/correction/change_workspace.dart';
+import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart';
+
+class FixAllCommandHandler extends SimpleEditCommandHandler {
+ FixAllCommandHandler(LspAnalysisServer server) : super(server);
+
+ @override
+ String get commandName => 'Fix All';
+
+ @override
+ Future<ErrorOr<void>> handle(List<Object?>? arguments,
+ ProgressReporter reporter, CancellationToken cancellationToken) async {
+ if (arguments == null || arguments.length != 1 || arguments[0] is! String) {
+ return ErrorOr.error(ResponseError(
+ code: ServerErrorCodes.InvalidCommandArguments,
+ message:
+ '$commandName requires a single String parameter containing the path of a Dart file',
+ ));
+ }
+
+ // Get the version of the doc before we calculate edits so we can send it back
+ // to the client so that they can discard this edit if the document has been
+ // modified since.
+ final path = arguments.single as String;
+ final docIdentifier = server.getVersionedDocumentIdentifier(path);
+
+ final result = await requireResolvedUnit(path);
+
+ if (cancellationToken.isCancellationRequested) {
+ return error(ErrorCodes.RequestCancelled, 'Request was cancelled');
+ }
+
+ return result.mapResult((result) async {
+ final workspace = DartChangeWorkspace(server.currentSessions);
+ final processor =
+ BulkFixProcessor(server.instrumentationService, workspace);
+
+ final collection = AnalysisContextCollectionImpl(
+ includedPaths: [path],
+ resourceProvider: server.resourceProvider,
+ sdkPath: server.sdkManager.defaultSdkDirectory,
+ );
+ final changeBuilder = await processor.fixErrors(collection.contexts);
+ final change = changeBuilder.sourceChange;
+
+ if (change.edits.isEmpty) {
+ return success(null);
+ }
+
+ // Before we send anything back, ensure the original file didn't change
+ // while we were computing changes.
+ if (fileHasBeenModified(path, docIdentifier.version)) {
+ return fileModifiedError;
+ }
+
+ final edit = createWorkspaceEdit(server, change);
+ return sendWorkspaceEditToClient(edit);
+ });
+ }
+}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/commands/organize_imports.dart b/pkg/analysis_server/lib/src/lsp/handlers/commands/organize_imports.dart
index b57dbbe..6b3ac68 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/commands/organize_imports.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/commands/organize_imports.dart
@@ -18,7 +18,7 @@
String get commandName => 'Organize Imports';
@override
- Future<ErrorOr<void>> handle(List<dynamic>? arguments,
+ Future<ErrorOr<void>> handle(List<Object?>? arguments,
ProgressReporter reporter, CancellationToken cancellationToken) async {
if (arguments == null || arguments.length != 1 || arguments[0] is! String) {
return ErrorOr.error(ResponseError(
@@ -31,7 +31,7 @@
// Get the version of the doc before we calculate edits so we can send it back
// to the client so that they can discard this edit if the document has been
// modified since.
- final path = arguments.single;
+ final path = arguments.single as String;
final docIdentifier = server.getVersionedDocumentIdentifier(path);
final result = await requireResolvedUnit(path);
@@ -57,6 +57,10 @@
final organizer = ImportOrganizer(code, unit, result.errors);
final edits = organizer.organize();
+ if (edits.isEmpty) {
+ return success(null);
+ }
+
return sendSourceEditsToClient(docIdentifier, unit, edits);
});
}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart b/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart
index 317b6a8..ed17c2a 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart
@@ -24,7 +24,7 @@
String get commandName => 'Perform Refactor';
@override
- Future<ErrorOr<void>> handle(List<dynamic>? arguments,
+ Future<ErrorOr<void>> handle(List<Object?>? arguments,
ProgressReporter reporter, CancellationToken cancellationToken) async {
if (arguments == null ||
arguments.length != 6 ||
@@ -43,12 +43,12 @@
));
}
- String kind = arguments[0];
- String path = arguments[1];
- int? docVersion = arguments[2];
- int offset = arguments[3];
- int length = arguments[4];
- Map<String, dynamic>? options = arguments[5];
+ final kind = arguments[0] as String;
+ final path = arguments[1] as String;
+ final docVersion = arguments[2] as int?;
+ final offset = arguments[3] as int;
+ final length = arguments[4] as int;
+ final options = arguments[5] as Map<String, Object?>?;
final result = await requireResolvedUnit(path);
return result.mapResult((result) async {
@@ -84,6 +84,10 @@
return error(ErrorCodes.RequestCancelled, 'Request was cancelled');
}
+ if (change.edits.isEmpty) {
+ return success(null);
+ }
+
// If the file changed while we were validating and preparing the change,
// we should fail to avoid sending bad edits.
if (fileHasBeenModified(path, docVersion)) {
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/commands/send_workspace_edit.dart b/pkg/analysis_server/lib/src/lsp/handlers/commands/send_workspace_edit.dart
index 2fbaea1..de71c8c 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/commands/send_workspace_edit.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/commands/send_workspace_edit.dart
@@ -24,11 +24,11 @@
String get commandName => 'Send Workspace Edit';
@override
- Future<ErrorOr<void>> handle(List<dynamic>? arguments,
+ Future<ErrorOr<void>> handle(List<Object?>? arguments,
ProgressReporter reporter, CancellationToken cancellationToken) async {
if (arguments == null ||
arguments.length != 1 ||
- arguments[0] is! Map<String, dynamic>) {
+ arguments[0] is! Map<String, Object?>) {
return ErrorOr.error(ResponseError(
code: ServerErrorCodes.InvalidCommandArguments,
message:
@@ -36,7 +36,8 @@
));
}
- final workspaceEdit = WorkspaceEdit.fromJson(arguments[0]);
+ final workspaceEdit =
+ WorkspaceEdit.fromJson(arguments[0] as Map<String, Object?>);
return await sendWorkspaceEditToClient(workspaceEdit);
}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/commands/sort_members.dart b/pkg/analysis_server/lib/src/lsp/handlers/commands/sort_members.dart
index 7fea763..9372068 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/commands/sort_members.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/commands/sort_members.dart
@@ -19,7 +19,7 @@
String get commandName => 'Sort Members';
@override
- Future<ErrorOr<void>> handle(List<dynamic>? arguments,
+ Future<ErrorOr<void>> handle(List<Object?>? arguments,
ProgressReporter reporter, CancellationToken cancellationToken) async {
if (arguments == null || arguments.length != 1 || arguments[0] is! String) {
return ErrorOr.error(ResponseError(
@@ -32,7 +32,7 @@
// Get the version of the doc before we calculate edits so we can send it back
// to the client so that they can discard this edit if the document has been
// modified since.
- final path = arguments.single;
+ final path = arguments.single as String;
final docIdentifier = server.getVersionedDocumentIdentifier(path);
var driver = server.getAnalysisDriver(path);
@@ -63,6 +63,11 @@
final sorter = MemberSorter(code, unit);
final edits = sorter.sort();
+
+ if (edits.isEmpty) {
+ return success(null);
+ }
+
return await sendSourceEditsToClient(docIdentifier, unit, edits);
}
}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
index 2485b8b..5063d04 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
@@ -476,6 +476,13 @@
command: Commands.organizeImports,
arguments: [path]),
),
+ if (shouldIncludeKind(DartCodeActionKind.FixAll))
+ _commandOrCodeAction(
+ supportsLiteralCodeActions,
+ DartCodeActionKind.FixAll,
+ Command(
+ title: 'Fix All', command: Commands.fixAll, arguments: [path]),
+ ),
];
}
}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_execute_command.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_execute_command.dart
index 533798f..05aaa4e 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_execute_command.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_execute_command.dart
@@ -5,6 +5,7 @@
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/constants.dart';
+import 'package:analysis_server/src/lsp/handlers/commands/fix_all.dart';
import 'package:analysis_server/src/lsp/handlers/commands/organize_imports.dart';
import 'package:analysis_server/src/lsp/handlers/commands/perform_refactor.dart';
import 'package:analysis_server/src/lsp/handlers/commands/send_workspace_edit.dart';
@@ -22,6 +23,7 @@
: commandHandlers = {
Commands.sortMembers: SortMembersCommandHandler(server),
Commands.organizeImports: OrganizeImportsCommandHandler(server),
+ Commands.fixAll: FixAllCommandHandler(server),
Commands.performRefactor: PerformRefactorCommandHandler(server),
Commands.sendWorkspaceEdit: SendWorkspaceEditCommandHandler(server),
},
@@ -49,6 +51,9 @@
: server.clientCapabilities?.workDoneProgress ?? false
? ProgressReporter.serverCreated(server)
: ProgressReporter.noop;
- return handler.handle(params.arguments, progress, cancellationToken);
+ // TODO(dantup): Remove this cast and update codegen to use `Object?` in
+ // place of the `dynamics`.
+ return handler.handle(
+ params.arguments?.cast<Object?>(), progress, cancellationToken);
}
}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart b/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart
index 89db7cc..eb22a64 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart
@@ -49,7 +49,7 @@
CommandHandler(this.server);
- Future<ErrorOr<Object?>> handle(List<dynamic>? arguments,
+ Future<ErrorOr<Object?>> handle(List<Object?>? arguments,
ProgressReporter progress, CancellationToken cancellationToken);
}
diff --git a/pkg/analysis_server/test/lsp/code_actions_source_test.dart b/pkg/analysis_server/test/lsp/code_actions_source_test.dart
index 6d977b8..75118f8 100644
--- a/pkg/analysis_server/test/lsp/code_actions_source_test.dart
+++ b/pkg/analysis_server/test/lsp/code_actions_source_test.dart
@@ -4,6 +4,7 @@
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/src/lsp/constants.dart';
+import 'package:linter/src/rules.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -14,10 +15,44 @@
defineReflectiveSuite(() {
defineReflectiveTests(SortMembersSourceCodeActionsTest);
defineReflectiveTests(OrganizeImportsSourceCodeActionsTest);
+ defineReflectiveTests(FixAllSourceCodeActionsTest);
});
}
@reflectiveTest
+class FixAllSourceCodeActionsTest extends AbstractCodeActionsTest {
+ Future<void> test_appliesCorrectEdits() async {
+ const analysisOptionsContent = '''
+linter:
+ rules:
+ - unnecessary_new
+ - prefer_collection_literals
+ ''';
+ const content = '''
+ final a = new Object();
+ final b = new Set<String>();
+ ''';
+ const expectedContent = '''
+ final a = Object();
+ final b = <String>{};
+ ''';
+
+ registerLintRules();
+ newFile(analysisOptionsPath, content: analysisOptionsContent);
+ newFile(mainFilePath, content: content);
+
+ await initialize(
+ workspaceCapabilities:
+ withApplyEditSupport(emptyWorkspaceClientCapabilities));
+
+ final codeActions = await getCodeActions(mainFileUri.toString());
+ final codeAction = findCommand(codeActions, Commands.fixAll)!;
+
+ await verifyCodeActionEdits(codeAction, content, expectedContent);
+ }
+}
+
+@reflectiveTest
class OrganizeImportsSourceCodeActionsTest extends AbstractCodeActionsTest {
Future<void> test_appliesCorrectEdits_withDocumentChangesSupport() async {
const content = '''
@@ -136,9 +171,10 @@
kinds: [kind],
);
- expect(await ofKind(CodeActionKind.Source), hasLength(2));
+ expect(await ofKind(CodeActionKind.Source), hasLength(3));
expect(await ofKind(CodeActionKind.SourceOrganizeImports), hasLength(1));
expect(await ofKind(DartCodeActionKind.SortMembers), hasLength(1));
+ expect(await ofKind(DartCodeActionKind.FixAll), hasLength(1));
expect(await ofKind(CodeActionKind('source.foo')), isEmpty);
expect(await ofKind(CodeActionKind.Refactor), isEmpty);
}
diff --git a/pkg/analysis_server/tool/lsp_spec/README.md b/pkg/analysis_server/tool/lsp_spec/README.md
index 1ef02d9..5376013 100644
--- a/pkg/analysis_server/tool/lsp_spec/README.md
+++ b/pkg/analysis_server/tool/lsp_spec/README.md
@@ -92,6 +92,7 @@
| textDocument/selectionRanges | ✅ | ✅ | | ✅ | ✅ |
| textDocument/codeAction (sortMembers) | ✅ | ✅ | | ✅ | ✅ |
| textDocument/codeAction (organiseImports) | ✅ | ✅ | | ✅ | ✅ |
+| textDocument/codeAction (fixAll) | ✅ | ✅ | | ✅ | ✅ |
| textDocument/codeAction (refactors) | ✅ | ✅ | | ✅ | ✅ |
| textDocument/codeAction (assists) | ✅ | ✅ | | ✅ | ✅ | Only if the client advertises `codeActionLiteralSupport` with `Refactor`
| textDocument/codeAction (fixes) | ✅ | ✅ | | ✅ | ✅ | Only if the client advertises `codeActionLiteralSupport` with `QuickFix`
diff --git a/pkg/analyzer/lib/src/dart/constant/evaluation.dart b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
index dfad758..17fe297 100644
--- a/pkg/analyzer/lib/src/dart/constant/evaluation.dart
+++ b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
@@ -983,12 +983,21 @@
var leftResult = node.leftOperand.accept(this);
// evaluate lazy operators
if (operatorType == TokenType.AMPERSAND_AMPERSAND) {
+ if (leftResult?.toBoolValue() == false) {
+ _reportNotPotentialConstants(node.rightOperand);
+ }
return _dartObjectComputer.lazyAnd(
node, leftResult, () => node.rightOperand.accept(this));
} else if (operatorType == TokenType.BAR_BAR) {
+ if (leftResult?.toBoolValue() == true) {
+ _reportNotPotentialConstants(node.rightOperand);
+ }
return _dartObjectComputer.lazyOr(
node, leftResult, () => node.rightOperand.accept(this));
} else if (operatorType == TokenType.QUESTION_QUESTION) {
+ if (leftResult?.isNull != true) {
+ _reportNotPotentialConstants(node.rightOperand);
+ }
return _dartObjectComputer.lazyQuestionQuestion(
node, leftResult, () => node.rightOperand.accept(this));
}
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index 7f845f6..4030bff 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -336,6 +336,7 @@
static const HintCode DEPRECATED_EXTENDS_FUNCTION = HintCode(
'DEPRECATED_SUBTYPE_OF_FUNCTION', "Extending 'Function' is deprecated.",
correction: "Try removing 'Function' from the 'extends' clause.",
+ hasPublishedDocs: true,
uniqueName: 'DEPRECATED_EXTENDS_FUNCTION');
/**
@@ -353,6 +354,7 @@
'DEPRECATED_SUBTYPE_OF_FUNCTION',
"Implementing 'Function' has no effect.",
correction: "Try removing 'Function' from the 'implements' clause.",
+ hasPublishedDocs: true,
uniqueName: 'DEPRECATED_IMPLEMENTS_FUNCTION');
/**
@@ -451,6 +453,7 @@
static const HintCode DEPRECATED_MIXIN_FUNCTION = HintCode(
'DEPRECATED_SUBTYPE_OF_FUNCTION', "Mixing in 'Function' is deprecated.",
correction: "Try removing 'Function' from the 'with' clause.",
+ hasPublishedDocs: true,
uniqueName: 'DEPRECATED_MIXIN_FUNCTION');
/**
@@ -843,7 +846,8 @@
"The imported library defines a top-level function named 'loadLibrary' "
"that is hidden by deferring this library.",
correction: "Try changing the import to not be deferred, or "
- "rename the function in the imported library.");
+ "rename the function in the imported library.",
+ hasPublishedDocs: true);
/**
* https://github.com/dart-lang/sdk/issues/44063
@@ -2769,7 +2773,8 @@
"it's sealed.",
correction:
"Try composing instead of inheriting, or refer to the documentation "
- "of '{0}' for more information.");
+ "of '{0}' for more information.",
+ hasPublishedDocs: true);
/**
* No parameters.
@@ -2823,6 +2828,7 @@
'TYPE_CHECK_WITH_NULL',
"Tests for non-null should be done with '!= null'.",
correction: "Try replacing the 'is! Null' check with '!= null'.",
+ hasPublishedDocs: true,
uniqueName: 'TYPE_CHECK_IS_NOT_NULL');
/**
@@ -2831,6 +2837,7 @@
static const HintCode TYPE_CHECK_IS_NULL = HintCode(
'TYPE_CHECK_WITH_NULL', "Tests for null should be done with '== null'.",
correction: "Try replacing the 'is Null' check with '== null'.",
+ hasPublishedDocs: true,
uniqueName: 'TYPE_CHECK_IS_NULL');
/**
@@ -3018,7 +3025,8 @@
// ```
static const HintCode UNNECESSARY_NO_SUCH_METHOD = HintCode(
'UNNECESSARY_NO_SUCH_METHOD', "Unnecessary 'noSuchMethod' declaration.",
- correction: "Try removing the declaration of 'noSuchMethod'.");
+ correction: "Try removing the declaration of 'noSuchMethod'.",
+ hasPublishedDocs: true);
/**
* No parameters.
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index 4c0a264..d383272 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -1605,6 +1605,7 @@
"'{0}' can't be used to name both a constructor and a static field "
"in this class.",
correction: "Try renaming either the constructor or the field.",
+ hasPublishedDocs: true,
uniqueName: 'CONFLICTING_CONSTRUCTOR_AND_STATIC_FIELD');
/**
@@ -1617,6 +1618,7 @@
"'{0}' can't be used to name both a constructor and a static method "
"in this class.",
correction: "Try renaming either the constructor or the method.",
+ hasPublishedDocs: true,
uniqueName: 'CONFLICTING_CONSTRUCTOR_AND_STATIC_METHOD');
/**
@@ -1757,6 +1759,7 @@
"'{0}' can't be used to name both a type variable and the class in "
"which the type variable is defined.",
correction: "Try renaming either the type variable or the class.",
+ hasPublishedDocs: true,
uniqueName: 'CONFLICTING_TYPE_VARIABLE_AND_CLASS',
);
@@ -1770,6 +1773,7 @@
"'{0}' can't be used to name both a type variable and the extension "
"in which the type variable is defined.",
correction: "Try renaming either the type variable or the extension.",
+ hasPublishedDocs: true,
uniqueName: 'CONFLICTING_TYPE_VARIABLE_AND_EXTENSION',
);
@@ -1809,6 +1813,7 @@
"'{0}' can't be used to name both a type variable and a member in "
"this class.",
correction: "Try renaming either the type variable or the member.",
+ hasPublishedDocs: true,
uniqueName: 'CONFLICTING_TYPE_VARIABLE_AND_MEMBER_CLASS',
);
@@ -1822,6 +1827,7 @@
"'{0}' can't be used to name both a type variable and a member in "
"this mixin.",
correction: "Try renaming either the type variable or the member.",
+ hasPublishedDocs: true,
uniqueName: 'CONFLICTING_TYPE_VARIABLE_AND_MEMBER_MIXIN',
);
@@ -1835,6 +1841,7 @@
"'{0}' can't be used to name both a type variable and a member in "
"this extension.",
correction: "Try renaming either the type variable or the member.",
+ hasPublishedDocs: true,
uniqueName: 'CONFLICTING_TYPE_VARIABLE_AND_MEMBER_EXTENSION',
);
@@ -1848,6 +1855,7 @@
"'{0}' can't be used to name both a type variable and the mixin in "
"which the type variable is defined.",
correction: "Try renaming either the type variable or the mixin.",
+ hasPublishedDocs: true,
uniqueName: 'CONFLICTING_TYPE_VARIABLE_AND_MIXIN',
);
@@ -3284,7 +3292,8 @@
"The field '{0}' can't be initialized by multiple parameters in the "
"same constructor.",
correction: "Try removing one of the parameters, or "
- "using different fields.");
+ "using different fields.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -3590,7 +3599,8 @@
// Remove the export directive.
static const CompileTimeErrorCode EXPORT_INTERNAL_LIBRARY =
CompileTimeErrorCode('EXPORT_INTERNAL_LIBRARY',
- "The library '{0}' is internal and can't be exported.");
+ "The library '{0}' is internal and can't be exported.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -3920,6 +3930,7 @@
correction:
"Try specifying a different superclass, or removing the extends "
"clause.",
+ hasPublishedDocs: true,
uniqueName: 'EXTENDS_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER');
/**
@@ -5521,6 +5532,7 @@
'SUPERTYPE_EXPANDS_TO_TYPE_PARAMETER',
"A type alias that expands to a type parameter can't be implemented.",
correction: "Try specifying a class or mixin, or removing the list.",
+ hasPublishedDocs: true,
uniqueName: 'IMPLEMENTS_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER');
/**
@@ -5844,7 +5856,8 @@
'INITIALIZER_FOR_STATIC_FIELD',
"'{0}' is a static field in the enclosing class. Fields initialized "
"in a constructor can't be static.",
- correction: "Try removing the initialization.");
+ correction: "Try removing the initialization.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -6203,7 +6216,8 @@
"precision: '{0}'.",
correction:
"Try using the class 'BigInt', or switch to the closest valid "
- "double: '{1}'.");
+ "double: '{1}'.",
+ hasPublishedDocs: true);
/**
* No parameters.
@@ -6833,7 +6847,7 @@
static const CompileTimeErrorCode INVALID_MODIFIER_ON_CONSTRUCTOR =
CompileTimeErrorCode('INVALID_MODIFIER_ON_CONSTRUCTOR',
"The modifier '{0}' can't be applied to the body of a constructor.",
- correction: "Try removing the modifier.");
+ correction: "Try removing the modifier.", hasPublishedDocs: true);
/**
* Parameters:
@@ -6877,7 +6891,7 @@
static const CompileTimeErrorCode INVALID_MODIFIER_ON_SETTER =
CompileTimeErrorCode('INVALID_MODIFIER_ON_SETTER',
"The modifier '{0}' can't be applied to the body of a setter.",
- correction: "Try removing the modifier.");
+ correction: "Try removing the modifier.", hasPublishedDocs: true);
/**
* Parameters:
@@ -8130,7 +8144,8 @@
CompileTimeErrorCode(
'MIXIN_APPLICATION_CONCRETE_SUPER_INVOKED_MEMBER_TYPE',
"The super-invoked member '{0}' has the type '{1}', and the concrete "
- "member in the class has the type '{2}'.");
+ "member in the class has the type '{2}'.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -8253,7 +8268,8 @@
'MIXIN_APPLICATION_NOT_IMPLEMENTED_INTERFACE',
"'{0}' can't be mixed onto '{1}' because '{1}' doesn't implement "
"'{2}'.",
- correction: "Try extending the class '{0}'.");
+ correction: "Try extending the class '{0}'.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -8312,7 +8328,8 @@
CompileTimeErrorCode(
'MIXIN_CLASS_DECLARES_CONSTRUCTOR',
"The class '{0}' can't be used as a mixin because it declares a "
- "constructor.");
+ "constructor.",
+ hasPublishedDocs: true);
/**
* The <i>mixinMember</i> production allows the same instance or static
@@ -8414,7 +8431,8 @@
CompileTimeErrorCode(
'MIXIN_INHERITS_FROM_NOT_OBJECT',
"The class '{0}' can't be used as a mixin because it extends a class "
- "other than 'Object'.");
+ "other than 'Object'.",
+ hasPublishedDocs: true);
/**
* No parameters.
@@ -8496,6 +8514,7 @@
MIXIN_OF_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER = CompileTimeErrorCode(
'SUPERTYPE_EXPANDS_TO_TYPE_PARAMETER',
"A type alias that expands to a type parameter can't be mixed in.",
+ hasPublishedDocs: true,
uniqueName: 'MIXIN_OF_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER');
/**
@@ -8506,6 +8525,7 @@
'SUPERTYPE_EXPANDS_TO_TYPE_PARAMETER',
"A type alias that expands to a type parameter can't be used as a "
"superclass constraint.",
+ hasPublishedDocs: true,
uniqueName: 'MIXIN_ON_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER');
/**
@@ -8678,7 +8698,8 @@
static const CompileTimeErrorCode MULTIPLE_SUPER_INITIALIZERS =
CompileTimeErrorCode('MULTIPLE_SUPER_INITIALIZERS',
"A constructor can have at most one 'super' initializer.",
- correction: "Try removing all but one of the 'super' initializers.");
+ correction: "Try removing all but one of the 'super' initializers.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -9892,7 +9913,8 @@
"found.",
correction:
"Try calling a different constructor of the superclass, or "
- "making the called constructor not be a factory constructor.");
+ "making the called constructor not be a factory constructor.",
+ hasPublishedDocs: true);
/**
* An error code for when a class has no explicit constructor, and therefore
@@ -10081,7 +10103,8 @@
static const CompileTimeErrorCode NON_VOID_RETURN_FOR_OPERATOR =
CompileTimeErrorCode('NON_VOID_RETURN_FOR_OPERATOR',
"The return type of the operator []= must be 'void'.",
- correction: "Try changing the return type to 'void'.");
+ correction: "Try changing the return type to 'void'.",
+ hasPublishedDocs: true);
/**
* No parameters.
@@ -10115,7 +10138,8 @@
CompileTimeErrorCode('NON_VOID_RETURN_FOR_SETTER',
"The return type of the setter must be 'void' or absent.",
correction: "Try removing the return type, or "
- "define a method rather than a setter.");
+ "define a method rather than a setter.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -10799,7 +10823,8 @@
static const CompileTimeErrorCode OPTIONAL_PARAMETER_IN_OPERATOR =
CompileTimeErrorCode('OPTIONAL_PARAMETER_IN_OPERATOR',
"Optional parameters aren't allowed when defining an operator.",
- correction: "Try removing the optional parameters.");
+ correction: "Try removing the optional parameters.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -10936,7 +10961,8 @@
"'{0}', in the part-of directive.",
correction:
"Try changing the part-of directive to a URI, or try including a "
- "different part.");
+ "different part.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -11106,7 +11132,8 @@
'PRIVATE_COLLISION_IN_MIXIN_APPLICATION',
"The private name '{0}', defined by '{1}', "
"conflicts with the same name defined by '{2}'.",
- correction: "Try removing '{1}' from the 'with' clause.");
+ correction: "Try removing '{1}' from the 'with' clause.",
+ hasPublishedDocs: true);
/**
* No parameters.
@@ -11329,6 +11356,7 @@
static const CompileTimeErrorCode RECURSIVE_INTERFACE_INHERITANCE =
CompileTimeErrorCode('RECURSIVE_INTERFACE_INHERITANCE',
"'{0}' can't be a superinterface of itself: {1}.",
+ hasPublishedDocs: true,
uniqueName: 'RECURSIVE_INTERFACE_INHERITANCE');
/**
@@ -11347,6 +11375,7 @@
static const CompileTimeErrorCode RECURSIVE_INTERFACE_INHERITANCE_EXTENDS =
CompileTimeErrorCode(
'RECURSIVE_INTERFACE_INHERITANCE', "'{0}' can't extend itself.",
+ hasPublishedDocs: true,
uniqueName: 'RECURSIVE_INTERFACE_INHERITANCE_EXTENDS');
/**
@@ -11365,6 +11394,7 @@
static const CompileTimeErrorCode RECURSIVE_INTERFACE_INHERITANCE_IMPLEMENTS =
CompileTimeErrorCode(
'RECURSIVE_INTERFACE_INHERITANCE', "'{0}' can't implement itself.",
+ hasPublishedDocs: true,
uniqueName: 'RECURSIVE_INTERFACE_INHERITANCE_IMPLEMENTS');
/**
@@ -11374,6 +11404,7 @@
static const CompileTimeErrorCode RECURSIVE_INTERFACE_INHERITANCE_ON =
CompileTimeErrorCode('RECURSIVE_INTERFACE_INHERITANCE',
"'{0}' can't use itself as a superclass constraint.",
+ hasPublishedDocs: true,
uniqueName: 'RECURSIVE_INTERFACE_INHERITANCE_ON');
/**
@@ -11392,6 +11423,7 @@
static const CompileTimeErrorCode RECURSIVE_INTERFACE_INHERITANCE_WITH =
CompileTimeErrorCode('RECURSIVE_INTERFACE_INHERITANCE',
"'{0}' can't use itself as a mixin.",
+ hasPublishedDocs: true,
uniqueName: 'RECURSIVE_INTERFACE_INHERITANCE_WITH');
/**
@@ -11973,7 +12005,8 @@
"Can't return a value from a generator function (using the '{0}' "
"modifier).",
correction: "Try removing the value, replacing 'return' with 'yield' or "
- "changing the method body modifier.");
+ "changing the method body modifier.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -12166,7 +12199,8 @@
// ```
static const CompileTimeErrorCode SET_ELEMENT_TYPE_NOT_ASSIGNABLE =
CompileTimeErrorCode('SET_ELEMENT_TYPE_NOT_ASSIGNABLE',
- "The element type '{0}' can't be assigned to the set type '{1}'.");
+ "The element type '{0}' can't be assigned to the set type '{1}'.",
+ hasPublishedDocs: true);
/**
* No parameters.
@@ -12549,7 +12583,8 @@
"through the cycle: {1}.",
correction:
"Try adding an explicit type to one or more of the variables in the "
- "cycle in order to break the cycle.");
+ "cycle in order to break the cycle.",
+ hasPublishedDocs: true);
/**
* No parameters.
@@ -12582,7 +12617,8 @@
CompileTimeErrorCode(
'TYPE_ALIAS_CANNOT_REFERENCE_ITSELF',
"Typedefs can't reference themselves directly or recursively via "
- "another typedef.");
+ "another typedef.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -12770,7 +12806,8 @@
CompileTimeErrorCode('TYPE_PARAMETER_SUPERTYPE_OF_ITS_BOUND',
"'{0}' can't be a supertype of its upper bound.",
correction:
- "Try using a type that is the same as or a subclass of '{1}'.");
+ "Try using a type that is the same as or a subclass of '{1}'.",
+ hasPublishedDocs: true);
/**
* No parameters.
@@ -12826,7 +12863,8 @@
'TYPE_TEST_WITH_NON_TYPE',
"The name '{0}' isn't a type and can't be used in an 'is' "
"expression.",
- correction: "Try correcting the name to match an existing type.");
+ correction: "Try correcting the name to match an existing type.",
+ hasPublishedDocs: true);
/**
* No parameters.
@@ -13195,6 +13233,7 @@
"The class '{0}' doesn't have an unnamed constructor.",
correction: "Try defining an unnamed constructor in '{0}', or "
"invoking a different constructor.",
+ hasPublishedDocs: true,
uniqueName: 'UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT',
);
@@ -13497,7 +13536,8 @@
static const CompileTimeErrorCode UNDEFINED_EXTENSION_OPERATOR =
CompileTimeErrorCode('UNDEFINED_EXTENSION_OPERATOR',
"The operator '{0}' isn't defined for the extension '{1}'.",
- correction: "Try defining the operator '{0}'.");
+ correction: "Try defining the operator '{0}'.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -14640,7 +14680,8 @@
static const CompileTimeErrorCode WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR =
CompileTimeErrorCode('WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR',
"The constructor '{0}.{1}' doesn't have type parameters.",
- correction: "Try moving type arguments to after the type name.");
+ correction: "Try moving type arguments to after the type name.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -14689,7 +14730,8 @@
'WRONG_NUMBER_OF_TYPE_ARGUMENTS_EXTENSION',
"The extension '{0}' is declared with {1} type parameters, "
"but {2} type arguments were given.",
- correction: "Try adjusting the number of type arguments.");
+ correction: "Try adjusting the number of type arguments.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -14836,6 +14878,7 @@
"(one marked with either 'async*' or 'sync*').",
correction:
"Try adding 'async*' or 'sync*' to the enclosing function.",
+ hasPublishedDocs: true,
uniqueName: 'YIELD_EACH_IN_NON_GENERATOR');
/**
@@ -14850,7 +14893,8 @@
"Yield statements must be in a generator function "
"(one marked with either 'async*' or 'sync*').",
correction:
- "Try adding 'async*' or 'sync*' to the enclosing function.");
+ "Try adding 'async*' or 'sync*' to the enclosing function.",
+ hasPublishedDocs: true);
/**
* Parameters:
diff --git a/pkg/analyzer/lib/src/pubspec/pubspec_warning_code.dart b/pkg/analyzer/lib/src/pubspec/pubspec_warning_code.dart
index 50dec14..5f90845 100644
--- a/pkg/analyzer/lib/src/pubspec/pubspec_warning_code.dart
+++ b/pkg/analyzer/lib/src/pubspec/pubspec_warning_code.dart
@@ -43,7 +43,8 @@
// file containing the asset.
static const PubspecWarningCode ASSET_DOES_NOT_EXIST = PubspecWarningCode(
'ASSET_DOES_NOT_EXIST', "The asset file '{0}' doesn't exist.",
- correction: "Try creating the file or fixing the path to the file.");
+ correction: "Try creating the file or fixing the path to the file.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -78,7 +79,8 @@
PubspecWarningCode('ASSET_DIRECTORY_DOES_NOT_EXIST',
"The asset directory '{0}' doesn't exist.",
correction: "Try creating the directory or fixing the path to the "
- "directory.");
+ "directory.",
+ hasPublishedDocs: true);
/**
* No parameters.
@@ -116,7 +118,8 @@
"The value of the 'asset' field is expected to be a list of relative "
"file paths.",
correction:
- "Try converting the value to be a list of relative file paths.");
+ "Try converting the value to be a list of relative file paths.",
+ hasPublishedDocs: true);
/**
* No parameters.
@@ -153,7 +156,8 @@
// ```
static const PubspecWarningCode ASSET_NOT_STRING = PubspecWarningCode(
'ASSET_NOT_STRING', "Assets are required to be file paths (strings).",
- correction: "Try converting the value to be a string.");
+ correction: "Try converting the value to be a string.",
+ hasPublishedDocs: true);
/**
* No parameters.
@@ -188,7 +192,8 @@
static const PubspecWarningCode DEPENDENCIES_FIELD_NOT_MAP =
PubspecWarningCode('DEPENDENCIES_FIELD_NOT_MAP',
"The value of the '{0}' field is expected to be a map.",
- correction: "Try converting the value to be a map.");
+ correction: "Try converting the value to be a map.",
+ hasPublishedDocs: true);
/**
* No parameters.
@@ -221,7 +226,8 @@
static const PubspecWarningCode DEPRECATED_FIELD = PubspecWarningCode(
'DEPRECATED_FIELD',
"The '{0}' field is no longer used and can be removed.",
- correction: "Try removing the field.");
+ correction: "Try removing the field.",
+ hasPublishedDocs: true);
/**
* No parameters.
@@ -264,7 +270,8 @@
static const PubspecWarningCode FLUTTER_FIELD_NOT_MAP = PubspecWarningCode(
'FLUTTER_FIELD_NOT_MAP',
"The value of the 'flutter' field is expected to be a map.",
- correction: "Try converting the value to be a map.");
+ correction: "Try converting the value to be a map.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -320,7 +327,8 @@
"Publishable packages can't have '{0}' dependencies.",
correction:
"Try adding a 'publish_to: none' entry to mark the package as not "
- "for publishing or remove the {0} dependency.");
+ "for publishing or remove the {0} dependency.",
+ hasPublishedDocs: true);
/**
* No parameters.
@@ -353,7 +361,7 @@
// ```
static const PubspecWarningCode MISSING_NAME = PubspecWarningCode(
'MISSING_NAME', "The 'name' field is required but missing.",
- correction: "Try adding a field named 'name'.");
+ correction: "Try adding a field named 'name'.", hasPublishedDocs: true);
/**
* No parameters.
@@ -385,7 +393,8 @@
static const PubspecWarningCode NAME_NOT_STRING = PubspecWarningCode(
'NAME_NOT_STRING',
"The value of the 'name' field is required to be a string.",
- correction: "Try converting the value to be a string.");
+ correction: "Try converting the value to be a string.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -418,7 +427,8 @@
static const PubspecWarningCode PATH_DOES_NOT_EXIST = PubspecWarningCode(
'PATH_DOES_NOT_EXIST', "The path '{0}' doesn't exist.",
correction:
- "Try creating the referenced path or using a path that exists.");
+ "Try creating the referenced path or using a path that exists.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -447,7 +457,8 @@
// Convert the path to a POSIX path.
static const PubspecWarningCode PATH_NOT_POSIX = PubspecWarningCode(
'PATH_NOT_POSIX', "The path '{0}' isn't a POSIX-style path.",
- correction: "Try converting the value to a POSIX-style path.");
+ correction: "Try converting the value to a POSIX-style path.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -487,7 +498,8 @@
'PATH_PUBSPEC_DOES_NOT_EXIST',
"The directory '{0}' doesn't contain a pubspec.",
correction:
- "Try creating a pubspec in the referenced directory or using a path that has a pubspec.");
+ "Try creating a pubspec in the referenced directory or using a path that has a pubspec.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -530,16 +542,19 @@
'UNNECESSARY_DEV_DEPENDENCY',
"The dev dependency on {0} is unnecessary because there is also a "
"normal dependency on that package.",
- correction: "Try removing the dev dependency.");
+ correction: "Try removing the dev dependency.",
+ hasPublishedDocs: true);
/// Initialize a newly created warning code to have the given [name],
/// [message] and [correction].
- const PubspecWarningCode(String name, String message, {String? correction})
+ const PubspecWarningCode(String name, String message,
+ {String? correction, bool hasPublishedDocs = false})
: super(
correction: correction,
message: message,
name: name,
uniqueName: 'PubspecWarningCode.$name',
+ hasPublishedDocs: hasPublishedDocs,
);
@override
diff --git a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
index 1119f1d..430201e 100644
--- a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
+++ b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
@@ -405,6 +405,39 @@
''');
}
+ test_visitBinaryExpression_and_bool_false_invalid() async {
+ await resolveTestCode('''
+final a = false;
+const c = false && a;
+''');
+ DartObjectImpl result = _evaluateConstant('c', errorCodes: [
+ CompileTimeErrorCode.INVALID_CONSTANT,
+ ]);
+ _assertBoolValue(result, false);
+ }
+
+ test_visitBinaryExpression_and_bool_invalid_false() async {
+ await resolveTestCode('''
+final a = false;
+const c = a && false;
+''');
+ var result = _evaluateConstantOrNull('c', errorCodes: [
+ CompileTimeErrorCode.INVALID_CONSTANT,
+ ]);
+ expect(result, isNull);
+ }
+
+ test_visitBinaryExpression_and_bool_invalid_true() async {
+ await resolveTestCode('''
+final a = false;
+const c = a && true;
+''');
+ var result = _evaluateConstantOrNull('c', errorCodes: [
+ CompileTimeErrorCode.INVALID_CONSTANT,
+ ]);
+ expect(result, isNull);
+ }
+
test_visitBinaryExpression_and_bool_known_known() async {
await resolveTestCode('''
const c = false & true;
@@ -422,6 +455,18 @@
expect(result.type, typeProvider.boolType);
}
+ test_visitBinaryExpression_and_bool_true_invalid() async {
+ await resolveTestCode('''
+final a = false;
+const c = true && a;
+''');
+ var result = _evaluateConstantOrNull('c', errorCodes: [
+ CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL,
+ CompileTimeErrorCode.INVALID_CONSTANT,
+ ]);
+ expect(result, isNull);
+ }
+
test_visitBinaryExpression_and_bool_unknown_known() async {
await resolveTestCode('''
const a = bool.fromEnvironment('x');
@@ -457,6 +502,40 @@
errorCodes: [CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_INT]);
}
+ test_visitBinaryExpression_or_bool_false_invalid() async {
+ await resolveTestCode('''
+final a = false;
+const c = false || a;
+''');
+ var result = _evaluateConstantOrNull('c', errorCodes: [
+ CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL,
+ CompileTimeErrorCode.INVALID_CONSTANT,
+ ]);
+ expect(result, isNull);
+ }
+
+ test_visitBinaryExpression_or_bool_invalid_false() async {
+ await resolveTestCode('''
+final a = false;
+const c = a || false;
+''');
+ var result = _evaluateConstantOrNull('c', errorCodes: [
+ CompileTimeErrorCode.INVALID_CONSTANT,
+ ]);
+ expect(result, isNull);
+ }
+
+ test_visitBinaryExpression_or_bool_invalid_true() async {
+ await resolveTestCode('''
+final a = false;
+const c = a || true;
+''');
+ var result = _evaluateConstantOrNull('c', errorCodes: [
+ CompileTimeErrorCode.INVALID_CONSTANT,
+ ]);
+ expect(result, isNull);
+ }
+
test_visitBinaryExpression_or_bool_known_known() async {
await resolveTestCode('''
const c = false | true;
@@ -474,6 +553,17 @@
expect(result.type, typeProvider.boolType);
}
+ test_visitBinaryExpression_or_bool_true_invalid() async {
+ await resolveTestCode('''
+final a = false;
+const c = true || a;
+''');
+ var result = _evaluateConstant('c', errorCodes: [
+ CompileTimeErrorCode.INVALID_CONSTANT,
+ ]);
+ _assertBoolValue(result, true);
+ }
+
test_visitBinaryExpression_or_bool_unknown_known() async {
await resolveTestCode('''
const a = bool.fromEnvironment('x');
@@ -509,7 +599,29 @@
errorCodes: [CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_INT]);
}
- test_visitBinaryExpression_questionQuestion_eager_notNull_notNull() async {
+ test_visitBinaryExpression_questionQuestion_invalid_notNull() async {
+ await resolveTestCode('''
+final x = 0;
+const c = x ?? 1;
+''');
+ var result = _evaluateConstantOrNull('c', errorCodes: [
+ CompileTimeErrorCode.INVALID_CONSTANT,
+ ]);
+ expect(result, isNull);
+ }
+
+ test_visitBinaryExpression_questionQuestion_notNull_invalid() async {
+ await resolveTestCode('''
+final x = 1;
+const c = 0 ?? x;
+''');
+ var result = _evaluateConstant('c', errorCodes: [
+ CompileTimeErrorCode.INVALID_CONSTANT,
+ ]);
+ _assertIntValue(result, 0);
+ }
+
+ test_visitBinaryExpression_questionQuestion_notNull_notNull() async {
await resolveTestCode('''
const c = 'a' ?? 'b';
''');
@@ -518,43 +630,7 @@
expect(result.toStringValue(), 'a');
}
- test_visitBinaryExpression_questionQuestion_eager_null_notNull() async {
- await resolveTestCode('''
-const c = null ?? 'b';
-''');
- DartObjectImpl result = _evaluateConstant('c');
- expect(result.type, typeProvider.stringType);
- expect(result.toStringValue(), 'b');
- }
-
- test_visitBinaryExpression_questionQuestion_eager_null_null() async {
- await resolveTestCode('''
-const c = null ?? null;
-''');
- DartObjectImpl result = _evaluateConstant('c');
- expect(result.isNull, isTrue);
- }
-
- test_visitBinaryExpression_questionQuestion_lazy_notNull_invalid() async {
- await resolveTestCode('''
-const c = 'a' ?? new C();
-class C {}
-''');
- DartObjectImpl result = _evaluateConstant('c');
- expect(result.type, typeProvider.stringType);
- expect(result.toStringValue(), 'a');
- }
-
- test_visitBinaryExpression_questionQuestion_lazy_notNull_notNull() async {
- await resolveTestCode('''
-const c = 'a' ?? 'b';
-''');
- DartObjectImpl result = _evaluateConstant('c');
- expect(result.type, typeProvider.stringType);
- expect(result.toStringValue(), 'a');
- }
-
- test_visitBinaryExpression_questionQuestion_lazy_null_invalid() async {
+ test_visitBinaryExpression_questionQuestion_null_invalid() async {
await resolveTestCode('''
const c = null ?? new C();
class C {}
@@ -563,7 +639,7 @@
errorCodes: [CompileTimeErrorCode.INVALID_CONSTANT]);
}
- test_visitBinaryExpression_questionQuestion_lazy_null_notNull() async {
+ test_visitBinaryExpression_questionQuestion_null_notNull() async {
await resolveTestCode('''
const c = null ?? 'b';
''');
@@ -572,7 +648,7 @@
expect(result.toStringValue(), 'b');
}
- test_visitBinaryExpression_questionQuestion_lazy_null_null() async {
+ test_visitBinaryExpression_questionQuestion_null_null() async {
await resolveTestCode('''
const c = null ?? null;
''');
@@ -1082,6 +1158,16 @@
expect(result.toIntValue(), 3);
}
+ void _assertBoolValue(DartObjectImpl result, bool value) {
+ expect(result.type, typeProvider.boolType);
+ expect(result.toBoolValue(), value);
+ }
+
+ void _assertIntValue(DartObjectImpl result, int value) {
+ expect(result.type, typeProvider.intType);
+ expect(result.toIntValue(), value);
+ }
+
DartObjectImpl _boolValue(bool value) {
if (identical(value, false)) {
return DartObjectImpl(
diff --git a/pkg/analyzer/test/src/dart/constant/potentially_constant_test.dart b/pkg/analyzer/test/src/dart/constant/potentially_constant_test.dart
index 0552496..8328c57 100644
--- a/pkg/analyzer/test/src/dart/constant/potentially_constant_test.dart
+++ b/pkg/analyzer/test/src/dart/constant/potentially_constant_test.dart
@@ -222,6 +222,201 @@
''', () => _xInitializer());
}
+ test_binaryExpression_andEager_const_const() async {
+ await _assertConst(r'''
+const a = false;
+const b = false;
+var x = a & b;
+''', () => _xInitializer());
+ }
+
+ test_binaryExpression_andEager_const_notConst() async {
+ await _assertNotConst(r'''
+const a = false;
+final b = false;
+var x = a & b;
+''', () => _xInitializer(), () => [findNode.simple('b;')]);
+ }
+
+ test_binaryExpression_andEager_notConst_const() async {
+ await _assertNotConst(r'''
+final a = false;
+const b = false;
+var x = a & b;
+''', () => _xInitializer(), () => [findNode.simple('a &')]);
+ }
+
+ test_binaryExpression_andEager_notConst_notConst() async {
+ await _assertNotConst(
+ r'''
+final a = false;
+final b = false;
+var x = a & b;
+''',
+ () => _xInitializer(),
+ () => [
+ findNode.simple('a &'),
+ findNode.simple('b;'),
+ ],
+ );
+ }
+
+ test_binaryExpression_andLazy_const_const() async {
+ await _assertConst(r'''
+const a = false;
+const b = false;
+var x = a && b;
+''', () => _xInitializer());
+ }
+
+ test_binaryExpression_andLazy_const_notConst() async {
+ await _assertNotConst(r'''
+const a = false;
+final b = false;
+var x = a && b;
+''', () => _xInitializer(), () => [findNode.simple('b;')]);
+ }
+
+ test_binaryExpression_andLazy_notConst_const() async {
+ await _assertNotConst(r'''
+final a = false;
+const b = false;
+var x = a && b;
+''', () => _xInitializer(), () => [findNode.simple('a &')]);
+ }
+
+ test_binaryExpression_andLazy_notConst_notConst() async {
+ await _assertNotConst(
+ r'''
+final a = false;
+final b = false;
+var x = a && b;
+''',
+ () => _xInitializer(),
+ () => [
+ findNode.simple('a &'),
+ findNode.simple('b;'),
+ ],
+ );
+ }
+
+ test_binaryExpression_ifNull_const_const() async {
+ await _assertConst(r'''
+const a = 0;
+const b = 1;
+var x = a ?? b;
+''', () => _xInitializer());
+ }
+
+ test_binaryExpression_ifNull_const_notConst() async {
+ await _assertNotConst(r'''
+const a = 0;
+final b = 1;
+var x = a ?? b;
+''', () => _xInitializer(), () => [findNode.simple('b;')]);
+ }
+
+ test_binaryExpression_ifNull_notConst_const() async {
+ await _assertNotConst(r'''
+final a = 0;
+const b = 1;
+var x = a ?? b;
+''', () => _xInitializer(), () => [findNode.simple('a ??')]);
+ }
+
+ test_binaryExpression_ifNull_notConst_notConst() async {
+ await _assertNotConst(
+ r'''
+final a = 0;
+final b = 1;
+var x = a ?? b;
+''',
+ () => _xInitializer(),
+ () => [
+ findNode.simple('a ??'),
+ findNode.simple('b;'),
+ ],
+ );
+ }
+
+ test_binaryExpression_orEager_const_const() async {
+ await _assertConst(r'''
+const a = false;
+const b = false;
+var x = a | b;
+''', () => _xInitializer());
+ }
+
+ test_binaryExpression_orEager_const_notConst() async {
+ await _assertNotConst(r'''
+const a = false;
+final b = false;
+var x = a | b;
+''', () => _xInitializer(), () => [findNode.simple('b;')]);
+ }
+
+ test_binaryExpression_orEager_notConst_const() async {
+ await _assertNotConst(r'''
+final a = false;
+const b = false;
+var x = a | b;
+''', () => _xInitializer(), () => [findNode.simple('a |')]);
+ }
+
+ test_binaryExpression_orEager_notConst_notConst() async {
+ await _assertNotConst(
+ r'''
+final a = false;
+final b = false;
+var x = a | b;
+''',
+ () => _xInitializer(),
+ () => [
+ findNode.simple('a |'),
+ findNode.simple('b;'),
+ ],
+ );
+ }
+
+ test_binaryExpression_orLazy_const_const() async {
+ await _assertConst(r'''
+const a = false;
+const b = false;
+var x = a || b;
+''', () => _xInitializer());
+ }
+
+ test_binaryExpression_orLazy_const_notConst() async {
+ await _assertNotConst(r'''
+const a = false;
+final b = false;
+var x = a || b;
+''', () => _xInitializer(), () => [findNode.simple('b;')]);
+ }
+
+ test_binaryExpression_orLazy_notConst_const() async {
+ await _assertNotConst(r'''
+final a = false;
+const b = false;
+var x = a || b;
+''', () => _xInitializer(), () => [findNode.simple('a |')]);
+ }
+
+ test_binaryExpression_orLazy_notConst_notConst() async {
+ await _assertNotConst(
+ r'''
+final a = false;
+final b = false;
+var x = a || b;
+''',
+ () => _xInitializer(),
+ () => [
+ findNode.simple('a |'),
+ findNode.simple('b;'),
+ ],
+ );
+ }
+
test_conditional() async {
await _assertConst(r'''
const a = 0;
diff --git a/pkg/analyzer/test/verify_diagnostics_test.dart b/pkg/analyzer/test/verify_diagnostics_test.dart
index 5222636..bc22b3b 100644
--- a/pkg/analyzer/test/verify_diagnostics_test.dart
+++ b/pkg/analyzer/test/verify_diagnostics_test.dart
@@ -447,6 +447,41 @@
}
}
}
+
+ @soloTest
+ test_published() {
+ // Verify that if _any_ error code is marked as having published docs then
+ // _all_ codes with the same name are also marked that way.
+ var nameToCodeMap = <String, List<ErrorCode>>{};
+ var nameToPublishedMap = <String, bool>{};
+ for (var code in errorCodeValues) {
+ var name = code.name;
+ nameToCodeMap.putIfAbsent(name, () => []).add(code);
+ nameToPublishedMap[name] =
+ (nameToPublishedMap[name] ?? false) || code.hasPublishedDocs;
+ }
+ var unpublished = <ErrorCode>[];
+ for (var entry in nameToCodeMap.entries) {
+ var name = entry.key;
+ if (nameToPublishedMap[name]!) {
+ for (var code in entry.value) {
+ if (!code.hasPublishedDocs) {
+ unpublished.add(code);
+ }
+ }
+ }
+ }
+ if (unpublished.isNotEmpty) {
+ var buffer = StringBuffer();
+ buffer.write("The following error codes have published docs but aren't "
+ "marked as such:");
+ for (var code in unpublished) {
+ buffer.writeln();
+ buffer.write('- ${code.runtimeType}.${code.uniqueName}');
+ }
+ fail(buffer.toString());
+ }
+ }
}
/// A data holder used to return multiple values when extracting an error range
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index 771756b..7ff044b 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -52,11 +52,6 @@
static const String experimentNewRti = '--experiment-new-rti';
- /// Use the dart2js lowering of late instance variables rather than the CFE
- /// lowering.
- static const String experimentLateInstanceVariables =
- '--experiment-late-instance-variables';
-
static const String enableLanguageExperiments = '--enable-experiment';
static const String fastStartup = '--fast-startup';
diff --git a/pkg/compiler/lib/src/common_elements.dart b/pkg/compiler/lib/src/common_elements.dart
index adbf857..c8cd6d7 100644
--- a/pkg/compiler/lib/src/common_elements.dart
+++ b/pkg/compiler/lib/src/common_elements.dart
@@ -646,6 +646,10 @@
bool isForeign(MemberEntity element);
+ /// Returns `true` if [member] is the `createSentinel` function defined in
+ /// dart:_internal.
+ bool isCreateSentinel(MemberEntity element);
+
/// Returns `true` if the implementation of the 'operator ==' [function] is
/// known to handle `null` as argument.
bool operatorEqHandlesNullArgument(FunctionEntity function);
@@ -2147,6 +2151,14 @@
}
@override
+ bool isCreateSentinel(MemberEntity member) {
+ return member.isTopLevel &&
+ member.isFunction &&
+ member.library == internalLibrary &&
+ member.name == 'createSentinel';
+ }
+
+ @override
bool operatorEqHandlesNullArgument(FunctionEntity function) {
assert(function.name == '==',
failedAt(function, "Unexpected function $function."));
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index f62a0c8..8907305 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -602,7 +602,6 @@
new OptionHandler(Flags.experimentUnreachableMethodsThrow, passThrough),
new OptionHandler(Flags.experimentCallInstrumentation, passThrough),
new OptionHandler(Flags.experimentNewRti, ignoreOption),
- new OptionHandler(Flags.experimentLateInstanceVariables, passThrough),
new OptionHandler('${Flags.mergeFragmentsThreshold}=.+', passThrough),
// Wire up feature flags.
@@ -1035,7 +1034,8 @@
if (uri.scheme != 'file') {
fail('Unhandled scheme ${uri.scheme}.');
}
- var file = new File(uri.toFilePath()).openSync(mode: FileMode.write);
+ var file = (File(uri.toFilePath())..createSync(recursive: true))
+ .openSync(mode: FileMode.write);
file.writeStringSync(text);
file.closeSync();
}
diff --git a/pkg/compiler/lib/src/inferrer/builder_kernel.dart b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
index 40e1ebe..3a35294 100644
--- a/pkg/compiler/lib/src/inferrer/builder_kernel.dart
+++ b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
@@ -1548,6 +1548,27 @@
Selector selector = _elementMap.getSelector(node);
if (_closedWorld.commonElements.isForeign(member)) {
return handleForeignInvoke(node, member, arguments, selector);
+ } else if (_closedWorld.commonElements.isCreateSentinel(member)) {
+ // `T createSentinel<T>()` ostensibly returns a `T` based on its static
+ // type. However, we need to handle this specially for a couple of
+ // reasons:
+ // 1. We do not currently handle type arguments during type inference and
+ // in the abstract value domain. Without additional tracing, this means
+ // that we lose all call-site sensitivity and `createSentinel` is seen
+ // as returning `Object?`, which widens the inferred types of late
+ // fields, resulting in poor codegen.
+ // 2. The sentinel isn't a real Dart value and doesn't really inhabit any
+ // Dart type. Nevertheless, we must view it as inhabiting every Dart
+ // type for the signature of `createSentinel` to make sense, making it
+ // a bottom value (similar to an expression of type `Never`). This
+ // matches the expectation that reading an uninitialized late field
+ // (that is, one initialized with the sentinel value) throws.
+ // Note that this currently breaks if `--experiment-unreachable-throw` is
+ // used. We'll be able to do something more precise here when more of the
+ // lowering is deferred to SSA and the abstract value domain can better
+ // track sentinel values.
+ handleStaticInvoke(node, selector, member, arguments);
+ return _types.nonNullEmptyType;
} else if (member.isConstructor) {
return handleConstructorInvoke(
node, node.arguments, selector, member, arguments);
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
index c4fcf53..7d3ea98 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
@@ -877,7 +877,9 @@
for (StaticMethod method in library.statics) {
Map<js.Name, js.Expression> propertyMap = emitStaticMethod(method);
propertyMap.forEach((js.Name key, js.Expression value) {
- var property = new js.Property(js.quoteName(key), value);
+ var property = _options.features.legacyJavaScript.isEnabled
+ ? js.Property(js.quoteName(key), value)
+ : js.MethodDefinition(js.quoteName(key), value);
Entity holderKey;
if (method is StaticStubMethod) {
// [StaticStubMethod]s should only be created for interceptors.
diff --git a/pkg/compiler/lib/src/kernel/dart2js_target.dart b/pkg/compiler/lib/src/kernel/dart2js_target.dart
index f939fe1..a1b5307 100644
--- a/pkg/compiler/lib/src/kernel/dart2js_target.dart
+++ b/pkg/compiler/lib/src/kernel/dart2js_target.dart
@@ -58,19 +58,6 @@
return allowedNativeTest(uri) || allowedDartLibrary();
}
-int _foldLateLowerings(List<int> lowerings) =>
- lowerings.fold(LateLowering.none, (a, b) => a | b);
-
-/// Late lowerings which the frontend performs for dart2js.
-const List<int> _allEnabledLateLowerings = [
- LateLowering.uninitializedNonFinalInstanceField,
- LateLowering.uninitializedFinalInstanceField,
- LateLowering.initializedNonFinalInstanceField,
- LateLowering.initializedFinalInstanceField,
-];
-
-final int _enabledLateLowerings = _foldLateLowerings(_allEnabledLateLowerings);
-
/// A kernel [Target] to configure the Dart Front End for dart2js.
class Dart2jsTarget extends Target {
@override
@@ -88,10 +75,7 @@
bool get enableNoSuchMethodForwarders => true;
@override
- int get enabledLateLowerings =>
- (options != null && options.experimentLateInstanceVariables)
- ? LateLowering.none
- : _enabledLateLowerings;
+ int get enabledLateLowerings => LateLowering.none;
@override
bool get supportsLateLoweringSentinel => true;
diff --git a/pkg/compiler/lib/src/kernel/transformations/late_lowering.dart b/pkg/compiler/lib/src/kernel/transformations/late_lowering.dart
index 210bbcb..faab75d 100644
--- a/pkg/compiler/lib/src/kernel/transformations/late_lowering.dart
+++ b/pkg/compiler/lib/src/kernel/transformations/late_lowering.dart
@@ -22,7 +22,6 @@
final CoreTypes _coreTypes;
final bool _omitLateNames;
- final bool _lowerInstanceVariables;
final _Reader _readLocal;
final _Reader _readField;
@@ -48,8 +47,6 @@
LateLowering(this._coreTypes, CompilerOptions _options)
: _omitLateNames = _options?.omitLateNames ?? false,
- _lowerInstanceVariables =
- _options?.experimentLateInstanceVariables ?? false,
_readLocal = _Reader(_coreTypes.cellReadLocal),
_readField = _Reader(_coreTypes.cellReadField),
_readInitialized = _Reader(_coreTypes.initializedCellRead),
@@ -69,7 +66,7 @@
field.isLate && field.isStatic && field.initializer == null;
bool _shouldLowerInstanceField(Field field) =>
- field.isLate && !field.isStatic && _lowerInstanceVariables;
+ field.isLate && !field.isStatic;
String _mangleFieldName(Field field) {
assert(_shouldLowerInstanceField(field));
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index 5c89ed6..4a8640f 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -471,10 +471,6 @@
/// called.
bool experimentCallInstrumentation = false;
- /// Use the dart2js lowering of late instance variables rather than the CFE
- /// lowering.
- bool experimentLateInstanceVariables = false;
-
/// When null-safety is enabled, whether the compiler should emit code with
/// unsound or sound semantics.
///
@@ -599,8 +595,6 @@
_hasOption(options, Flags.experimentUnreachableMethodsThrow)
..experimentCallInstrumentation =
_hasOption(options, Flags.experimentCallInstrumentation)
- ..experimentLateInstanceVariables =
- _hasOption(options, Flags.experimentLateInstanceVariables)
..generateSourceMap = !_hasOption(options, Flags.noSourceMaps)
..outputUri = _extractUriOption(options, '--out=')
..platformBinaries = platformBinaries
diff --git a/pkg/compiler/lib/src/source_file_provider.dart b/pkg/compiler/lib/src/source_file_provider.dart
index 9a7fe7f..54da609 100644
--- a/pkg/compiler/lib/src/source_file_provider.dart
+++ b/pkg/compiler/lib/src/source_file_provider.dart
@@ -159,7 +159,7 @@
}
List<int> readAll(String filename, {bool zeroTerminated: true}) {
- RandomAccessFile file = (new File(filename)).openSync();
+ RandomAccessFile file = File(filename).openSync();
int length = file.lengthSync();
int bufferLength = length;
if (zeroTerminated) {
@@ -386,7 +386,8 @@
RandomAccessFile output;
try {
- output = new File(uri.toFilePath()).openSync(mode: FileMode.write);
+ output = (File(uri.toFilePath())..createSync(recursive: true))
+ .openSync(mode: FileMode.write);
} on FileSystemException catch (e) {
onFailure('$e');
}
@@ -434,7 +435,8 @@
RandomAccessFile output;
try {
- output = new File(uri.toFilePath()).openSync(mode: FileMode.write);
+ output = (File(uri.toFilePath())..createSync(recursive: true))
+ .openSync(mode: FileMode.write);
} on FileSystemException catch (e) {
onFailure('$e');
}
diff --git a/pkg/compiler/test/end_to_end/bad_output_io_test.dart b/pkg/compiler/test/end_to_end/bad_output_io_test.dart
deleted file mode 100644
index ccacc18..0000000
--- a/pkg/compiler/test/end_to_end/bad_output_io_test.dart
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright (c) 2013, 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.7
-
-// TODO(johnniwinther): Port this test to use '--use-kernel'.
-
-// Test that the compiler can handle imports when package root has not been set.
-
-library dart2js.test.bad_output_io;
-
-import 'dart:async' show Future;
-import 'dart:io' show exit;
-import 'package:expect/expect.dart';
-
-import 'package:compiler/compiler.dart' show Diagnostic;
-import 'package:compiler/compiler_new.dart'
- show
- CompilationResult,
- CompilerDiagnostics,
- CompilerInput,
- CompilerOutput,
- OutputType;
-import 'package:compiler/src/dart2js.dart'
- show exitFunc, compileFunc, compile, diagnosticHandler;
-import 'package:compiler/src/source_file_provider.dart'
- show FormattingDiagnosticHandler;
-
-import 'package:compiler/src/options.dart' show CompilerOptions;
-
-class CollectingFormattingDiagnosticHandler
- implements FormattingDiagnosticHandler {
- @override
- final provider = null;
- @override
- bool showWarnings = true;
- @override
- bool showHints = true;
- @override
- bool verbose = true;
- @override
- bool isAborting = false;
- @override
- bool enableColors = false;
- @override
- bool throwOnError = false;
- @override
- bool autoReadFileUri = false;
- @override
- var lastKind = null;
-
- @override
- final int FATAL = 0;
- @override
- final int INFO = 1;
-
- final messages = [];
-
- @override
- void info(var message, [kind = Diagnostic.VERBOSE_INFO]) {
- messages.add([message, kind]);
- }
-
- @override
- void report(var code, Uri uri, int begin, int end, String message, kind) {
- messages.add([message, kind]);
- }
-
- @override
- void call(Uri uri, int begin, int end, String message, kind) {
- report(null, uri, begin, end, message, kind);
- }
-
- @override
- String prefixMessage(String message, Diagnostic kind) {
- return message;
- }
-
- @override
- int fatalCount;
-
- @override
- int throwOnErrorCount;
-}
-
-Future<CompilationResult> testOutputProvider(
- CompilerOptions options,
- CompilerInput input,
- CompilerDiagnostics diagnostics,
- CompilerOutput output) {
- diagnosticHandler = new CollectingFormattingDiagnosticHandler();
- output.createOutputSink(
- "/non/existing/directory/should/fail/file", "js", OutputType.js);
- return null;
-}
-
-void main() {
- compileFunc = testOutputProvider;
- exitFunc = (exitCode) {
- CollectingFormattingDiagnosticHandler handler = diagnosticHandler;
- Expect.equals(1, handler.messages.length);
- var message = handler.messages[0];
- Expect.isTrue(message[0].contains("Cannot open file"));
- Expect.equals(Diagnostic.ERROR, message[1]);
- Expect.equals(1, exitCode);
- exit(0);
- };
- compile(["foo.dart", "--out=bar.dart"]);
-}
diff --git a/pkg/dds/lib/src/dap/adapters/dart.dart b/pkg/dds/lib/src/dap/adapters/dart.dart
index 8730cb1..d7811e0 100644
--- a/pkg/dds/lib/src/dap/adapters/dart.dart
+++ b/pkg/dds/lib/src/dap/adapters/dart.dart
@@ -105,6 +105,9 @@
/// yet been made.
DartDevelopmentService? _dds;
+ /// Whether to use IPv6 for DAP/Debugger services.
+ final bool ipv6;
+
/// Whether to enable DDS for launched applications.
final bool enableDds;
@@ -121,6 +124,7 @@
DartDebugAdapter(
ByteStreamServerChannel channel, {
+ this.ipv6 = false,
this.enableDds = true,
this.enableAuthCodes = true,
this.logger,
@@ -194,8 +198,8 @@
logger?.call('Starting a DDS instance for $uri');
final dds = await DartDevelopmentService.startDartDevelopmentService(
uri,
- // TODO(dantup): Allow this to be disabled?
- enableAuthCodes: true,
+ enableAuthCodes: enableAuthCodes,
+ ipv6: ipv6,
);
_dds = dds;
uri = dds.wsUri!;
diff --git a/pkg/dds/lib/src/dap/adapters/dart_cli.dart b/pkg/dds/lib/src/dap/adapters/dart_cli.dart
index 6a01c8c..b0fd701 100644
--- a/pkg/dds/lib/src/dap/adapters/dart_cli.dart
+++ b/pkg/dds/lib/src/dap/adapters/dart_cli.dart
@@ -43,11 +43,13 @@
DartCliDebugAdapter(
ByteStreamServerChannel channel, {
+ bool ipv6 = false,
bool enableDds = true,
bool enableAuthCodes = true,
Logger? logger,
}) : super(
channel,
+ ipv6: ipv6,
enableDds: enableDds,
enableAuthCodes: enableAuthCodes,
logger: logger,
@@ -109,7 +111,7 @@
final vmServiceInfoFile = _vmServiceInfoFile;
final vmArgs = <String>[
if (debug) ...[
- '--enable-vm-service=${args.vmServicePort ?? 0}',
+ '--enable-vm-service=${args.vmServicePort ?? 0}${ipv6 ? '/::1' : ''}',
'--pause_isolates_on_start=true',
if (!enableAuthCodes) '--disable-service-auth-codes'
],
diff --git a/pkg/dds/lib/src/dap/server.dart b/pkg/dds/lib/src/dap/server.dart
index 2fe4ac5..f2530a3 100644
--- a/pkg/dds/lib/src/dap/server.dart
+++ b/pkg/dds/lib/src/dap/server.dart
@@ -16,6 +16,7 @@
/// A DAP server that binds to a port and runs in multi-session mode.
class DapServer {
final ServerSocket _socket;
+ final bool ipv6;
final bool enableDds;
final bool enableAuthCodes;
final Logger? logger;
@@ -24,6 +25,7 @@
DapServer._(
this._socket, {
+ this.ipv6 = false,
this.enableDds = true,
this.enableAuthCodes = true,
this.logger,
@@ -55,6 +57,7 @@
final channel = ByteStreamServerChannel(_input, _output, logger);
final adapter = DartCliDebugAdapter(
channel,
+ ipv6: ipv6,
enableDds: enableDds,
enableAuthCodes: enableAuthCodes,
logger: logger,
@@ -70,15 +73,19 @@
/// Starts a DAP Server listening on [host]:[port].
static Future<DapServer> create({
- String host = 'localhost',
+ String? host,
int port = 0,
+ bool ipv6 = false,
bool enableDdds = true,
bool enableAuthCodes = true,
Logger? logger,
}) async {
- final _socket = await ServerSocket.bind(host, port);
+ final hostFallback =
+ ipv6 ? InternetAddress.loopbackIPv6 : InternetAddress.loopbackIPv4;
+ final _socket = await ServerSocket.bind(host ?? hostFallback, port);
return DapServer._(
_socket,
+ ipv6: ipv6,
enableDds: enableDdds,
enableAuthCodes: enableAuthCodes,
logger: logger,
diff --git a/pkg/dds/test/dap/integration/debug_breakpoints_test.dart b/pkg/dds/test/dap/integration/debug_breakpoints_test.dart
index 6e1744c..9a50b03 100644
--- a/pkg/dds/test/dap/integration/debug_breakpoints_test.dart
+++ b/pkg/dds/test/dap/integration/debug_breakpoints_test.dart
@@ -5,6 +5,7 @@
import 'package:test/test.dart';
import 'test_client.dart';
+import 'test_scripts.dart';
import 'test_support.dart';
main() {
@@ -12,11 +13,7 @@
group('debug mode breakpoints', () {
test('stops at a line breakpoint', () async {
final client = dap.client;
- final testFile = dap.createTestFile(r'''
-void main(List<String> args) async {
- print('Hello!'); // BREAKPOINT
-}
- ''');
+ final testFile = dap.createTestFile(simpleBreakpointProgram);
final breakpointLine = lineWith(testFile, '// BREAKPOINT');
await client.hitBreakpoint(testFile, breakpointLine);
@@ -24,11 +21,7 @@
test('stops at a line breakpoint and can be resumed', () async {
final client = dap.client;
- final testFile = dap.createTestFile(r'''
-void main(List<String> args) async {
- print('Hello!'); // BREAKPOINT
-}
- ''');
+ final testFile = dap.createTestFile(simpleBreakpointProgram);
final breakpointLine = lineWith(testFile, '// BREAKPOINT');
// Hit the initial breakpoint.
diff --git a/pkg/dds/test/dap/integration/debug_eval_test.dart b/pkg/dds/test/dap/integration/debug_eval_test.dart
index 00a4408..9b59310 100644
--- a/pkg/dds/test/dap/integration/debug_eval_test.dart
+++ b/pkg/dds/test/dap/integration/debug_eval_test.dart
@@ -6,6 +6,7 @@
import 'package:test/test.dart';
import 'test_client.dart';
+import 'test_scripts.dart';
import 'test_support.dart';
main() {
@@ -30,10 +31,7 @@
test('evaluates expressions with complex results', () async {
final client = dap.client;
- final testFile = await dap.createTestFile(r'''
-void main(List<String> args) {
- print('Hello!'); // BREAKPOINT
-}''');
+ final testFile = await dap.createTestFile(simpleBreakpointProgram);
final breakpointLine = lineWith(testFile, '// BREAKPOINT');
final stop = await client.hitBreakpoint(testFile, breakpointLine);
@@ -57,10 +55,7 @@
'evaluates complex expressions expressions with evaluateToStringInDebugViews=true',
() async {
final client = dap.client;
- final testFile = await dap.createTestFile(r'''
-void main(List<String> args) {
- print('Hello!'); // BREAKPOINT
-}''');
+ final testFile = await dap.createTestFile(simpleBreakpointProgram);
final breakpointLine = lineWith(testFile, '// BREAKPOINT');
final stop = await client.hitBreakpoint(
diff --git a/pkg/dds/test/dap/integration/debug_test.dart b/pkg/dds/test/dap/integration/debug_test.dart
index ded4663..7b80af0 100644
--- a/pkg/dds/test/dap/integration/debug_test.dart
+++ b/pkg/dds/test/dap/integration/debug_test.dart
@@ -6,6 +6,7 @@
import 'package:test/test.dart';
import 'test_client.dart';
+import 'test_scripts.dart';
import 'test_support.dart';
main() {
@@ -47,11 +48,7 @@
test('provides a list of threads', () async {
final client = dap.client;
- final testFile = dap.createTestFile(r'''
-void main(List<String> args) async {
- print('Hello!'); // BREAKPOINT
-}
- ''');
+ final testFile = dap.createTestFile(simpleBreakpointProgram);
final breakpointLine = lineWith(testFile, '// BREAKPOINT');
await client.hitBreakpoint(testFile, breakpointLine);
@@ -63,11 +60,7 @@
test('runs with DDS', () async {
final client = dap.client;
- final testFile = dap.createTestFile(r'''
-void main(List<String> args) async {
- print('Hello!'); // BREAKPOINT
-}
- ''');
+ final testFile = dap.createTestFile(simpleBreakpointProgram);
final breakpointLine = lineWith(testFile, '// BREAKPOINT');
await client.hitBreakpoint(testFile, breakpointLine);
@@ -77,9 +70,7 @@
}, timeout: Timeout.none);
test('runs with auth codes enabled', () async {
- final testFile = dap.createTestFile(r'''
-void main(List<String> args) {}
- ''');
+ final testFile = dap.createTestFile(emptyProgram);
final outputEvents = await dap.client.collectOutput(file: testFile);
expect(_hasAuthCode(outputEvents.first), isTrue);
@@ -90,11 +81,7 @@
group('debug mode', () {
test('runs without DDS', () async {
final client = dap.client;
- final testFile = dap.createTestFile(r'''
-void main(List<String> args) async {
- print('Hello!'); // BREAKPOINT
-}
- ''');
+ final testFile = dap.createTestFile(simpleBreakpointProgram);
final breakpointLine = lineWith(testFile, '// BREAKPOINT');
await client.hitBreakpoint(testFile, breakpointLine);
@@ -103,9 +90,7 @@
});
test('runs with auth tokens disabled', () async {
- final testFile = dap.createTestFile(r'''
-void main(List<String> args) {}
- ''');
+ final testFile = dap.createTestFile(emptyProgram);
final outputEvents = await dap.client.collectOutput(file: testFile);
expect(_hasAuthCode(outputEvents.first), isFalse);
@@ -113,18 +98,39 @@
// These tests can be slow due to starting up the external server process.
}, timeout: Timeout.none);
}, additionalArgs: ['--no-dds', '--no-auth-codes']);
+
+ testDap((dap) async {
+ group('debug mode', () {
+ test('can run with ipv6', () async {
+ final testFile = dap.createTestFile(emptyProgram);
+
+ final outputEvents = await dap.client.collectOutput(file: testFile);
+ final vmServiceUri = _extractVmServiceUri(outputEvents.first);
+
+ // Check DAP server host.
+ expect(dap.server.host, equals('::1'));
+ // Check VM Service/DDS host.
+ expect(vmServiceUri.host, equals('::1'));
+ });
+ // These tests can be slow due to starting up the external server process.
+ }, timeout: Timeout.none);
+ }, additionalArgs: ['--ipv6']);
+}
+
+/// Extracts the VM Service URI from the "Connecting to ..." banner output by
+/// the DAP server upon connection.
+Uri _extractVmServiceUri(OutputEventBody vmConnectionBanner) {
+ // TODO(dantup): Change this to use the dart.debuggerUris custom event
+ // if implemented (whch VS Code also needs).
+ final vmServiceUriPattern = RegExp(r'Connecting to VM Service at ([^\s]+)\s');
+ final match = vmServiceUriPattern.firstMatch(vmConnectionBanner.output);
+ return Uri.parse(match!.group(1)!);
}
/// Checks for the presence of an auth token in a VM Service URI in the
/// "Connecting to VM Service" [OutputEvent].
-bool _hasAuthCode(OutputEventBody vmConnection) {
- // TODO(dantup): Change this to use the dart.debuggerUris custom event
- // if implemented (whch VS Code also needs).
- final vmServiceUriPattern = RegExp(r'Connecting to VM Service at ([^\s]+)\s');
- final authCodePattern = RegExp(r'ws://127.0.0.1:\d+/[\w=]{5,15}/ws');
-
- final vmServiceUri =
- vmServiceUriPattern.firstMatch(vmConnection.output)!.group(1);
-
- return vmServiceUri != null && authCodePattern.hasMatch(vmServiceUri);
+bool _hasAuthCode(OutputEventBody vmConnectionBanner) {
+ final vmServiceUri = _extractVmServiceUri(vmConnectionBanner);
+ final authCodePattern = RegExp(r'^/[\w=]{5,15}/ws');
+ return authCodePattern.hasMatch(vmServiceUri.path);
}
diff --git a/pkg/dds/test/dap/integration/test_client.dart b/pkg/dds/test/dap/integration/test_client.dart
index 0bc4afe..c130e00 100644
--- a/pkg/dds/test/dap/integration/test_client.dart
+++ b/pkg/dds/test/dap/integration/test_client.dart
@@ -305,8 +305,8 @@
/// Creates a [DapTestClient] that connects the server listening on
/// [host]:[port].
static Future<DapTestClient> connect(
+ String host,
int port, {
- String host = 'localhost',
bool captureVmServiceTraffic = false,
Logger? logger,
}) async {
diff --git a/pkg/dds/test/dap/integration/test_scripts.dart b/pkg/dds/test/dap/integration/test_scripts.dart
new file mode 100644
index 0000000..6b6a05b
--- /dev/null
+++ b/pkg/dds/test/dap/integration/test_scripts.dart
@@ -0,0 +1,17 @@
+// 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.
+
+/// A simple empty Dart script that should run with no output and no errors.
+const emptyProgram = '''
+ void main(List<String> args) {}
+''';
+
+/// A simple Dart script that should run with no errors and contains a comment
+/// marker '// BREAKPOINT' for use in tests that require stopping at a breakpoint
+/// but require no other context.
+const simpleBreakpointProgram = r'''
+ void main(List<String> args) async {
+ print('Hello!'); // BREAKPOINT
+ }
+''';
diff --git a/pkg/dds/test/dap/integration/test_support.dart b/pkg/dds/test/dap/integration/test_support.dart
index 3b1d3ab..45460b2 100644
--- a/pkg/dds/test/dap/integration/test_support.dart
+++ b/pkg/dds/test/dap/integration/test_support.dart
@@ -110,7 +110,7 @@
var attempt = 1;
while (attempt++ <= 100) {
try {
- return await DapTestClient.connect(server.port);
+ return await DapTestClient.connect(server.host, server.port);
} catch (e) {
await Future.delayed(const Duration(milliseconds: 200));
}
diff --git a/pkg/dds/tool/dap/run_server.dart b/pkg/dds/tool/dap/run_server.dart
index b35a46d..5fd19f2 100644
--- a/pkg/dds/tool/dap/run_server.dart
+++ b/pkg/dds/tool/dap/run_server.dart
@@ -25,6 +25,7 @@
class DapCommand extends Command {
static const argHost = 'host';
static const argPort = 'port';
+ static const argIpv6 = 'ipv6';
static const argDds = 'dds';
static const argAuthCodes = 'auth-codes';
static const argVerbose = 'verbose';
@@ -39,8 +40,9 @@
argParser
..addOption(
argHost,
- defaultsTo: 'localhost',
- help: 'The hostname/IP to bind the server to',
+ help: 'The hostname/IP to bind the server to. If not supplied, will'
+ ' use the appropriate loopback address depending on whether'
+ ' --ipv6 is set',
)
..addOption(
argPort,
@@ -49,6 +51,10 @@
help: 'The port to bind the server to',
)
..addFlag(
+ argIpv6,
+ help: 'Whether to bind DAP/VM Service/DDS to IPv6 addresses',
+ )
+ ..addFlag(
argDds,
defaultsTo: true,
help: 'Whether to enable DDS for debug sessions',
@@ -69,10 +75,12 @@
final args = argResults!;
final port = int.parse(args[argPort]);
final host = args[argHost];
+ final ipv6 = args[argIpv6] as bool;
final server = await DapServer.create(
host: host,
port: port,
+ ipv6: ipv6,
enableDdds: args[argDds],
enableAuthCodes: args[argAuthCodes],
logger: args[argVerbose] ? print : null,
diff --git a/pkg/front_end/testcases/dart2js/late_fields.dart.strong.expect b/pkg/front_end/testcases/dart2js/late_fields.dart.strong.expect
index 0c0fa5a..ee029897 100644
--- a/pkg/front_end/testcases/dart2js/late_fields.dart.strong.expect
+++ b/pkg/front_end/testcases/dart2js/late_fields.dart.strong.expect
@@ -1,33 +1,15 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
-import "dart:_internal" as _in;
class C extends core::Object {
- field core::int? _#C#a = null;
- field core::int? _#C#b = null;
- field core::int? _#C#c = null;
- field core::int? _#C#d = null;
+ late field core::int a;
+ late final [setter] field core::int b;
+ late field core::int c = 1.{core::int::unary-}(){() → core::int};
+ late final field core::int d = 1.{core::int::unary-}(){() → core::int};
synthetic constructor •() → self::C
: super core::Object::•()
;
- get a() → core::int
- return let final core::int? #t1 = this.{self::C::_#C#a}{core::int?} in #t1 == null ?{core::int} throw new _in::LateError::fieldNI("a") : #t1{core::int};
- set a(core::int #t2) → void
- this.{self::C::_#C#a} = #t2;
- get b() → core::int
- return let final core::int? #t3 = this.{self::C::_#C#b}{core::int?} in #t3 == null ?{core::int} throw new _in::LateError::fieldNI("b") : #t3{core::int};
- set b(core::int #t4) → void
- if(this.{self::C::_#C#b}{core::int?} == null)
- this.{self::C::_#C#b} = #t4;
- else
- throw new _in::LateError::fieldAI("b");
- get c() → core::int
- return let final core::int? #t5 = this.{self::C::_#C#c}{core::int?} in #t5 == null ?{core::int} this.{self::C::_#C#c} = 1.{core::int::unary-}(){() → core::int} : #t5{core::int};
- set c(core::int #t6) → void
- this.{self::C::_#C#c} = #t6;
- get d() → core::int
- return let final core::int? #t7 = this.{self::C::_#C#d}{core::int?} in #t7 == null ?{core::int} let final core::int #t8 = 1.{core::int::unary-}(){() → core::int} in this.{self::C::_#C#d}{core::int?} == null ?{core::int} this.{self::C::_#C#d} = #t8 : throw new _in::LateError::fieldADI("d") : #t7{core::int};
}
static field self::C c = new self::C::•();
static method main() → void {
diff --git a/pkg/front_end/testcases/dart2js/late_fields.dart.strong.transformed.expect b/pkg/front_end/testcases/dart2js/late_fields.dart.strong.transformed.expect
index e162d20..25ca1b2 100644
--- a/pkg/front_end/testcases/dart2js/late_fields.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/dart2js/late_fields.dart.strong.transformed.expect
@@ -1,33 +1,44 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
+import "dart:_late_helper" as _la;
import "dart:_internal" as _in;
class C extends core::Object {
- field core::int? _#C#a = null;
- field core::int? _#C#b = null;
- field core::int? _#C#c = null;
- field core::int? _#C#d = null;
+ field core::int _#C#a = _in::createSentinel<core::int>();
+ field core::int _#C#b = _in::createSentinel<core::int>();
+ field core::int _#C#c = _in::createSentinel<core::int>();
+ field core::int _#C#d = _in::createSentinel<core::int>();
synthetic constructor •() → self::C
: super core::Object::•()
;
get a() → core::int
- return let final core::int? #t1 = this.{self::C::_#C#a}{core::int?} in #t1 == null ?{core::int} throw new _in::LateError::fieldNI("a") : #t1{core::int};
- set a(core::int #t2) → void
- this.{self::C::_#C#a} = #t2;
+ return _la::_lateReadCheck<core::int>(this.{self::C::_#C#a}{core::int}, "a");
+ set a(core::int value) → void
+ this.{self::C::_#C#a} = value;
get b() → core::int
- return let final core::int? #t3 = this.{self::C::_#C#b}{core::int?} in #t3 == null ?{core::int} throw new _in::LateError::fieldNI("b") : #t3{core::int};
- set b(core::int #t4) → void
- if(this.{self::C::_#C#b}{core::int?} == null)
- this.{self::C::_#C#b} = #t4;
- else
- throw new _in::LateError::fieldAI("b");
- get c() → core::int
- return let final core::int? #t5 = this.{self::C::_#C#c}{core::int?} in #t5 == null ?{core::int} this.{self::C::_#C#c} = 1.{core::int::unary-}(){() → core::int} : #t5{core::int};
- set c(core::int #t6) → void
- this.{self::C::_#C#c} = #t6;
- get d() → core::int
- return let final core::int? #t7 = this.{self::C::_#C#d}{core::int?} in #t7 == null ?{core::int} let final core::int #t8 = 1.{core::int::unary-}(){() → core::int} in this.{self::C::_#C#d}{core::int?} == null ?{core::int} this.{self::C::_#C#d} = #t8 : throw new _in::LateError::fieldADI("d") : #t7{core::int};
+ return _la::_lateReadCheck<core::int>(this.{self::C::_#C#b}{core::int}, "b");
+ set b(core::int value) → void {
+ _la::_lateWriteOnceCheck(this.{self::C::_#C#b}{core::int}, "b");
+ this.{self::C::_#C#b} = value;
+ }
+ get c() → core::int {
+ core::int value = this.{self::C::_#C#c}{core::int};
+ if(_in::isSentinel(value))
+ value = this.{self::C::_#C#c} = 1.{core::int::unary-}(){() → core::int};
+ return value;
+ }
+ set c(core::int value) → void
+ this.{self::C::_#C#c} = value;
+ get d() → core::int {
+ core::int value = this.{self::C::_#C#d}{core::int};
+ if(_in::isSentinel(value)) {
+ final core::int result = 1.{core::int::unary-}(){() → core::int};
+ _la::_lateInitializeOnceCheck(this.{self::C::_#C#d}{core::int}, "d");
+ value = this.{self::C::_#C#d} = result;
+ }
+ return value;
+ }
}
static field self::C c = new self::C::•();
static method main() → void {
@@ -59,5 +70,4 @@
Extra constant evaluation status:
Evaluated: InstanceInvocation @ org-dartlang-testcase:///late_fields.dart:15:16 -> DoubleConstant(-1.0)
Evaluated: InstanceInvocation @ org-dartlang-testcase:///late_fields.dart:16:22 -> DoubleConstant(-1.0)
-Evaluated: VariableGet @ org-dartlang-testcase:///late_fields.dart:16:18 -> DoubleConstant(-1.0)
-Extra constant evaluation: evaluated: 92, effectively constant: 3
+Extra constant evaluation: evaluated: 76, effectively constant: 2
diff --git a/pkg/front_end/testcases/dart2js/late_fields.dart.weak.expect b/pkg/front_end/testcases/dart2js/late_fields.dart.weak.expect
index ca585bf..ee029897 100644
--- a/pkg/front_end/testcases/dart2js/late_fields.dart.weak.expect
+++ b/pkg/front_end/testcases/dart2js/late_fields.dart.weak.expect
@@ -1,33 +1,15 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
-import "dart:_internal" as _in;
class C extends core::Object {
- field core::int? _#C#a = _in::createSentinel<core::int>();
- field core::int? _#C#b = _in::createSentinel<core::int>();
- field core::int? _#C#c = _in::createSentinel<core::int>();
- field core::int? _#C#d = _in::createSentinel<core::int>();
+ late field core::int a;
+ late final [setter] field core::int b;
+ late field core::int c = 1.{core::int::unary-}(){() → core::int};
+ late final field core::int d = 1.{core::int::unary-}(){() → core::int};
synthetic constructor •() → self::C
: super core::Object::•()
;
- get a() → core::int
- return let final core::int? #t1 = this.{self::C::_#C#a}{core::int?} in _in::isSentinel(#t1) ?{core::int} throw new _in::LateError::fieldNI("a") : #t1{core::int};
- set a(core::int #t2) → void
- this.{self::C::_#C#a} = #t2;
- get b() → core::int
- return let final core::int? #t3 = this.{self::C::_#C#b}{core::int?} in _in::isSentinel(#t3) ?{core::int} throw new _in::LateError::fieldNI("b") : #t3{core::int};
- set b(core::int #t4) → void
- if(_in::isSentinel(this.{self::C::_#C#b}{core::int?}))
- this.{self::C::_#C#b} = #t4;
- else
- throw new _in::LateError::fieldAI("b");
- get c() → core::int
- return let final core::int? #t5 = this.{self::C::_#C#c}{core::int?} in _in::isSentinel(#t5) ?{core::int} this.{self::C::_#C#c} = 1.{core::int::unary-}(){() → core::int} : #t5{core::int};
- set c(core::int #t6) → void
- this.{self::C::_#C#c} = #t6;
- get d() → core::int
- return let final core::int #t7 = this.{self::C::_#C#d}{core::int?} in _in::isSentinel(#t7) ?{core::int} let final core::int #t8 = 1.{core::int::unary-}(){() → core::int} in _in::isSentinel(this.{self::C::_#C#d}{core::int?}) ?{core::int} this.{self::C::_#C#d} = #t8 : throw new _in::LateError::fieldADI("d") : #t7;
}
static field self::C c = new self::C::•();
static method main() → void {
diff --git a/pkg/front_end/testcases/dart2js/late_fields.dart.weak.outline.expect b/pkg/front_end/testcases/dart2js/late_fields.dart.weak.outline.expect
index 09228574..4f8c98b 100644
--- a/pkg/front_end/testcases/dart2js/late_fields.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/dart2js/late_fields.dart.weak.outline.expect
@@ -3,19 +3,12 @@
import "dart:core" as core;
class C extends core::Object {
- field core::int? _#C#a;
- field core::int? _#C#b;
- field core::int? _#C#c;
- field core::int? _#C#d;
+ late field core::int a;
+ late final [setter] field core::int b;
+ late field core::int c;
+ late final field core::int d;
synthetic constructor •() → self::C
;
- get a() → core::int;
- set a(core::int #t1) → void;
- get b() → core::int;
- set b(core::int #t2) → void;
- get c() → core::int;
- set c(core::int #t3) → void;
- get d() → core::int;
}
static field self::C c;
static method main() → void
diff --git a/pkg/front_end/testcases/dart2js/late_fields.dart.weak.transformed.expect b/pkg/front_end/testcases/dart2js/late_fields.dart.weak.transformed.expect
index 06e4c45..25ca1b2 100644
--- a/pkg/front_end/testcases/dart2js/late_fields.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/dart2js/late_fields.dart.weak.transformed.expect
@@ -1,33 +1,44 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
+import "dart:_late_helper" as _la;
import "dart:_internal" as _in;
class C extends core::Object {
- field core::int? _#C#a = _in::createSentinel<core::int>();
- field core::int? _#C#b = _in::createSentinel<core::int>();
- field core::int? _#C#c = _in::createSentinel<core::int>();
- field core::int? _#C#d = _in::createSentinel<core::int>();
+ field core::int _#C#a = _in::createSentinel<core::int>();
+ field core::int _#C#b = _in::createSentinel<core::int>();
+ field core::int _#C#c = _in::createSentinel<core::int>();
+ field core::int _#C#d = _in::createSentinel<core::int>();
synthetic constructor •() → self::C
: super core::Object::•()
;
get a() → core::int
- return let final core::int? #t1 = this.{self::C::_#C#a}{core::int?} in _in::isSentinel(#t1) ?{core::int} throw new _in::LateError::fieldNI("a") : #t1{core::int};
- set a(core::int #t2) → void
- this.{self::C::_#C#a} = #t2;
+ return _la::_lateReadCheck<core::int>(this.{self::C::_#C#a}{core::int}, "a");
+ set a(core::int value) → void
+ this.{self::C::_#C#a} = value;
get b() → core::int
- return let final core::int? #t3 = this.{self::C::_#C#b}{core::int?} in _in::isSentinel(#t3) ?{core::int} throw new _in::LateError::fieldNI("b") : #t3{core::int};
- set b(core::int #t4) → void
- if(_in::isSentinel(this.{self::C::_#C#b}{core::int?}))
- this.{self::C::_#C#b} = #t4;
- else
- throw new _in::LateError::fieldAI("b");
- get c() → core::int
- return let final core::int? #t5 = this.{self::C::_#C#c}{core::int?} in _in::isSentinel(#t5) ?{core::int} this.{self::C::_#C#c} = 1.{core::int::unary-}(){() → core::int} : #t5{core::int};
- set c(core::int #t6) → void
- this.{self::C::_#C#c} = #t6;
- get d() → core::int
- return let final core::int #t7 = this.{self::C::_#C#d}{core::int?} in _in::isSentinel(#t7) ?{core::int} let final core::int #t8 = 1.{core::int::unary-}(){() → core::int} in _in::isSentinel(this.{self::C::_#C#d}{core::int?}) ?{core::int} this.{self::C::_#C#d} = #t8 : throw new _in::LateError::fieldADI("d") : #t7;
+ return _la::_lateReadCheck<core::int>(this.{self::C::_#C#b}{core::int}, "b");
+ set b(core::int value) → void {
+ _la::_lateWriteOnceCheck(this.{self::C::_#C#b}{core::int}, "b");
+ this.{self::C::_#C#b} = value;
+ }
+ get c() → core::int {
+ core::int value = this.{self::C::_#C#c}{core::int};
+ if(_in::isSentinel(value))
+ value = this.{self::C::_#C#c} = 1.{core::int::unary-}(){() → core::int};
+ return value;
+ }
+ set c(core::int value) → void
+ this.{self::C::_#C#c} = value;
+ get d() → core::int {
+ core::int value = this.{self::C::_#C#d}{core::int};
+ if(_in::isSentinel(value)) {
+ final core::int result = 1.{core::int::unary-}(){() → core::int};
+ _la::_lateInitializeOnceCheck(this.{self::C::_#C#d}{core::int}, "d");
+ value = this.{self::C::_#C#d} = result;
+ }
+ return value;
+ }
}
static field self::C c = new self::C::•();
static method main() → void {
@@ -59,5 +70,4 @@
Extra constant evaluation status:
Evaluated: InstanceInvocation @ org-dartlang-testcase:///late_fields.dart:15:16 -> DoubleConstant(-1.0)
Evaluated: InstanceInvocation @ org-dartlang-testcase:///late_fields.dart:16:22 -> DoubleConstant(-1.0)
-Evaluated: VariableGet @ org-dartlang-testcase:///late_fields.dart:16:18 -> DoubleConstant(-1.0)
-Extra constant evaluation: evaluated: 96, effectively constant: 3
+Extra constant evaluation: evaluated: 76, effectively constant: 2
diff --git a/runtime/include/dart_tools_api.h b/runtime/include/dart_tools_api.h
index 3d1b890..65d35ce 100644
--- a/runtime/include/dart_tools_api.h
+++ b/runtime/include/dart_tools_api.h
@@ -542,7 +542,7 @@
* \return The UserTag's label. NULL if the user_tag is invalid. The caller is
* responsible for freeing the returned label.
*/
-DART_WARN_UNUSED_RESULT DART_EXPORT char* Dart_GetUserTagLabel(
+DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_GetUserTagLabel(
Dart_Handle user_tag);
#endif // RUNTIME_INCLUDE_DART_TOOLS_API_H_
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 45d402d..2cd1ed4 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -11,6 +11,7 @@
cc/IsolateReload_PendingStaticCall_NSMToDefined: Fail, Crash # Issue 32981. Fails on non-Windows, crashes on Windows (because of test.py special handline)
cc/IsolateReload_PendingUnqualifiedCall_InstanceToStatic: Fail # Issue 32981
cc/IsolateReload_PendingUnqualifiedCall_StaticToInstance: Fail # Issue 32981
+dart/boxmint_test: Pass, Slow # Uses slow path
dart/data_uri_import_test/none: SkipByDesign
dart/emit_aot_size_info_flag_test: Pass, Slow # Spawns several subprocesses
dart/isolates/*: Pass, Slow # Tests use many isolates and take a longer time.
@@ -20,6 +21,7 @@
dart/snapshot_version_test: Skip # This test is a Dart1 test (script snapshot)
dart/stack_overflow_shared_test: Pass, Slow # Uses --shared-slow-path-triggers-gc flag.
dart/use_bare_instructions_flag_test: Pass, Slow # Spawns several subprocesses
+dart_2/boxmint_test: Pass, Slow # Uses slow path
dart_2/data_uri_import_test/none: SkipByDesign
dart_2/emit_aot_size_info_flag_test: Pass, Slow # Spawns several subprocesses
dart_2/isolates/*: Pass, Slow # Tests use many isolates and take a longer time.
diff --git a/runtime/vm/compiler/assembler/assembler_arm_test.cc b/runtime/vm/compiler/assembler/assembler_arm_test.cc
index 504c848..f925d7c 100644
--- a/runtime/vm/compiler/assembler/assembler_arm_test.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm_test.cc
@@ -1769,7 +1769,7 @@
// 10987654321098765432109876543210
static constexpr uint32_t kBfxTestBits = 0b00010000001000001000010001001011;
-static constexpr int32_t ExpectedUbfxBitPattern(uint8_t lsb, uint8_t width) {
+static int32_t ExpectedUbfxBitPattern(uint8_t lsb, uint8_t width) {
ASSERT(width >= 1);
ASSERT(width < 32);
ASSERT(lsb < 32);
@@ -1777,7 +1777,7 @@
return (kBfxTestBits & (Utils::NBitMask(width) << lsb)) >> lsb;
}
-static constexpr int32_t ExpectedSbfxBitPattern(uint8_t lsb, uint8_t width) {
+static int32_t ExpectedSbfxBitPattern(uint8_t lsb, uint8_t width) {
const uint32_t no_extension = ExpectedUbfxBitPattern(lsb, width);
const uint32_t sign_extension =
Utils::TestBit(no_extension, width - 1) ? ~Utils::NBitMask(width) : 0;
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index d67e9e9..87cc6b7c 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -2708,8 +2708,11 @@
if (array_size < (kInlineArraySize * kCompressedWordSize)) {
intptr_t current_offset = 0;
while (current_offset < array_size) {
- __ str(R6, compiler::Address(R8, current_offset),
- compiler::kObjectBytes);
+ __ StoreCompressedIntoObjectNoBarrier(
+ AllocateArrayABI::kResultReg,
+ compiler::Address(R8, current_offset, compiler::Address::Offset,
+ compiler::kObjectBytes),
+ R6);
current_offset += kCompressedWordSize;
}
} else {
@@ -2717,7 +2720,11 @@
__ Bind(&init_loop);
__ CompareRegisters(R8, R3);
__ b(&end_loop, CS);
- __ str(R6, compiler::Address(R8), compiler::kObjectBytes);
+ __ StoreCompressedIntoObjectNoBarrier(
+ AllocateArrayABI::kResultReg,
+ compiler::Address(R8, 0, compiler::Address::Offset,
+ compiler::kObjectBytes),
+ R6);
__ AddImmediate(R8, kCompressedWordSize);
__ b(&init_loop);
__ Bind(&end_loop);
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index f64d5df..56cdfac 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -2752,7 +2752,9 @@
return (IsZoneHandle() || IsReadOnlyHandle());
}
-ObjectPtr Object::Clone(const Object& orig, Heap::Space space) {
+ObjectPtr Object::Clone(const Object& orig,
+ Heap::Space space,
+ bool load_with_relaxed_atomics) {
const Class& cls = Class::Handle(orig.clazz());
intptr_t size = orig.ptr()->untag()->HeapSize();
ObjectPtr raw_clone =
@@ -2762,9 +2764,19 @@
uword orig_addr = UntaggedObject::ToAddr(orig.ptr());
uword clone_addr = UntaggedObject::ToAddr(raw_clone);
static const intptr_t kHeaderSizeInBytes = sizeof(UntaggedObject);
- memmove(reinterpret_cast<uint8_t*>(clone_addr + kHeaderSizeInBytes),
- reinterpret_cast<uint8_t*>(orig_addr + kHeaderSizeInBytes),
- size - kHeaderSizeInBytes);
+ if (load_with_relaxed_atomics) {
+ auto orig_atomics_ptr = reinterpret_cast<std::atomic<uword>*>(orig_addr);
+ auto clone_ptr = reinterpret_cast<uword*>(clone_addr);
+ for (intptr_t i = kHeaderSizeInBytes / kWordSize; i < size / kWordSize;
+ i++) {
+ *(clone_ptr + i) =
+ (orig_atomics_ptr + i)->load(std::memory_order_relaxed);
+ }
+ } else {
+ memmove(reinterpret_cast<uint8_t*>(clone_addr + kHeaderSizeInBytes),
+ reinterpret_cast<uint8_t*>(orig_addr + kHeaderSizeInBytes),
+ size - kHeaderSizeInBytes);
+ }
// Add clone to store buffer, if needed.
if (!raw_clone->IsOldObject()) {
@@ -7971,9 +7983,8 @@
if (!Utils::IsUint(UntaggedFunction::kMaxTypeParametersBits, value)) {
ReportTooManyTypeParameters(*this);
}
- const uint32_t* original = &untag()->packed_fields_;
- StoreNonPointer(original, UntaggedFunction::PackedNumTypeParameters::update(
- value, *original));
+ untag()->packed_fields_.Update<UntaggedFunction::PackedNumTypeParameters>(
+ value);
}
intptr_t FunctionType::NumTypeParameters(Thread* thread) const {
@@ -10187,9 +10198,8 @@
void Function::set_num_fixed_parameters(intptr_t value) const {
ASSERT(value >= 0);
ASSERT(Utils::IsUint(UntaggedFunction::kMaxFixedParametersBits, value));
- const uint32_t* original = &untag()->packed_fields_;
- StoreNonPointer(original, UntaggedFunction::PackedNumFixedParameters::update(
- value, *original));
+ untag()->packed_fields_.Update<UntaggedFunction::PackedNumFixedParameters>(
+ value);
// Also store in signature.
FunctionType::Handle(signature()).set_num_fixed_parameters(value);
}
@@ -10206,12 +10216,12 @@
void Function::SetNumOptionalParameters(intptr_t value,
bool are_optional_positional) const {
ASSERT(Utils::IsUint(UntaggedFunction::kMaxOptionalParametersBits, value));
- uint32_t packed_fields = untag()->packed_fields_;
- packed_fields = UntaggedFunction::PackedHasNamedOptionalParameters::update(
- (value > 0) && !are_optional_positional, packed_fields);
- packed_fields = UntaggedFunction::PackedNumOptionalParameters::update(
- value, packed_fields);
- StoreNonPointer(&untag()->packed_fields_, packed_fields);
+ untag()
+ ->packed_fields_
+ .Update<UntaggedFunction::PackedHasNamedOptionalParameters>(
+ (value > 0) && !are_optional_positional);
+ untag()->packed_fields_.Update<UntaggedFunction::PackedNumOptionalParameters>(
+ value);
// Also store in signature.
FunctionType::Handle(signature())
.SetNumOptionalParameters(value, are_optional_positional);
@@ -20312,6 +20322,7 @@
untag()->set_type_test_stub(stub.ptr());
return;
}
+
StoreNonPointer(&untag()->type_test_stub_entry_point_, stub.EntryPoint());
untag()->set_type_test_stub(stub.ptr());
}
@@ -20468,7 +20479,9 @@
Type& type = Type::Handle();
// Always cloning in old space and removing space parameter would not satisfy
// currently existing requests for type instantiation in new space.
- type ^= Object::Clone(*this, space);
+ // Load with relaxed atomics to prevent data race with updating type
+ // testing stub.
+ type ^= Object::Clone(*this, space, /*load_with_relaxed_atomics=*/true);
type.set_nullability(value);
type.SetHash(0);
type.InitializeTypeTestingStubNonAtomic(
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 18cb982..0700711 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -756,7 +756,9 @@
#undef STORE_NON_POINTER_ILLEGAL_TYPE
// Allocate an object and copy the body of 'orig'.
- static ObjectPtr Clone(const Object& orig, Heap::Space space);
+ static ObjectPtr Clone(const Object& orig,
+ Heap::Space space,
+ bool load_with_relaxed_atomics = false);
// End of field mutator guards.
@@ -3724,11 +3726,11 @@
// some functions known to be execute infrequently and functions
// which have been de-optimized too many times.
bool is_optimizable() const {
- return UntaggedFunction::PackedOptimizable::decode(untag()->packed_fields_);
+ return untag()->packed_fields_.Read<UntaggedFunction::PackedOptimizable>();
}
void set_is_optimizable(bool value) const {
- set_packed_fields(UntaggedFunction::PackedOptimizable::update(
- value, untag()->packed_fields_));
+ untag()->packed_fields_.UpdateBool<UntaggedFunction::PackedOptimizable>(
+ value);
}
enum KindTagBits {
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 044f9c7..6101970 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -1396,7 +1396,7 @@
NOT_IN_PRECOMPILED(TokenPosition token_pos_);
NOT_IN_PRECOMPILED(TokenPosition end_token_pos_);
Tags<uint32_t> kind_tag_; // See Function::KindTagBits.
- uint32_t packed_fields_;
+ Tags<uint32_t> packed_fields_;
// TODO(regis): Split packed_fields_ in 2 uint32_t if max values are too low.
diff --git a/tests/corelib/symbol_operator_test.dart b/tests/corelib/symbol_operator_test.dart
index c32837f..af4404e 100644
--- a/tests/corelib/symbol_operator_test.dart
+++ b/tests/corelib/symbol_operator_test.dart
@@ -28,14 +28,14 @@
testSymbol(#[]=, ($[$] = $).lastMember, "[]=");
testSymbol(Symbol.unaryMinus, -$, "unary-");
- testSymbolThrows(">>>"); // //# 03: ok
- testSymbolThrows("!"); // //# 03: continued
- testSymbolThrows("&&"); // //# 03: continued
- testSymbolThrows("||"); // //# 03: continued
- testSymbolThrows("?"); // //# 03: continued
- testSymbolThrows("?:"); // //# 03: continued
- testSymbolThrows("#"); // //# 03: continued
- testSymbolThrows("//"); // //# 03: continued
+ testSymbolNotInstanceOperator(">>>");
+ testSymbolNotInstanceOperator("!");
+ testSymbolNotInstanceOperator("&&");
+ testSymbolNotInstanceOperator("||");
+ testSymbolNotInstanceOperator("?");
+ testSymbolNotInstanceOperator("?:");
+ testSymbolNotInstanceOperator("#");
+ testSymbolNotInstanceOperator("//");
}
void testSymbol(Symbol constSymbol, var mirrorSymbol, String name) {
@@ -63,16 +63,8 @@
}
}
-void testSymbolThrows(name) {
- bool fails = false;
- try {
- new Symbol(name);
- } catch (e) {
- fails = true;
- }
- if (!fails) {
- throw "Didn't throw: $name";
- }
+void testSymbolNotInstanceOperator(name) {
+ new Symbol(name);
}
class Symbolize {
diff --git a/tests/corelib/symbol_test.dart b/tests/corelib/symbol_test.dart
index ec47d45..287565b 100644
--- a/tests/corelib/symbol_test.dart
+++ b/tests/corelib/symbol_test.dart
@@ -15,31 +15,10 @@
print('Caught TypeError');
}
- try {
- print(const Symbol('0')); //# 02: compile-time error
- } on ArgumentError catch (e) {
- print('Caught $e');
- }
-
- try {
- print(const Symbol('_')); //# 03: compile-time error
- } on ArgumentError catch (e) {
- print('Caught $e');
- }
-
- try {
- print(new Symbol('0'));
- throw 'Expected an ArgumentError';
- } on ArgumentError catch (e) {
- print('Caught $e');
- }
-
- try {
- print(new Symbol('_'));
- throw 'Expected an ArgumentError';
- } on ArgumentError catch (e) {
- print('Caught $e');
- }
+ print(const Symbol('0'));
+ print(const Symbol('_'));
+ print(new Symbol('0'));
+ print(new Symbol('_'));
if (!identical(const Symbol('fisk'), x)) {
throw 'Symbol constant is not canonicalized';
diff --git a/tests/lib/mirrors/deferred_type_other.dart b/tests/lib/mirrors/deferred_type_other.dart
deleted file mode 100644
index 58e7417..0000000
--- a/tests/lib/mirrors/deferred_type_other.dart
+++ /dev/null
@@ -1,7 +0,0 @@
-// 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.
-
-library deferred_type_other;
-
-class DeferredType {}
diff --git a/tests/lib/mirrors/deferred_type_test.dart b/tests/lib/mirrors/deferred_type_test.dart
deleted file mode 100644
index 338680d..0000000
--- a/tests/lib/mirrors/deferred_type_test.dart
+++ /dev/null
@@ -1,18 +0,0 @@
-// 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.
-
-library deferred_type;
-
-import 'dart:mirrors';
-import 'package:expect/expect.dart';
-import 'package:async_helper/async_helper.dart';
-
-import 'deferred_type_other.dart' deferred as other;
-
-bad(other.DeferredType x) {}
-
-main() {
- print((reflect(bad) as ClosureMirror).function.parameters[0].type);
- throw "Should have died sooner. other.DeferredType is not loaded";
-}
diff --git a/tools/VERSION b/tools/VERSION
index b8b0fea..f272f4f 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 269
+PRERELEASE 270
PRERELEASE_PATCH 0
\ No newline at end of file