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