Version 2.15.0-90.0.dev
Merge commit 'b3cb952a69981bc5ab19ed41ac297ffa70cf9868' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2c7f285..9371d2d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -93,6 +93,36 @@
Support for `dart-ext:`-style native extensions has been removed as previously
announced. Use `dart:ffi` to bind to native libraries instead.
+#### Linter
+
+Updated the Linter to `1.10.0`, which includes changes that
+- improves regular expression parsing performance for common checks
+ (`camel_case_types`, `file_names`, etc.).
+- (internal) migrates to analyzer 2.1.0 APIs.
+- fixes false positive in `use_build_context_synchronously` in awaits inside
+ anonymous functions.
+- fixes `overridden_fields` false positive w/ static fields.
+- fixes false positive in `avoid_null_checks_in_equality_operators` w/
+ non-nullable params.
+- fixes false positive for deferred imports in `prefer_const_constructors`.
+- marks `avoid_dynamic_calls` stable.
+- (internal) removes unused `MockPubVisitor` and `MockRule` classes.
+- fixes a `prefer_void_to_null` false positive w/ overridden properties.
+- (internal) removes references to `NodeLintRule` in lint rule declarations.
+- fixes `prefer_void_to_null` false positives on overriding returns.
+- fixes `prefer_generic_function_type_aliases` false positives w/ incomplete
+ statements.
+- fixes false positives for `prefer_initializing_formals` with factory
+ constructors.
+- fixes `void_checks` false positives with incomplete source.
+- updates `unnecessary_getters_setters` to only flag the getter.
+- improves messages for `avoid_renaming_method_parameters`.
+- fixes false positives in `prefer_void_to_null`.
+- fixes false positives in `omit_local_variable_types`.
+- fixes false positives in `use_rethrow_when_possible`.
+- improves performance for `annotate_overrides`, `prefer_contains`, and
+ `prefer_void_to_null`.
+
## 2.14.0
### Language
@@ -256,32 +286,7 @@
#### Linter
-Updated the Linter to `1.10.0`, which includes changes that
-- improves regular expression parsing performance for common checks
- (`camel_case_types`, `file_names`, etc.).
-- (internal) migrates to analyzer 2.1.0 APIs.
-- fixes false positive in `use_build_context_synchronously` in awaits inside
- anonymous functions.
-- fixes `overridden_fields` false positive w/ static fields.
-- fixes false positive in `avoid_null_checks_in_equality_operators` w/
- non-nullable params.
-- fixes false positive for deferred imports in `prefer_const_constructors`.
-- marks `avoid_dynamic_calls` stable.
-- (internal) removes unused `MockPubVisitor` and `MockRule` classes.
-- fixes a `prefer_void_to_null` false positive w/ overridden properties.
-- (internal) removes references to `NodeLintRule` in lint rule declarations.
-- fixes `prefer_void_to_null` false positives on overriding returns.
-- fixes `prefer_generic_function_type_aliases` false positives w/ incomplete
- statements.
-- fixes false positives for `prefer_initializing_formals` with factory constructors.
-- fixes `void_checks` false positives with incomplete source.
-- updates `unnecessary_getters_setters` to only flag the getter.
-- improves messages for `avoid_renaming_method_parameters`.
-- fixes false positives in `prefer_void_to_null`.
-- fixes false positives in `omit_local_variable_types`.
-- fixes false positives in `use_rethrow_when_possible`.
-- improves performance for `annotate_overrides`, `prefer_contains`, and
- `prefer_void_to_null`.
+Updated the Linter to `1.8.0`, which includes changes that
- improve performance for `prefer_is_not_empty`.
- fix false positives in `no_logic_in_create_state`.
- improve `package_names` to allow dart identifiers as package names.
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index 2e13ba2..ff410a2 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -4337,7 +4337,7 @@
An enumeration of the kinds of highlighting that can be applied to files.
</p>
- <dl><dt class="value">ANNOTATION</dt><dt class="value">BUILT_IN</dt><dt class="value">CLASS</dt><dt class="value">COMMENT_BLOCK</dt><dt class="value">COMMENT_DOCUMENTATION</dt><dt class="value">COMMENT_END_OF_LINE</dt><dt class="value">CONSTRUCTOR</dt><dt class="value">DIRECTIVE</dt><dt class="value">DYNAMIC_TYPE</dt><dd>
+ <dl><dt class="value">ANNOTATION</dt><dt class="value">BUILT_IN</dt><dt class="value">CLASS</dt><dt class="value">COMMENT_BLOCK</dt><dt class="value">COMMENT_DOCUMENTATION</dt><dt class="value">COMMENT_END_OF_LINE</dt><dt class="value">CONSTRUCTOR</dt><dt class="value">CONSTRUCTOR_TEAR_OFF</dt><dt class="value">DIRECTIVE</dt><dt class="value">DYNAMIC_TYPE</dt><dd>
<p>Deprecated - no longer sent.</p>
</dd><dt class="value">DYNAMIC_LOCAL_VARIABLE_DECLARATION</dt><dt class="value">DYNAMIC_LOCAL_VARIABLE_REFERENCE</dt><dt class="value">DYNAMIC_PARAMETER_DECLARATION</dt><dt class="value">DYNAMIC_PARAMETER_REFERENCE</dt><dt class="value">ENUM</dt><dt class="value">ENUM_CONSTANT</dt><dt class="value">FIELD</dt><dd>
diff --git a/pkg/analysis_server/lib/src/computer/computer_highlights.dart b/pkg/analysis_server/lib/src/computer/computer_highlights.dart
index 6db03d6..74e88d5 100644
--- a/pkg/analysis_server/lib/src/computer/computer_highlights.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_highlights.dart
@@ -662,6 +662,22 @@
}
@override
+ void visitConstructorReference(ConstructorReference node) {
+ var constructorName = node.constructorName;
+ constructorName.type.accept(this);
+
+ // We have a `ConstructorReference` only when it is resolved.
+ // TODO(scheglov) The `ConstructorName` in a tear-off always has a name,
+ // but this is not expressed via types.
+ computer._addRegion_node(
+ constructorName.name!,
+ HighlightRegionType.CONSTRUCTOR_TEAR_OFF,
+ semanticTokenType: SemanticTokenTypes.method,
+ semanticTokenModifiers: {CustomSemanticTokenModifiers.constructor},
+ );
+ }
+
+ @override
void visitContinueStatement(ContinueStatement node) {
computer._addRegion_token(node.continueKeyword, HighlightRegionType.KEYWORD,
semanticTokenModifiers: {CustomSemanticTokenModifiers.control});
diff --git a/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart b/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
index 7be1db5c1..a09c3b7 100644
--- a/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
@@ -232,7 +232,11 @@
var analysisOptions = result.session.analysisContext.analysisOptions;
for (var unitResult in result.units) {
var overrideSet = _readOverrideSet(unitResult);
- for (var error in unitResult.errors) {
+
+ var errors = List.from(unitResult.errors, growable: false);
+ errors.sort((a, b) => a.offset.compareTo(b.offset));
+
+ for (var error in errors) {
var processor = ErrorProcessor.getProcessor(analysisOptions, error);
// Only fix errors not filtered out in analysis options.
if (processor == null || processor.severity != null) {
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_const.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_const.dart
index 3dcb6c7..74c7d31 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_const.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_const.dart
@@ -8,18 +8,17 @@
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/source/source_range.dart';
+import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_dart.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:analyzer_plugin/utilities/range_factory.dart';
class AddConst extends CorrectionProducer {
@override
- bool canBeAppliedInBulk;
+ bool get canBeAppliedInBulk => true;
@override
- bool canBeAppliedToFile;
-
- AddConst(this.canBeAppliedInBulk, this.canBeAppliedToFile);
+ bool get canBeAppliedToFile => true;
@override
FixKind get fixKind => DartFixKind.ADD_CONST;
@@ -42,10 +41,29 @@
return;
}
+ bool isParentConstant(
+ DartFileEditBuilderImpl builder, Expression targetNode) {
+ var edits = builder.fileEdit.edits;
+ var child = targetNode.parent;
+ while (child is Expression || child is ArgumentList) {
+ if (edits.any((element) =>
+ element.replacement == 'const ' &&
+ element.offset == child!.offset)) {
+ return true;
+ }
+ child = child!.parent;
+ }
+ return false;
+ }
+
Future<void> insertAtOffset(Expression targetNode) async {
var finder = _ConstRangeFinder();
targetNode.accept(finder);
await builder.addDartFileEdit(file, (builder) {
+ if (builder is DartFileEditBuilderImpl &&
+ isParentConstant(builder, targetNode)) {
+ return;
+ }
builder.addSimpleInsertion(targetNode.offset, 'const ');
for (var range in finder.ranges) {
builder.addDeletion(range);
@@ -76,16 +94,7 @@
}
/// Return an instance of this class. Used as a tear-off in `FixProcessor`.
- static AddConst toDeclaration() => AddConst(true, true);
-
- /// Return an instance of this class. Used as a tear-off in `FixProcessor`.
- // TODO(brianwilkerson) This fix can produce changes that are inconsistent
- // with the `unnecessary_const` lint. Fix it and then enable it for both
- // uses.
- static AddConst toInvocation() => AddConst(false, false);
-
- /// Return an instance of this class. Used as a tear-off in `FixProcessor`.
- static AddConst toLiteral() => AddConst(true, true);
+ static AddConst newInstance() => AddConst();
}
class _ConstRangeFinder extends RecursiveAstVisitor<void> {
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index c99707b..9f2403c 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -441,17 +441,17 @@
ReplaceWithConditionalAssignment.newInstance,
],
LintNames.prefer_const_constructors: [
- AddConst.toInvocation,
+ AddConst.newInstance,
ReplaceNewWithConst.newInstance,
],
LintNames.prefer_const_constructors_in_immutables: [
- AddConst.toDeclaration,
+ AddConst.newInstance,
],
LintNames.prefer_const_declarations: [
ReplaceFinalWithConst.newInstance,
],
LintNames.prefer_const_literals_to_create_immutables: [
- AddConst.toLiteral,
+ AddConst.newInstance,
],
LintNames.prefer_contains: [
ConvertToContains.newInstance,
diff --git a/pkg/analysis_server/test/analysis/notification_highlights2_test.dart b/pkg/analysis_server/test/analysis/notification_highlights2_test.dart
index 0169e37..e8a2907 100644
--- a/pkg/analysis_server/test/analysis/notification_highlights2_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_highlights2_test.dart
@@ -524,6 +524,49 @@
assertHasRegion(HighlightRegionType.CONSTRUCTOR, 'name(42)');
}
+ Future<void> test_CONSTRUCTOR_TEAR_OFF_named() async {
+ addTestFile('''
+class A<T> {
+ A.named();
+}
+void f() {
+ A<int>.named;
+}
+''');
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.CLASS, 'A<int');
+ assertHasRegion(HighlightRegionType.CLASS, 'int>');
+ assertHasRegion(HighlightRegionType.CONSTRUCTOR_TEAR_OFF, 'named;');
+ }
+
+ Future<void> test_CONSTRUCTOR_TEAR_OFF_new_declared() async {
+ addTestFile('''
+class A<T> {
+ A.new();
+}
+void f() {
+ A<int>.new;
+}
+''');
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.CLASS, 'A<int');
+ assertHasRegion(HighlightRegionType.CLASS, 'int>');
+ assertHasRegion(HighlightRegionType.CONSTRUCTOR_TEAR_OFF, 'new;');
+ }
+
+ Future<void> test_CONSTRUCTOR_TEAR_OFF_new_synthetic() async {
+ addTestFile('''
+class A<T> {}
+void f() {
+ A<int>.new;
+}
+''');
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.CLASS, 'A<int');
+ assertHasRegion(HighlightRegionType.CLASS, 'int>');
+ assertHasRegion(HighlightRegionType.CONSTRUCTOR_TEAR_OFF, 'new;');
+ }
+
Future<void> test_DIRECTIVE() async {
addTestFile('''
library lib;
diff --git a/pkg/analysis_server/test/integration/support/protocol_matchers.dart b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
index 3c3eecb..4791ace 100644
--- a/pkg/analysis_server/test/integration/support/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
@@ -774,6 +774,7 @@
/// COMMENT_DOCUMENTATION
/// COMMENT_END_OF_LINE
/// CONSTRUCTOR
+/// CONSTRUCTOR_TEAR_OFF
/// DIRECTIVE
/// DYNAMIC_TYPE
/// DYNAMIC_LOCAL_VARIABLE_DECLARATION
@@ -850,6 +851,7 @@
'COMMENT_DOCUMENTATION',
'COMMENT_END_OF_LINE',
'CONSTRUCTOR',
+ 'CONSTRUCTOR_TEAR_OFF',
'DIRECTIVE',
'DYNAMIC_TYPE',
'DYNAMIC_LOCAL_VARIABLE_DECLARATION',
diff --git a/pkg/analysis_server/test/search/element_references_test.dart b/pkg/analysis_server/test/search/element_references_test.dart
index 2bc7a79..55ab879 100644
--- a/pkg/analysis_server/test/search/element_references_test.dart
+++ b/pkg/analysis_server/test/search/element_references_test.dart
@@ -42,19 +42,31 @@
Future<void> test_constructor_named() async {
addTestFile('''
+/// [new A.named] 1
class A {
- A.named(p);
+ A.named() {}
+ A.other() : this.named(); // 2
}
+
+class B extends A {
+ B() : super.named(); // 3
+ factory B.other() = A.named; // 4
+}
+
void f() {
- new A.named(1);
- new A.named(2);
+ A.named(); // 5
+ A.named; // 6
}
''');
- await findElementReferences('named(p)', false);
+ await findElementReferences('named() {}', false);
expect(searchElement!.kind, ElementKind.CONSTRUCTOR);
- expect(results, hasLength(2));
- assertHasResult(SearchResultKind.REFERENCE, '.named(1)', 6);
- assertHasResult(SearchResultKind.REFERENCE, '.named(2)', 6);
+ expect(results, hasLength(6));
+ assertHasResult(SearchResultKind.REFERENCE, '.named] 1', 6);
+ assertHasResult(SearchResultKind.INVOCATION, '.named(); // 2', 6);
+ assertHasResult(SearchResultKind.INVOCATION, '.named(); // 3', 6);
+ assertHasResult(SearchResultKind.REFERENCE, '.named; // 4', 6);
+ assertHasResult(SearchResultKind.INVOCATION, '.named(); // 5', 6);
+ assertHasResult(SearchResultKind.REFERENCE, '.named; // 6', 6);
}
Future<void> test_constructor_named_potential() async {
@@ -77,24 +89,36 @@
await findElementReferences('named(p); // A', true);
expect(searchElement!.kind, ElementKind.CONSTRUCTOR);
expect(results, hasLength(1));
- assertHasResult(SearchResultKind.REFERENCE, '.named(1)', 6);
+ assertHasResult(SearchResultKind.INVOCATION, '.named(1)', 6);
}
Future<void> test_constructor_unnamed() async {
addTestFile('''
+/// [new A] 1
class A {
- A(p);
+ A() {}
+ A.other() : this(); // 2
}
+
+class B extends A {
+ B() : super(); // 3
+ factory B.other() = A; // 4
+}
+
void f() {
- new A(1);
- new A(2);
+ A(); // 5
+ A.new; // 6
}
''');
- await findElementReferences('A(p)', false);
+ await findElementReferences('A() {}', false);
expect(searchElement!.kind, ElementKind.CONSTRUCTOR);
- expect(results, hasLength(2));
- assertHasResult(SearchResultKind.REFERENCE, '(1)', 0);
- assertHasResult(SearchResultKind.REFERENCE, '(2)', 0);
+ expect(results, hasLength(6));
+ assertHasResult(SearchResultKind.REFERENCE, '] 1', 0);
+ assertHasResult(SearchResultKind.INVOCATION, '(); // 2', 0);
+ assertHasResult(SearchResultKind.INVOCATION, '(); // 3', 0);
+ assertHasResult(SearchResultKind.REFERENCE, '; // 4', 0);
+ assertHasResult(SearchResultKind.INVOCATION, '(); // 5', 0);
+ assertHasResult(SearchResultKind.REFERENCE, '.new; // 6', 4);
}
Future<void> test_constructor_unnamed_potential() async {
@@ -122,7 +146,7 @@
await findElementReferences('A(p)', true);
expect(searchElement!.kind, ElementKind.CONSTRUCTOR);
expect(results, hasLength(1));
- assertHasResult(SearchResultKind.REFERENCE, '(1)', 0);
+ assertHasResult(SearchResultKind.INVOCATION, '(1)', 0);
}
Future<void> test_extension() async {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_const_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_const_test.dart
index 5dc2905c..c2f2e4a 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_const_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_const_test.dart
@@ -26,8 +26,6 @@
@override
String get lintCode => LintNames.prefer_const_constructors;
- /// Disabled in BulkFixProcessor.
- @failingTest
Future<void> test_noKeyword() async {
writeTestPackageConfig(meta: true);
await resolveTestCode(r'''
@@ -36,12 +34,11 @@
}
var c = C(C());
''');
- // TODO (pq): results are incompatible w/ `unnecessary_const`
await assertHasFix(r'''
class C {
const C([C c]);
}
-var c = const C(const C());
+var c = const C(C());
''');
}
}
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/HighlightRegionType.java b/pkg/analysis_server/tool/spec/generated/java/types/HighlightRegionType.java
index 65f636a..01b222b 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/HighlightRegionType.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/HighlightRegionType.java
@@ -29,6 +29,8 @@
public static final String CONSTRUCTOR = "CONSTRUCTOR";
+ public static final String CONSTRUCTOR_TEAR_OFF = "CONSTRUCTOR_TEAR_OFF";
+
public static final String DIRECTIVE = "DIRECTIVE";
/**
diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_common.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_common.dart
index 76b7a2c..2900b89 100644
--- a/pkg/analysis_server_client/lib/src/protocol/protocol_common.dart
+++ b/pkg/analysis_server_client/lib/src/protocol/protocol_common.dart
@@ -1854,6 +1854,7 @@
/// COMMENT_DOCUMENTATION
/// COMMENT_END_OF_LINE
/// CONSTRUCTOR
+/// CONSTRUCTOR_TEAR_OFF
/// DIRECTIVE
/// DYNAMIC_TYPE
/// DYNAMIC_LOCAL_VARIABLE_DECLARATION
@@ -1944,6 +1945,9 @@
static const HighlightRegionType CONSTRUCTOR =
HighlightRegionType._('CONSTRUCTOR');
+ static const HighlightRegionType CONSTRUCTOR_TEAR_OFF =
+ HighlightRegionType._('CONSTRUCTOR_TEAR_OFF');
+
static const HighlightRegionType DIRECTIVE =
HighlightRegionType._('DIRECTIVE');
@@ -2162,6 +2166,7 @@
COMMENT_DOCUMENTATION,
COMMENT_END_OF_LINE,
CONSTRUCTOR,
+ CONSTRUCTOR_TEAR_OFF,
DIRECTIVE,
DYNAMIC_TYPE,
DYNAMIC_LOCAL_VARIABLE_DECLARATION,
@@ -2252,6 +2257,8 @@
return COMMENT_END_OF_LINE;
case 'CONSTRUCTOR':
return CONSTRUCTOR;
+ case 'CONSTRUCTOR_TEAR_OFF':
+ return CONSTRUCTOR_TEAR_OFF;
case 'DIRECTIVE':
return DIRECTIVE;
case 'DYNAMIC_TYPE':
diff --git a/pkg/analyzer/lib/src/dart/analysis/index.dart b/pkg/analyzer/lib/src/dart/analysis/index.dart
index 1d20779..8387f8a 100644
--- a/pkg/analyzer/lib/src/dart/analysis/index.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/index.dart
@@ -610,17 +610,28 @@
void visitConstructorName(ConstructorName node) {
var element = node.staticElement?.declaration;
element = _getActualConstructorElement(element);
- // record relation
- if (node.name != null) {
- int offset = node.period!.offset;
- int length = node.name!.end - offset;
- recordRelationOffset(
- element, IndexRelationKind.IS_REFERENCED_BY, offset, length, true);
+
+ IndexRelationKind kind;
+ if (node.parent is ConstructorReference) {
+ kind = IndexRelationKind.IS_REFERENCED_BY_CONSTRUCTOR_TEAR_OFF;
+ } else if (node.parent is InstanceCreationExpression) {
+ kind = IndexRelationKind.IS_INVOKED_BY;
} else {
- int offset = node.type.end;
- recordRelationOffset(
- element, IndexRelationKind.IS_REFERENCED_BY, offset, 0, true);
+ kind = IndexRelationKind.IS_REFERENCED_BY;
}
+
+ int offset;
+ int length;
+ if (node.name != null) {
+ offset = node.period!.offset;
+ length = node.name!.end - offset;
+ } else {
+ offset = node.type.end;
+ length = 0;
+ }
+
+ recordRelationOffset(element, kind, offset, length, true);
+
node.type.accept(this);
}
@@ -735,11 +746,11 @@
int offset = node.period!.offset;
int length = node.constructorName!.end - offset;
recordRelationOffset(
- element, IndexRelationKind.IS_REFERENCED_BY, offset, length, true);
+ element, IndexRelationKind.IS_INVOKED_BY, offset, length, true);
} else {
int offset = node.thisKeyword.end;
recordRelationOffset(
- element, IndexRelationKind.IS_REFERENCED_BY, offset, 0, true);
+ element, IndexRelationKind.IS_INVOKED_BY, offset, 0, true);
}
node.argumentList.accept(this);
}
@@ -797,11 +808,11 @@
int offset = node.period!.offset;
int length = node.constructorName!.end - offset;
recordRelationOffset(
- element, IndexRelationKind.IS_REFERENCED_BY, offset, length, true);
+ element, IndexRelationKind.IS_INVOKED_BY, offset, length, true);
} else {
int offset = node.superKeyword.end;
recordRelationOffset(
- element, IndexRelationKind.IS_REFERENCED_BY, offset, 0, true);
+ element, IndexRelationKind.IS_INVOKED_BY, offset, 0, true);
}
node.argumentList.accept(this);
}
diff --git a/pkg/analyzer/lib/src/dart/analysis/search.dart b/pkg/analyzer/lib/src/dart/analysis/search.dart
index 8d7a200..9a79ce1 100644
--- a/pkg/analyzer/lib/src/dart/analysis/search.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/search.dart
@@ -73,11 +73,12 @@
ElementKind kind = element.kind;
if (element is ClassElement ||
- element is ConstructorElement ||
element is ExtensionElement ||
element is PropertyAccessorElement && element.isSetter ||
element is TypeAliasElement) {
return _searchReferences(element, searchedFiles);
+ } else if (element is ConstructorElement) {
+ return await _searchReferences_Constructor(element, searchedFiles);
} else if (element is CompilationUnitElement) {
return _searchReferences_CompilationUnit(element);
} else if (element is PropertyAccessorElement && element.isGetter) {
@@ -323,6 +324,18 @@
return results;
}
+ Future<List<SearchResult>> _searchReferences_Constructor(
+ ConstructorElement element, SearchedFiles searchedFiles) async {
+ List<SearchResult> results = <SearchResult>[];
+ await _addResults(results, element, searchedFiles, const {
+ IndexRelationKind.IS_INVOKED_BY: SearchResultKind.INVOCATION,
+ IndexRelationKind.IS_REFERENCED_BY: SearchResultKind.REFERENCE,
+ IndexRelationKind.IS_REFERENCED_BY_CONSTRUCTOR_TEAR_OFF:
+ SearchResultKind.REFERENCE_BY_CONSTRUCTOR_TEAR_OFF,
+ });
+ return results;
+ }
+
Future<List<SearchResult>> _searchReferences_Field(
PropertyInducingElement field, SearchedFiles searchedFiles) async {
List<SearchResult> results = <SearchResult>[];
@@ -562,7 +575,14 @@
}
/// The kind of reference in a [SearchResult].
-enum SearchResultKind { READ, READ_WRITE, WRITE, INVOCATION, REFERENCE }
+enum SearchResultKind {
+ READ,
+ READ_WRITE,
+ WRITE,
+ INVOCATION,
+ REFERENCE,
+ REFERENCE_BY_CONSTRUCTOR_TEAR_OFF,
+}
/// A single subtype of a type.
class SubtypeResult {
diff --git a/pkg/analyzer/lib/src/summary/format.fbs b/pkg/analyzer/lib/src/summary/format.fbs
index 4d7e28d..75c773b 100644
--- a/pkg/analyzer/lib/src/summary/format.fbs
+++ b/pkg/analyzer/lib/src/summary/format.fbs
@@ -73,6 +73,12 @@
/// Right: location.
IS_REFERENCED_BY,
+ /// Left: a constructor.
+ /// Is referenced by a constructor tear-off at, which is special because
+ /// the name of the constructor is required (`new` for unnamed).
+ /// Right: location.
+ IS_REFERENCED_BY_CONSTRUCTOR_TEAR_OFF,
+
/// Left: unresolved member name.
/// Is read at.
/// Right: location.
diff --git a/pkg/analyzer/lib/src/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
index ea3274f..ee5b366 100644
--- a/pkg/analyzer/lib/src/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -545,6 +545,12 @@
/// Right: location.
IS_REFERENCED_BY,
+ /// Left: a constructor.
+ /// Is referenced by a constructor tear-off at, which is special because
+ /// the name of the constructor is required (`new` for unnamed).
+ /// Right: location.
+ IS_REFERENCED_BY_CONSTRUCTOR_TEAR_OFF,
+
/// Left: unresolved member name.
/// Is read at.
/// Right: location.
@@ -558,7 +564,7 @@
/// Left: unresolved member name.
/// Is written at.
/// Right: location.
- IS_WRITTEN_BY
+ IS_WRITTEN_BY,
}
/// When we need to reference a synthetic element in [PackageIndex] we use a
diff --git a/pkg/analyzer/test/src/dart/analysis/index_test.dart b/pkg/analyzer/test/src/dart/analysis/index_test.dart
index b6d1f58..cecd83d 100644
--- a/pkg/analyzer/test/src/dart/analysis/index_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/index_test.dart
@@ -678,11 +678,11 @@
var constA = findElement.unnamedConstructor('A');
var constA_named = findElement.constructor('named', of: 'A');
assertThat(constA)
- ..isReferencedAt('(); // B1', true, length: 0)
- ..isReferencedAt('(); // C1', true, length: 0);
+ ..isInvokedAt('(); // B1', true, length: 0)
+ ..isInvokedAt('(); // C1', true, length: 0);
assertThat(constA_named)
- ..isReferencedAt('.named(); // B2', true, length: 6)
- ..isReferencedAt('.named(); // C2', true, length: 6);
+ ..isInvokedAt('.named(); // B2', true, length: 6)
+ ..isInvokedAt('.named(); // C2', true, length: 6);
}
test_isReferencedBy_ConstructorElement_classTypeAlias_cycle() async {
@@ -718,11 +718,11 @@
assertThat(element)
..hasRelationCount(6)
..isReferencedAt('.foo] 1', true, length: 4)
- ..isReferencedAt('.foo(); // 2', true, length: 4)
- ..isReferencedAt('.foo(); // 3', true, length: 4)
+ ..isInvokedAt('.foo(); // 2', true, length: 4)
+ ..isInvokedAt('.foo(); // 3', true, length: 4)
..isReferencedAt('.foo; // 4', true, length: 4)
- ..isReferencedAt('.foo(); // 5', true, length: 4)
- ..isReferencedAt('.foo; // 6', true, length: 4);
+ ..isInvokedAt('.foo(); // 5', true, length: 4)
+ ..isReferencedByConstructorTearOffAt('.foo; // 6', length: 4);
}
test_isReferencedBy_ConstructorElement_namedOnlyWithDot() async {
@@ -752,8 +752,8 @@
''');
var constA = findElement.unnamedConstructor('A');
var constA_bar = findElement.constructor('bar');
- assertThat(constA).isReferencedAt('(); // 2', true, length: 0);
- assertThat(constA_bar).isReferencedAt('.bar(); // 1', true, length: 4);
+ assertThat(constA).isInvokedAt('(); // 2', true, length: 0);
+ assertThat(constA_bar).isInvokedAt('.bar(); // 1', true, length: 4);
}
test_isReferencedBy_ConstructorElement_unnamed_declared() async {
@@ -761,24 +761,26 @@
/// [new A] 1
class A {
A() {}
+ A.other() : this(); // 2
}
class B extends A {
- B() : super(); // 2
- factory B.bar() = A; // 3
+ B() : super(); // 3
+ factory B.other() = A; // 4
}
void f() {
- A(); // 4
- A.new; // 5
+ A(); // 5
+ A.new; // 6
}
''');
var element = findElement.unnamedConstructor('A');
assertThat(element)
- ..hasRelationCount(5)
+ ..hasRelationCount(6)
..isReferencedAt('] 1', true, length: 0)
- ..isReferencedAt('(); // 2', true, length: 0)
- ..isReferencedAt('; // 3', true, length: 0)
- ..isReferencedAt('(); // 4', true, length: 0)
- ..isReferencedAt('.new; // 5', true, length: 4);
+ ..isInvokedAt('(); // 2', true, length: 0)
+ ..isInvokedAt('(); // 3', true, length: 0)
+ ..isReferencedAt('; // 4', true, length: 0)
+ ..isInvokedAt('(); // 5', true, length: 0)
+ ..isReferencedByConstructorTearOffAt('.new; // 6', length: 4);
}
test_isReferencedBy_ConstructorElement_unnamed_declared_new() async {
@@ -786,24 +788,26 @@
/// [new A] 1
class A {
A.new() {}
+ A.other() : this(); // 2
}
class B extends A {
- B() : super(); // 2
- factory B.bar() = A; // 3
+ B() : super(); // 3
+ factory B.bar() = A; // 4
}
void f() {
- A(); // 4
- A.new; // 5
+ A(); // 5
+ A.new; // 6
}
''');
var element = findElement.unnamedConstructor('A');
assertThat(element)
- ..hasRelationCount(5)
+ ..hasRelationCount(6)
..isReferencedAt('] 1', true, length: 0)
- ..isReferencedAt('(); // 2', true, length: 0)
- ..isReferencedAt('; // 3', true, length: 0)
- ..isReferencedAt('(); // 4', true, length: 0)
- ..isReferencedAt('.new; // 5', true, length: 4);
+ ..isInvokedAt('(); // 2', true, length: 0)
+ ..isInvokedAt('(); // 3', true, length: 0)
+ ..isReferencedAt('; // 4', true, length: 0)
+ ..isInvokedAt('(); // 5', true, length: 0)
+ ..isReferencedByConstructorTearOffAt('.new; // 6', length: 4);
}
test_isReferencedBy_ConstructorElement_unnamed_synthetic() async {
@@ -823,10 +827,10 @@
assertThat(element)
..hasRelationCount(5)
..isReferencedAt('] 1', true, length: 0)
- ..isReferencedAt('(); // 2', true, length: 0)
+ ..isInvokedAt('(); // 2', true, length: 0)
..isReferencedAt('; // 3', true, length: 0)
- ..isReferencedAt('(); // 4', true, length: 0)
- ..isReferencedAt('.new; // 5', true, length: 4);
+ ..isInvokedAt('(); // 4', true, length: 0)
+ ..isReferencedByConstructorTearOffAt('.new; // 5', length: 4);
}
test_isReferencedBy_DynamicElement() async {
@@ -1615,6 +1619,16 @@
test._expectedLocation(search, isQualified, length: length));
}
+ void isReferencedByConstructorTearOffAt(String search,
+ {required int length}) {
+ test._assertHasRelation(
+ element,
+ relations,
+ IndexRelationKind.IS_REFERENCED_BY_CONSTRUCTOR_TEAR_OFF,
+ test._expectedLocation(search, true, length: length),
+ );
+ }
+
void isWrittenAt(String search, bool isQualified, {int? length}) {
test._assertHasRelation(element, relations, IndexRelationKind.IS_WRITTEN_BY,
test._expectedLocation(search, isQualified, length: length));
diff --git a/pkg/analyzer/test/src/dart/analysis/search_test.dart b/pkg/analyzer/test/src/dart/analysis/search_test.dart
index 774cbf2..9512ac4 100644
--- a/pkg/analyzer/test/src/dart/analysis/search_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/search_test.dart
@@ -344,21 +344,41 @@
test_searchReferences_ConstructorElement_named() async {
await resolveTestCode('''
+/// [new A.named] 1
class A {
A.named() {}
+ A.other() : this.named(); // 2
}
-void main() {
- A.named();
- A.named;
+class B extends A {
+ B() : super.named(); // 3
+ factory B.other() = A.named; // 4
+}
+
+void f() {
+ A.named(); // 5
+ A.named; // 6
}
''');
var element = findElement.constructor('named');
- var main = findElement.function('main');
+ var f = findElement.function('f');
var expected = [
- _expectIdQ(main, SearchResultKind.REFERENCE, '.named();',
+ _expectIdQ(
+ findElement.class_('A'), SearchResultKind.REFERENCE, '.named] 1',
length: '.named'.length),
- _expectIdQ(main, SearchResultKind.REFERENCE, '.named;',
+ _expectIdQ(findElement.constructor('other', of: 'A'),
+ SearchResultKind.INVOCATION, '.named(); // 2',
+ length: '.named'.length),
+ _expectIdQ(findElement.unnamedConstructor('B'),
+ SearchResultKind.INVOCATION, '.named(); // 3',
+ length: '.named'.length),
+ _expectIdQ(findElement.constructor('other', of: 'B'),
+ SearchResultKind.REFERENCE, '.named; // 4',
+ length: '.named'.length),
+ _expectIdQ(f, SearchResultKind.INVOCATION, '.named(); // 5',
+ length: '.named'.length),
+ _expectIdQ(
+ f, SearchResultKind.REFERENCE_BY_CONSTRUCTOR_TEAR_OFF, '.named; // 6',
length: '.named'.length),
];
await _verifyReferences(element, expected);
@@ -381,29 +401,49 @@
var element = findElement.constructor('named');
var f = findElement.topFunction('f');
await _verifyReferences(element, [
- _expectIdQ(f, SearchResultKind.REFERENCE, '.named(); // ref',
+ _expectIdQ(f, SearchResultKind.INVOCATION, '.named(); // ref',
length: '.named'.length),
- _expectIdQ(f, SearchResultKind.REFERENCE, '.named;',
+ _expectIdQ(
+ f, SearchResultKind.REFERENCE_BY_CONSTRUCTOR_TEAR_OFF, '.named;',
length: '.named'.length),
]);
}
- test_searchReferences_ConstructorElement_unnamed() async {
+ test_searchReferences_ConstructorElement_unnamed_declared() async {
await resolveTestCode('''
+/// [new A] 1
class A {
A() {}
+ A.other() : this(); // 2
}
-void main() {
- A();
- A.new;
+class B extends A {
+ B() : super(); // 3
+ factory B.other() = A; // 4
+}
+
+void f() {
+ A(); // 5
+ A.new; // 6
}
''');
var element = findElement.unnamedConstructor('A');
- var main = findElement.function('main');
+ var f = findElement.function('f');
var expected = [
- _expectIdQ(main, SearchResultKind.REFERENCE, '();', length: 0),
- _expectIdQ(main, SearchResultKind.REFERENCE, '.new;',
+ _expectIdQ(findElement.class_('A'), SearchResultKind.REFERENCE, '] 1',
+ length: 0),
+ _expectIdQ(findElement.constructor('other', of: 'A'),
+ SearchResultKind.INVOCATION, '(); // 2',
+ length: 0),
+ _expectIdQ(findElement.unnamedConstructor('B'),
+ SearchResultKind.INVOCATION, '(); // 3',
+ length: 0),
+ _expectIdQ(findElement.constructor('other', of: 'B'),
+ SearchResultKind.REFERENCE, '; // 4',
+ length: 0),
+ _expectIdQ(f, SearchResultKind.INVOCATION, '(); // 5', length: 0),
+ _expectIdQ(
+ f, SearchResultKind.REFERENCE_BY_CONSTRUCTOR_TEAR_OFF, '.new; // 6',
length: '.new'.length),
];
await _verifyReferences(element, expected);
@@ -432,7 +472,7 @@
CompilationUnit otherUnit = otherUnitResult.unit;
Element main = otherUnit.declaredElement!.functions[0];
var expected = [
- ExpectedResult(main, SearchResultKind.REFERENCE,
+ ExpectedResult(main, SearchResultKind.INVOCATION,
otherCode.indexOf('(); // in other'), 0,
isResolved: true, isQualified: true)
];
@@ -441,18 +481,33 @@
test_searchReferences_ConstructorElement_unnamed_synthetic() async {
await resolveTestCode('''
+/// [new A] 1
class A {}
-void main() {
- A();
- A.new;
+class B extends A {
+ B() : super(); // 2
+ factory B.other() = A; // 3
+}
+
+void f() {
+ A(); // 4
+ A.new; // 5
}
''');
var element = findElement.unnamedConstructor('A');
- var main = findElement.function('main');
+ var f = findElement.function('f');
var expected = [
- _expectIdQ(main, SearchResultKind.REFERENCE, '();', length: 0),
- _expectIdQ(main, SearchResultKind.REFERENCE, '.new;',
+ _expectIdQ(findElement.class_('A'), SearchResultKind.REFERENCE, '] 1',
+ length: 0),
+ _expectIdQ(findElement.unnamedConstructor('B'),
+ SearchResultKind.INVOCATION, '(); // 2',
+ length: 0),
+ _expectIdQ(findElement.constructor('other', of: 'B'),
+ SearchResultKind.REFERENCE, '; // 3',
+ length: 0),
+ _expectIdQ(f, SearchResultKind.INVOCATION, '(); // 4', length: 0),
+ _expectIdQ(
+ f, SearchResultKind.REFERENCE_BY_CONSTRUCTOR_TEAR_OFF, '.new; // 5',
length: '.new'.length),
];
await _verifyReferences(element, expected);
diff --git a/pkg/analyzer_plugin/doc/api.html b/pkg/analyzer_plugin/doc/api.html
index 96c8505..83c8834 100644
--- a/pkg/analyzer_plugin/doc/api.html
+++ b/pkg/analyzer_plugin/doc/api.html
@@ -1385,7 +1385,7 @@
An enumeration of the kinds of highlighting that can be applied to files.
</p>
- <dl><dt class="value">ANNOTATION</dt><dt class="value">BUILT_IN</dt><dt class="value">CLASS</dt><dt class="value">COMMENT_BLOCK</dt><dt class="value">COMMENT_DOCUMENTATION</dt><dt class="value">COMMENT_END_OF_LINE</dt><dt class="value">CONSTRUCTOR</dt><dt class="value">DIRECTIVE</dt><dt class="value">DYNAMIC_TYPE</dt><dd>
+ <dl><dt class="value">ANNOTATION</dt><dt class="value">BUILT_IN</dt><dt class="value">CLASS</dt><dt class="value">COMMENT_BLOCK</dt><dt class="value">COMMENT_DOCUMENTATION</dt><dt class="value">COMMENT_END_OF_LINE</dt><dt class="value">CONSTRUCTOR</dt><dt class="value">CONSTRUCTOR_TEAR_OFF</dt><dt class="value">DIRECTIVE</dt><dt class="value">DYNAMIC_TYPE</dt><dd>
<p>Deprecated - no longer sent.</p>
</dd><dt class="value">DYNAMIC_LOCAL_VARIABLE_DECLARATION</dt><dt class="value">DYNAMIC_LOCAL_VARIABLE_REFERENCE</dt><dt class="value">DYNAMIC_PARAMETER_DECLARATION</dt><dt class="value">DYNAMIC_PARAMETER_REFERENCE</dt><dt class="value">ENUM</dt><dt class="value">ENUM_CONSTANT</dt><dt class="value">FIELD</dt><dd>
diff --git a/pkg/analyzer_plugin/lib/protocol/protocol_common.dart b/pkg/analyzer_plugin/lib/protocol/protocol_common.dart
index e437a89..83ecb6f 100644
--- a/pkg/analyzer_plugin/lib/protocol/protocol_common.dart
+++ b/pkg/analyzer_plugin/lib/protocol/protocol_common.dart
@@ -1854,6 +1854,7 @@
/// COMMENT_DOCUMENTATION
/// COMMENT_END_OF_LINE
/// CONSTRUCTOR
+/// CONSTRUCTOR_TEAR_OFF
/// DIRECTIVE
/// DYNAMIC_TYPE
/// DYNAMIC_LOCAL_VARIABLE_DECLARATION
@@ -1944,6 +1945,9 @@
static const HighlightRegionType CONSTRUCTOR =
HighlightRegionType._('CONSTRUCTOR');
+ static const HighlightRegionType CONSTRUCTOR_TEAR_OFF =
+ HighlightRegionType._('CONSTRUCTOR_TEAR_OFF');
+
static const HighlightRegionType DIRECTIVE =
HighlightRegionType._('DIRECTIVE');
@@ -2162,6 +2166,7 @@
COMMENT_DOCUMENTATION,
COMMENT_END_OF_LINE,
CONSTRUCTOR,
+ CONSTRUCTOR_TEAR_OFF,
DIRECTIVE,
DYNAMIC_TYPE,
DYNAMIC_LOCAL_VARIABLE_DECLARATION,
@@ -2252,6 +2257,8 @@
return COMMENT_END_OF_LINE;
case 'CONSTRUCTOR':
return CONSTRUCTOR;
+ case 'CONSTRUCTOR_TEAR_OFF':
+ return CONSTRUCTOR_TEAR_OFF;
case 'DIRECTIVE':
return DIRECTIVE;
case 'DYNAMIC_TYPE':
diff --git a/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart b/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart
index 4ed7683..a4aade5 100644
--- a/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart
+++ b/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart
@@ -368,6 +368,7 @@
/// COMMENT_DOCUMENTATION
/// COMMENT_END_OF_LINE
/// CONSTRUCTOR
+/// CONSTRUCTOR_TEAR_OFF
/// DIRECTIVE
/// DYNAMIC_TYPE
/// DYNAMIC_LOCAL_VARIABLE_DECLARATION
@@ -444,6 +445,7 @@
'COMMENT_DOCUMENTATION',
'COMMENT_END_OF_LINE',
'CONSTRUCTOR',
+ 'CONSTRUCTOR_TEAR_OFF',
'DIRECTIVE',
'DYNAMIC_TYPE',
'DYNAMIC_LOCAL_VARIABLE_DECLARATION',
diff --git a/pkg/analyzer_plugin/tool/spec/common_types_spec.html b/pkg/analyzer_plugin/tool/spec/common_types_spec.html
index 412fcb7..a802f72 100644
--- a/pkg/analyzer_plugin/tool/spec/common_types_spec.html
+++ b/pkg/analyzer_plugin/tool/spec/common_types_spec.html
@@ -682,6 +682,7 @@
<value><code>COMMENT_DOCUMENTATION</code></value>
<value><code>COMMENT_END_OF_LINE</code></value>
<value><code>CONSTRUCTOR</code></value>
+ <value><code>CONSTRUCTOR_TEAR_OFF</code></value>
<value><code>DIRECTIVE</code></value>
<value>
<code>DYNAMIC_TYPE</code>
diff --git a/pkg/compiler/lib/src/kernel/dart2js_target.dart b/pkg/compiler/lib/src/kernel/dart2js_target.dart
index 4510755..312fad7 100644
--- a/pkg/compiler/lib/src/kernel/dart2js_target.dart
+++ b/pkg/compiler/lib/src/kernel/dart2js_target.dart
@@ -233,7 +233,7 @@
}
@override
- ConstantsBackend constantsBackend(CoreTypes coreTypes) =>
+ ConstantsBackend get constantsBackend =>
const Dart2jsConstantsBackend(supportsUnevaluatedConstants: true);
}
diff --git a/pkg/dev_compiler/lib/src/kernel/constants.dart b/pkg/dev_compiler/lib/src/kernel/constants.dart
index 87df7e3..9a938b2 100644
--- a/pkg/dev_compiler/lib/src/kernel/constants.dart
+++ b/pkg/dev_compiler/lib/src/kernel/constants.dart
@@ -99,7 +99,11 @@
NumberSemantics get numberSemantics => NumberSemantics.js;
@override
+ bool get alwaysInlineConstants => false;
+
+ @override
bool shouldInlineConstant(ConstantExpression initializer) {
+ assert(!alwaysInlineConstants);
var constant = initializer.constant;
if (constant is StringConstant) {
// Only inline small string constants, not large ones.
diff --git a/pkg/dev_compiler/lib/src/kernel/target.dart b/pkg/dev_compiler/lib/src/kernel/target.dart
index 8468f28..2bab515 100644
--- a/pkg/dev_compiler/lib/src/kernel/target.dart
+++ b/pkg/dev_compiler/lib/src/kernel/target.dart
@@ -243,8 +243,7 @@
}
@override
- ConstantsBackend constantsBackend(CoreTypes coreTypes) =>
- const DevCompilerConstantsBackend();
+ ConstantsBackend get constantsBackend => const DevCompilerConstantsBackend();
}
/// Analyzes a component to determine if any covariance checks in private
diff --git a/pkg/front_end/lib/src/base/processed_options.dart b/pkg/front_end/lib/src/base/processed_options.dart
index 219a798..e6a3ec0 100644
--- a/pkg/front_end/lib/src/base/processed_options.dart
+++ b/pkg/front_end/lib/src/base/processed_options.dart
@@ -848,6 +848,8 @@
return null;
}
}
+
+ CompilerOptions get rawOptionsForTesting => _raw;
}
/// A [FileSystem] that only allows access to files that have been explicitly
diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
index 3484b81..6978d00 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -691,6 +691,14 @@
Instantiation result =
super.visitInstantiation(node, removalSentinel) as Instantiation;
Expression expression = result.expression;
+ if (expression is StaticGet && expression.target.isConst) {
+ // Handle [StaticGet] of constant fields also when these are not inlined.
+ expression = (expression.target as Field).initializer!;
+ } else if (expression is VariableGet && expression.variable.isConst) {
+ // Handle [VariableGet] of constant locals also when these are not
+ // inlined.
+ expression = expression.variable.initializer!;
+ }
if (expression is ConstantExpression) {
if (result.typeArguments.every(isInstantiated)) {
return evaluateAndTransformWithContext(node, result);
@@ -882,6 +890,9 @@
}
bool shouldInline(Expression initializer) {
+ if (backend.alwaysInlineConstants) {
+ return true;
+ }
if (initializer is ConstantExpression) {
return backend.shouldInlineConstant(initializer);
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index a4ccfdf..e8ab694 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -1234,7 +1234,7 @@
constants.ConstantEvaluationData constantEvaluationData =
constants.transformLibraries(
loader.libraries,
- backendTarget.constantsBackend(loader.coreTypes),
+ backendTarget.constantsBackend,
environmentDefines,
environment,
new KernelConstantErrorReporter(loader),
@@ -1290,7 +1290,7 @@
constants.transformProcedure(
procedure,
- backendTarget.constantsBackend(loader.coreTypes),
+ backendTarget.constantsBackend,
environmentDefines,
environment,
new KernelConstantErrorReporter(loader),
diff --git a/pkg/front_end/lib/src/fasta/kernel/verifier.dart b/pkg/front_end/lib/src/fasta/kernel/verifier.dart
index efc9de8..7543cd9 100644
--- a/pkg/front_end/lib/src/fasta/kernel/verifier.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/verifier.dart
@@ -33,8 +33,8 @@
List<LocatedMessage> verifyComponent(Component component, Target target,
{bool? isOutline, bool? afterConst, bool skipPlatform: false}) {
- FastaVerifyingVisitor verifier =
- new FastaVerifyingVisitor(target, isOutline, afterConst, skipPlatform);
+ FastaVerifyingVisitor verifier = new FastaVerifyingVisitor(target,
+ isOutline: isOutline, afterConst: afterConst, skipPlatform: skipPlatform);
component.accept(verifier);
return verifier.errors;
}
@@ -47,9 +47,13 @@
final List<TreeNode> treeNodeStack = <TreeNode>[];
final bool skipPlatform;
- FastaVerifyingVisitor(
- this.target, bool? isOutline, bool? afterConst, this.skipPlatform)
- : super(isOutline: isOutline, afterConst: afterConst);
+ FastaVerifyingVisitor(this.target,
+ {bool? isOutline, bool? afterConst, required this.skipPlatform})
+ : super(
+ isOutline: isOutline,
+ afterConst: afterConst,
+ constantsAreAlwaysInlined:
+ target.constantsBackend.alwaysInlineConstants);
/// Invoked by all visit methods if the visited node is a [TreeNode].
void enterTreeNode(TreeNode node) {
diff --git a/pkg/front_end/test/constant_evaluator_benchmark.dart b/pkg/front_end/test/constant_evaluator_benchmark.dart
index 11ff8c4..63900b8 100644
--- a/pkg/front_end/test/constant_evaluator_benchmark.dart
+++ b/pkg/front_end/test/constant_evaluator_benchmark.dart
@@ -80,7 +80,7 @@
stopwatch.reset();
CoreTypes coreTypes = new CoreTypes(component);
ConstantsBackend constantsBackend =
- target.backendTarget.constantsBackend(coreTypes);
+ target.backendTarget.constantsBackend;
ClassHierarchy hierarchy = new ClassHierarchy(component, coreTypes);
TypeEnvironment environment = new TypeEnvironment(coreTypes, hierarchy);
if (verbose) {
diff --git a/pkg/front_end/test/fasta/testing/suite.dart b/pkg/front_end/test/fasta/testing/suite.dart
index f38eaff..607d44c 100644
--- a/pkg/front_end/test/fasta/testing/suite.dart
+++ b/pkg/front_end/test/fasta/testing/suite.dart
@@ -879,8 +879,7 @@
Future<Result<ComponentResult>> run(
ComponentResult result, FastaContext context) async {
KernelTarget target = result.sourceTarget;
- ConstantsBackend constantsBackend =
- target.backendTarget.constantsBackend(target.loader.coreTypes);
+ ConstantsBackend constantsBackend = target.backendTarget.constantsBackend;
TypeEnvironment environment =
new TypeEnvironment(target.loader.coreTypes, target.loader.hierarchy);
StressConstantEvaluatorVisitor stressConstantEvaluatorVisitor =
@@ -1971,19 +1970,20 @@
Component component = result.component;
StringBuffer messages = new StringBuffer();
- ProcessedOptions options = new ProcessedOptions(
- options: new CompilerOptions()
- ..onDiagnostic = (DiagnosticMessage message) {
- if (messages.isNotEmpty) {
- messages.write("\n");
- }
- messages.writeAll(message.plainTextFormatted, "\n");
- });
- return await CompilerContext.runWithOptions(options,
- (compilerContext) async {
+ void Function(DiagnosticMessage)? previousOnDiagnostics =
+ result.options.rawOptionsForTesting.onDiagnostic;
+ result.options.rawOptionsForTesting.onDiagnostic =
+ (DiagnosticMessage message) {
+ if (messages.isNotEmpty) {
+ messages.write("\n");
+ }
+ messages.writeAll(message.plainTextFormatted, "\n");
+ };
+ Result<ComponentResult> verifyResult = await CompilerContext.runWithOptions(
+ result.options, (compilerContext) async {
compilerContext.uriToSource.addAll(component.uriToSource);
List<LocatedMessage> verificationErrors = verifyComponent(
- component, options.target,
+ component, result.options.target,
isOutline: !fullCompile, skipPlatform: true);
assert(verificationErrors.isEmpty || messages.isNotEmpty);
if (messages.isEmpty) {
@@ -1993,6 +1993,8 @@
null, context.expectationSet["VerificationError"], "$messages");
}
}, errorOnMissingInput: false);
+ result.options.rawOptionsForTesting.onDiagnostic = previousOnDiagnostics;
+ return verifyResult;
}
}
diff --git a/pkg/front_end/test/issue_34856_test.dart b/pkg/front_end/test/issue_34856_test.dart
index d291270..a82d5c5 100644
--- a/pkg/front_end/test/issue_34856_test.dart
+++ b/pkg/front_end/test/issue_34856_test.dart
@@ -30,6 +30,7 @@
import 'package:front_end/src/fasta/kernel/verifier.dart' show verifyComponent;
import 'package:kernel/ast.dart' show Component;
+import 'package:kernel/target/targets.dart';
const Map<String, String> files = const <String, String>{
"repro.dart": """
@@ -88,7 +89,8 @@
options = new CompilerOptions()
..fileSystem = fs
..additionalDills = <Uri>[base.resolve("lib.dart.dill")]
- ..sdkSummary = platformDill;
+ ..sdkSummary = platformDill
+ ..target = new NoneTarget(new TargetFlags());
List<Uri> inputs = <Uri>[base.resolve("repro.dart")];
diff --git a/pkg/front_end/testcases/dartdevc/issue47108.dart b/pkg/front_end/testcases/dartdevc/issue47108.dart
new file mode 100644
index 0000000..e3dbb5c
--- /dev/null
+++ b/pkg/front_end/testcases/dartdevc/issue47108.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.
+
+class C<T> {}
+
+const constructorTearOff = C.new;
+
+main() {
+ // These instantiations are in a const context so they appear in the const pool.
+ const instantiatedTearOff = constructorTearOff<int>;
+ const instantiatedTearOff2 = constructorTearOff<int>;
+ print(identical(instantiatedTearOff, instantiatedTearOff2)); // Prints true
+
+ // These instantiations are not in a const context so they don't appear in the const pool.
+ print(identical(constructorTearOff<String>, constructorTearOff<String>)); // Prints false
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/dartdevc/issue47108.dart.strong.expect b/pkg/front_end/testcases/dartdevc/issue47108.dart.strong.expect
new file mode 100644
index 0000000..fb9bcc0
--- /dev/null
+++ b/pkg/front_end/testcases/dartdevc/issue47108.dart.strong.expect
@@ -0,0 +1,24 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class C<T extends core::Object? = dynamic> extends core::Object {
+ synthetic constructor •() → self::C<self::C::T%>
+ : super core::Object::•()
+ ;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::C<self::C::_#new#tearOff::T%>
+ return new self::C::•<self::C::_#new#tearOff::T%>();
+}
+static const field <T extends core::Object? = dynamic>() → self::C<T%> constructorTearOff = #C1;
+static method main() → dynamic {
+ const () → self::C<core::int> instantiatedTearOff = #C2;
+ const () → self::C<core::int> instantiatedTearOff2 = #C2;
+ core::print(core::identical(instantiatedTearOff, instantiatedTearOff2));
+ core::print(core::identical(#C3, #C3));
+}
+
+constants {
+ #C1 = static-tearoff self::C::_#new#tearOff
+ #C2 = instantiation self::C::_#new#tearOff <core::int>
+ #C3 = instantiation self::C::_#new#tearOff <core::String>
+}
diff --git a/pkg/front_end/testcases/dartdevc/issue47108.dart.strong.transformed.expect b/pkg/front_end/testcases/dartdevc/issue47108.dart.strong.transformed.expect
new file mode 100644
index 0000000..bae63cb
--- /dev/null
+++ b/pkg/front_end/testcases/dartdevc/issue47108.dart.strong.transformed.expect
@@ -0,0 +1,29 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class C<T extends core::Object? = dynamic> extends core::Object {
+ synthetic constructor •() → self::C<self::C::T%>
+ : super core::Object::•()
+ ;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::C<self::C::_#new#tearOff::T%>
+ return new self::C::•<self::C::_#new#tearOff::T%>();
+}
+static const field <T extends core::Object? = dynamic>() → self::C<T%> constructorTearOff = #C1;
+static method main() → dynamic {
+ const () → self::C<core::int> instantiatedTearOff = #C2;
+ const () → self::C<core::int> instantiatedTearOff2 = #C2;
+ core::print(core::identical(instantiatedTearOff, instantiatedTearOff2));
+ core::print(core::identical(#C3, #C3));
+}
+
+constants {
+ #C1 = static-tearoff self::C::_#new#tearOff
+ #C2 = instantiation self::C::_#new#tearOff <core::int>
+ #C3 = instantiation self::C::_#new#tearOff <core::String>
+}
+
+Extra constant evaluation status:
+Evaluated: StaticInvocation @ org-dartlang-testcase:///issue47108.dart:13:9 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///issue47108.dart:16:9 -> BoolConstant(true)
+Extra constant evaluation: evaluated: 5, effectively constant: 2
diff --git a/pkg/front_end/testcases/dartdevc/issue47108.dart.textual_outline.expect b/pkg/front_end/testcases/dartdevc/issue47108.dart.textual_outline.expect
new file mode 100644
index 0000000..f6ae152
--- /dev/null
+++ b/pkg/front_end/testcases/dartdevc/issue47108.dart.textual_outline.expect
@@ -0,0 +1,4 @@
+class C<T> {}
+
+const constructorTearOff = C.new;
+main() {}
diff --git a/pkg/front_end/testcases/dartdevc/issue47108.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/dartdevc/issue47108.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..f6ae152
--- /dev/null
+++ b/pkg/front_end/testcases/dartdevc/issue47108.dart.textual_outline_modelled.expect
@@ -0,0 +1,4 @@
+class C<T> {}
+
+const constructorTearOff = C.new;
+main() {}
diff --git a/pkg/front_end/testcases/dartdevc/issue47108.dart.weak.expect b/pkg/front_end/testcases/dartdevc/issue47108.dart.weak.expect
new file mode 100644
index 0000000..04f3df1
--- /dev/null
+++ b/pkg/front_end/testcases/dartdevc/issue47108.dart.weak.expect
@@ -0,0 +1,24 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class C<T extends core::Object? = dynamic> extends core::Object {
+ synthetic constructor •() → self::C<self::C::T%>
+ : super core::Object::•()
+ ;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::C<self::C::_#new#tearOff::T%>
+ return new self::C::•<self::C::_#new#tearOff::T%>();
+}
+static const field <T extends core::Object? = dynamic>() → self::C<T%> constructorTearOff = #C1;
+static method main() → dynamic {
+ const () → self::C<core::int> instantiatedTearOff = #C2;
+ const () → self::C<core::int> instantiatedTearOff2 = #C2;
+ core::print(core::identical(instantiatedTearOff, instantiatedTearOff2));
+ core::print(core::identical(#C3, #C3));
+}
+
+constants {
+ #C1 = static-tearoff self::C::_#new#tearOff
+ #C2 = instantiation self::C::_#new#tearOff <core::int*>
+ #C3 = instantiation self::C::_#new#tearOff <core::String*>
+}
diff --git a/pkg/front_end/testcases/dartdevc/issue47108.dart.weak.outline.expect b/pkg/front_end/testcases/dartdevc/issue47108.dart.weak.outline.expect
new file mode 100644
index 0000000..1d9f460
--- /dev/null
+++ b/pkg/front_end/testcases/dartdevc/issue47108.dart.weak.outline.expect
@@ -0,0 +1,18 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class C<T extends core::Object? = dynamic> extends core::Object {
+ synthetic constructor •() → self::C<self::C::T%>
+ ;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::C<self::C::_#new#tearOff::T%>
+ return new self::C::•<self::C::_#new#tearOff::T%>();
+}
+static const field <T extends core::Object? = dynamic>() → self::C<T%> constructorTearOff = self::C::_#new#tearOff;
+static method main() → dynamic
+ ;
+
+
+Extra constant evaluation status:
+Evaluated: StaticTearOff @ org-dartlang-testcase:///issue47108.dart:7:28 -> StaticTearOffConstant(C._#new#tearOff)
+Extra constant evaluation: evaluated: 2, effectively constant: 1
diff --git a/pkg/front_end/testcases/dartdevc/issue47108.dart.weak.transformed.expect b/pkg/front_end/testcases/dartdevc/issue47108.dart.weak.transformed.expect
new file mode 100644
index 0000000..0f3b2dc
--- /dev/null
+++ b/pkg/front_end/testcases/dartdevc/issue47108.dart.weak.transformed.expect
@@ -0,0 +1,29 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class C<T extends core::Object? = dynamic> extends core::Object {
+ synthetic constructor •() → self::C<self::C::T%>
+ : super core::Object::•()
+ ;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::C<self::C::_#new#tearOff::T%>
+ return new self::C::•<self::C::_#new#tearOff::T%>();
+}
+static const field <T extends core::Object? = dynamic>() → self::C<T%> constructorTearOff = #C1;
+static method main() → dynamic {
+ const () → self::C<core::int> instantiatedTearOff = #C2;
+ const () → self::C<core::int> instantiatedTearOff2 = #C2;
+ core::print(core::identical(instantiatedTearOff, instantiatedTearOff2));
+ core::print(core::identical(#C3, #C3));
+}
+
+constants {
+ #C1 = static-tearoff self::C::_#new#tearOff
+ #C2 = instantiation self::C::_#new#tearOff <core::int*>
+ #C3 = instantiation self::C::_#new#tearOff <core::String*>
+}
+
+Extra constant evaluation status:
+Evaluated: StaticInvocation @ org-dartlang-testcase:///issue47108.dart:13:9 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///issue47108.dart:16:9 -> BoolConstant(true)
+Extra constant evaluation: evaluated: 5, effectively constant: 2
diff --git a/pkg/kernel/lib/target/targets.dart b/pkg/kernel/lib/target/targets.dart
index 82718b5..1cb1b2c 100644
--- a/pkg/kernel/lib/target/targets.dart
+++ b/pkg/kernel/lib/target/targets.dart
@@ -112,6 +112,10 @@
/// Number semantics to use for this backend.
NumberSemantics get numberSemantics => NumberSemantics.vm;
+ /// If true, all constants are inlined. Otherwise [shouldInlineConstant] is
+ /// called to determine whether a constant expression should be inlined.
+ bool get alwaysInlineConstants => true;
+
/// Inline control of constant variables. The given constant expression
/// is the initializer of a [Field] or [VariableDeclaration] node.
/// If this method returns `true`, the variable will be inlined at all
@@ -119,7 +123,11 @@
/// by the `keepFields` or `keepLocals` properties).
/// This method must be deterministic, i.e. it must always return the same
/// value for the same constant value and place in the AST.
- bool shouldInlineConstant(ConstantExpression initializer) => true;
+ ///
+ /// This is only called if [alwaysInlineConstants] is `true`.
+ bool shouldInlineConstant(ConstantExpression initializer) =>
+ throw new UnsupportedError(
+ 'Per-value constant inlining is not supported');
/// Whether this target supports unevaluated constants.
///
@@ -445,7 +453,7 @@
Class? concreteDoubleLiteralClass(CoreTypes coreTypes, double value) => null;
Class? concreteStringLiteralClass(CoreTypes coreTypes, String value) => null;
- ConstantsBackend constantsBackend(CoreTypes coreTypes);
+ ConstantsBackend get constantsBackend;
}
class NoneConstantsBackend extends ConstantsBackend {
@@ -517,7 +525,7 @@
}
@override
- ConstantsBackend constantsBackend(CoreTypes coreTypes) =>
+ ConstantsBackend get constantsBackend =>
// TODO(johnniwinther): Should this vary with the use case?
const NoneConstantsBackend(supportsUnevaluatedConstants: true);
}
@@ -763,9 +771,7 @@
}
@override
- ConstantsBackend constantsBackend(CoreTypes coreTypes) {
- return _target.constantsBackend(coreTypes);
- }
+ ConstantsBackend get constantsBackend => _target.constantsBackend;
@override
bool enableNative(Uri uri) {
diff --git a/pkg/kernel/lib/verifier.dart b/pkg/kernel/lib/verifier.dart
index ec9a9aa..051bc3a 100644
--- a/pkg/kernel/lib/verifier.dart
+++ b/pkg/kernel/lib/verifier.dart
@@ -8,9 +8,12 @@
import 'transformations/flags.dart';
import 'type_environment.dart' show StatefulStaticTypeContext, TypeEnvironment;
-void verifyComponent(Component component, {bool? isOutline, bool? afterConst}) {
+void verifyComponent(Component component,
+ {bool? isOutline, bool? afterConst, bool constantsAreAlwaysInlined: true}) {
VerifyingVisitor.check(component,
- isOutline: isOutline, afterConst: afterConst);
+ isOutline: isOutline,
+ afterConst: afterConst,
+ constantsAreAlwaysInlined: constantsAreAlwaysInlined);
}
class VerificationError {
@@ -67,6 +70,9 @@
/// a verification error for anything that should have been removed by it.
final bool afterConst;
+ /// If true, constant fields and local variables are expected to be inlined.
+ final bool constantsAreAlwaysInlined;
+
AsyncMarker currentAsyncMarker = AsyncMarker.Sync;
bool inCatchBlock = false;
@@ -88,12 +94,20 @@
TreeNode? get currentClassOrExtensionOrMember =>
currentMember ?? currentClass ?? currentExtension;
- static void check(Component component, {bool? isOutline, bool? afterConst}) {
- component.accept(
- new VerifyingVisitor(isOutline: isOutline, afterConst: afterConst));
+ static void check(Component component,
+ {bool? isOutline,
+ bool? afterConst,
+ required bool constantsAreAlwaysInlined}) {
+ component.accept(new VerifyingVisitor(
+ isOutline: isOutline,
+ afterConst: afterConst,
+ constantsAreAlwaysInlined: constantsAreAlwaysInlined));
}
- VerifyingVisitor({bool? isOutline, bool? afterConst})
+ VerifyingVisitor(
+ {bool? isOutline,
+ bool? afterConst,
+ required this.constantsAreAlwaysInlined})
: isOutline = isOutline ?? false,
afterConst = afterConst ?? !(isOutline ?? false);
@@ -577,10 +591,12 @@
declareVariable(node);
if (afterConst && node.isConst) {
Expression? initializer = node.initializer;
- if (!(initializer is InvalidExpression ||
- initializer is ConstantExpression &&
- initializer.constant is UnevaluatedConstant)) {
- problem(node, "Constant VariableDeclaration");
+ if (constantsAreAlwaysInlined) {
+ if (!(initializer is InvalidExpression ||
+ initializer is ConstantExpression &&
+ initializer.constant is UnevaluatedConstant)) {
+ problem(node, "Constant VariableDeclaration");
+ }
}
}
}
@@ -589,7 +605,7 @@
void visitVariableGet(VariableGet node) {
checkVariableInScope(node.variable, node);
visitChildren(node);
- if (afterConst && node.variable.isConst) {
+ if (constantsAreAlwaysInlined && afterConst && node.variable.isConst) {
problem(node, "VariableGet of const variable '${node.variable}'.");
}
}
@@ -621,7 +637,10 @@
if (node.target.isInstanceMember) {
problem(node, "StaticGet of '${node.target}' that's an instance member.");
}
- if (afterConst && node.target is Field && node.target.isConst) {
+ if (constantsAreAlwaysInlined &&
+ afterConst &&
+ node.target is Field &&
+ node.target.isConst) {
problem(node, "StaticGet of const field '${node.target}'.");
}
}
diff --git a/pkg/vm/lib/target/vm.dart b/pkg/vm/lib/target/vm.dart
index 079aca9..b788180 100644
--- a/pkg/vm/lib/target/vm.dart
+++ b/pkg/vm/lib/target/vm.dart
@@ -488,7 +488,7 @@
}
@override
- ConstantsBackend constantsBackend(CoreTypes coreTypes) => ConstantsBackend();
+ ConstantsBackend get constantsBackend => const ConstantsBackend();
@override
Map<String, String> updateEnvironmentDefines(Map<String, String> map) {
diff --git a/runtime/vm/compiler/aot/aot_call_specializer.cc b/runtime/vm/compiler/aot/aot_call_specializer.cc
index 8a0978b..6fa1d01 100644
--- a/runtime/vm/compiler/aot/aot_call_specializer.cc
+++ b/runtime/vm/compiler/aot/aot_call_specializer.cc
@@ -602,7 +602,7 @@
case Token::kNE: {
// TODO(dartbug.com/32166): Support EQ, NE for nullable doubles.
// (requires null-aware comparison instruction).
- if (left_type->IsDouble() && right_type->IsDouble()) {
+ if (!left_type->is_nullable() && !right_type->is_nullable()) {
left_value = PrepareStaticOpInput(left_value, kDoubleCid, instr);
right_value = PrepareStaticOpInput(right_value, kDoubleCid, instr);
replacement = new (Z) EqualityCompareInstr(
diff --git a/runtime/vm/compiler/backend/il_test.cc b/runtime/vm/compiler/backend/il_test.cc
index 260d17d..d373a1a 100644
--- a/runtime/vm/compiler/backend/il_test.cc
+++ b/runtime/vm/compiler/backend/il_test.cc
@@ -604,4 +604,33 @@
RANGES_CONTAIN_EXPECTED_CIDS(abstract_range, expected_cids);
}
+// This test verifies that double == Smi is recognized and
+// implemented using EqualityCompare.
+// Regression test for https://github.com/dart-lang/sdk/issues/47031.
+ISOLATE_UNIT_TEST_CASE(IRTest_DoubleEqualsSmi) {
+ const char* kScript = R"(
+ bool foo(double x) => (x + 0.5) == 0;
+ main() {
+ foo(-0.5);
+ }
+ )";
+
+ const auto& root_library = Library::Handle(LoadTestScript(kScript));
+ const auto& function = Function::Handle(GetFunction(root_library, "foo"));
+
+ TestPipeline pipeline(function, CompilerPass::kAOT);
+ FlowGraph* flow_graph = pipeline.RunPasses({});
+
+ auto entry = flow_graph->graph_entry()->normal_entry();
+ ILMatcher cursor(flow_graph, entry, /*trace=*/true,
+ ParallelMovesHandling::kSkip);
+
+ RELEASE_ASSERT(cursor.TryMatch({
+ kMoveGlob,
+ kMatchAndMoveBinaryDoubleOp,
+ kMatchAndMoveEqualityCompare,
+ kMatchReturn,
+ }));
+}
+
} // namespace dart
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index 5ef43b9..108213c 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -1932,13 +1932,6 @@
// The target didn't change, so we can stay inside monomorphic state.
if (ic_data.NumberOfChecksIs(1) &&
(ic_data.GetReceiverClassIdAt(0) == receiver().GetClassId())) {
- // We got a miss because the old target code got disabled.
- // Notice the reverse is not true: If the old code got disabled, the call
- // might still have a different receiver then last time and possibly a
- // different target.
- ASSERT(miss_handler_ == MissHandler::kFixCallersTargetMonomorphic ||
- !IsolateGroup::Current()->ContainsOnlyOneIsolate());
-
// No need to update ICData - it's already up-to-date.
if (FLAG_trace_ic) {
diff --git a/sdk/lib/_internal/vm/lib/compact_hash.dart b/sdk/lib/_internal/vm/lib/compact_hash.dart
index 29c57e7..abd8baa 100644
--- a/sdk/lib/_internal/vm/lib/compact_hash.dart
+++ b/sdk/lib/_internal/vm/lib/compact_hash.dart
@@ -248,8 +248,6 @@
}
void _createIndex() {
- assert(_indexNullable == null);
-
final size = max(_data.length, _HashBase._INITIAL_INDEX_SIZE);
assert(size == _roundUpToPowerOfTwo(size));
final newIndex = new Uint32List(size);
@@ -827,8 +825,6 @@
}
void _createIndex() {
- assert(_indexNullable == null);
-
final size = _roundUpToPowerOfTwo(
max(_data.length * 2, _HashBase._INITIAL_INDEX_SIZE));
final index = new Uint32List(size);
diff --git a/tools/VERSION b/tools/VERSION
index fdc1fda..570bc94 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 15
PATCH 0
-PRERELEASE 89
+PRERELEASE 90
PRERELEASE_PATCH 0
\ No newline at end of file