[cfe] Keep non-proper renames distinct in constant evaluation

Closes https://github.com/dart-lang/sdk/issues/47462

Change-Id: I669ca4f97bfbe10900453b1aa78211c52e0ad2e6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/217720
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
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 90961d6..bc2af8b 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -35,7 +35,6 @@
 import '../fasta_codes.dart';
 
 import 'constant_int_folder.dart';
-import 'constructor_tearoff_lowering.dart';
 
 part 'constant_collection_builders.dart';
 
@@ -701,34 +700,6 @@
     if (expression is ConstantExpression) {
       if (result.typeArguments.every(isInstantiated)) {
         return evaluateAndTransformWithContext(node, result);
-      } else if (enableConstructorTearOff) {
-        Constant constant = expression.constant;
-        if (constant is TypedefTearOffConstant) {
-          Substitution substitution =
-              Substitution.fromPairs(constant.parameters, node.typeArguments);
-          return new Instantiation(
-              new ConstantExpression(constant.tearOffConstant,
-                  constant.tearOffConstant.getType(_staticTypeContext!))
-                ..fileOffset = expression.fileOffset,
-              constant.types.map(substitution.substituteType).toList());
-        } else {
-          LoweredTypedefTearOff? loweredTypedefTearOff =
-              LoweredTypedefTearOff.fromConstant(constant);
-          if (loweredTypedefTearOff != null) {
-            Constant tearOffConstant = constantEvaluator
-                .canonicalize(loweredTypedefTearOff.targetTearOffConstant);
-            Substitution substitution = Substitution.fromPairs(
-                loweredTypedefTearOff.typedefTearOff.function.typeParameters,
-                node.typeArguments);
-            return new Instantiation(
-                new ConstantExpression(tearOffConstant,
-                    tearOffConstant.getType(_staticTypeContext!))
-                  ..fileOffset = expression.fileOffset,
-                loweredTypedefTearOff.typeArguments
-                    .map(substitution.substituteType)
-                    .toList());
-          }
-        }
       }
     }
     return node;
@@ -3364,29 +3335,8 @@
         // ignore: unnecessary_null_comparison
         assert(types != null);
 
-        List<DartType> typeArguments = types;
-        if (constant is TypedefTearOffConstant) {
-          Substitution substitution =
-              Substitution.fromPairs(constant.parameters, typeArguments);
-          typeArguments =
-              constant.types.map(substitution.substituteType).toList();
-          constant = constant.tearOffConstant;
-        } else {
-          LoweredTypedefTearOff? loweredTypedefTearOff =
-              LoweredTypedefTearOff.fromConstant(constant);
-          if (loweredTypedefTearOff != null) {
-            constant =
-                canonicalize(loweredTypedefTearOff.targetTearOffConstant);
-            Substitution substitution = Substitution.fromPairs(
-                loweredTypedefTearOff.typedefTearOff.function.typeParameters,
-                node.typeArguments);
-            typeArguments = loweredTypedefTearOff.typeArguments
-                .map(substitution.substituteType)
-                .toList();
-          }
-        }
         return canonicalize(
-            new InstantiationConstant(constant, convertTypes(typeArguments)));
+            new InstantiationConstant(constant, convertTypes(types)));
       } else {
         // Probably unreachable.
         return createEvaluationErrorConstant(
diff --git a/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart b/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart
index e3dd8b1..244a71d 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart
@@ -428,19 +428,18 @@
 /// Reverse engineered typedef tear off information.
 class LoweredTypedefTearOff {
   Procedure typedefTearOff;
-  Constant targetTearOffConstant;
+  Expression targetTearOff;
   List<DartType> typeArguments;
 
   LoweredTypedefTearOff(
-      this.typedefTearOff, this.targetTearOffConstant, this.typeArguments);
+      this.typedefTearOff, this.targetTearOff, this.typeArguments);
 
-  /// Reverse engineers [constant] to a [LoweredTypedefTearOff] if [constant] is
-  /// the encoding of a lowered typedef tear off.
-  // TODO(johnniwinther): Check that this works with outlines.
-  static LoweredTypedefTearOff? fromConstant(Constant constant) {
-    if (constant is StaticTearOffConstant &&
-        isTypedefTearOffLowering(constant.target)) {
-      Procedure typedefTearOff = constant.target;
+  /// Reverse engineers [expression] to a [LoweredTypedefTearOff] if
+  /// [expression] is the encoding of a lowered typedef tear off.
+  static LoweredTypedefTearOff? fromExpression(Expression expression) {
+    if (expression is StaticTearOff &&
+        isTypedefTearOffLowering(expression.target)) {
+      Procedure typedefTearOff = expression.target;
       Statement? body = typedefTearOff.function.body;
       if (body is ReturnStatement) {
         Expression? constructorInvocation = body.expression;
@@ -463,15 +462,15 @@
               break;
             }
           }
-          Constant tearOffConstant;
+          Expression targetTearOff;
           if (target is Constructor ||
               target is Procedure && target.isFactory) {
-            tearOffConstant = new ConstructorTearOffConstant(target!);
+            targetTearOff = new ConstructorTearOff(target!);
           } else {
-            tearOffConstant = new StaticTearOffConstant(target as Procedure);
+            targetTearOff = new StaticTearOff(target as Procedure);
           }
           return new LoweredTypedefTearOff(
-              typedefTearOff, tearOffConstant, typeArguments!);
+              typedefTearOff, targetTearOff, typeArguments!);
         }
       }
     }
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 3fcba19..7e9d30a 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -36,6 +36,7 @@
 import '../fasta_codes.dart';
 
 import '../kernel/class_hierarchy_builder.dart' show ClassMember;
+import '../kernel/constructor_tearoff_lowering.dart';
 import '../kernel/kernel_helper.dart';
 import '../kernel/inference_visitor.dart';
 import '../kernel/internal_ast.dart';
@@ -4065,14 +4066,33 @@
       DartType tearOffType,
       Expression expression) {
     if (implicitInstantiation != null) {
+      List<DartType> typeArguments = implicitInstantiation.typeArguments;
       if (!isTopLevel) {
         checkBoundsInInstantiation(implicitInstantiation.functionType,
-            implicitInstantiation.typeArguments, expression.fileOffset,
+            typeArguments, expression.fileOffset,
             inferred: true);
       }
-      expression =
-          new Instantiation(expression, implicitInstantiation.typeArguments)
-            ..fileOffset = expression.fileOffset;
+      if (expression is TypedefTearOff) {
+        Substitution substitution =
+            Substitution.fromPairs(expression.typeParameters, typeArguments);
+        typeArguments =
+            expression.typeArguments.map(substitution.substituteType).toList();
+        expression = expression.expression;
+      } else {
+        LoweredTypedefTearOff? loweredTypedefTearOff =
+            LoweredTypedefTearOff.fromExpression(expression);
+        if (loweredTypedefTearOff != null) {
+          Substitution substitution = Substitution.fromPairs(
+              loweredTypedefTearOff.typedefTearOff.function.typeParameters,
+              typeArguments);
+          typeArguments = loweredTypedefTearOff.typeArguments
+              .map(substitution.substituteType)
+              .toList();
+          expression = loweredTypedefTearOff.targetTearOff;
+        }
+      }
+      expression = new Instantiation(expression, typeArguments)
+        ..fileOffset = expression.fileOffset;
       tearOffType = implicitInstantiation.instantiatedType;
     }
     return new ExpressionInferenceResult(tearOffType, expression);
diff --git a/pkg/front_end/testcases/constructor_tearoffs/inferred_non_proper_rename.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/inferred_non_proper_rename.dart.weak.outline.expect
index ab09476..8f1f43b 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/inferred_non_proper_rename.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/inferred_non_proper_rename.dart.weak.outline.expect
@@ -12,13 +12,13 @@
 static final field core::bool inSoundMode;
 static const field () → self::A<core::int> f1a = self::A::•<core::int>;
 static const field () → self::A<core::int> f1b = self::A::•<core::int>;
-static const field () → self::A<core::int> f1c = (<X extends core::num>.(self::A::•<X>))<core::int>;
+static const field () → self::A<core::int> f1c = self::A::•<core::int>;
 static const field () → self::A<core::int> g1a = self::A::•<core::int>;
 static const field () → self::A<core::int> g1b = self::A::•<core::int>;
-static const field () → self::A<core::int> g1c = (<unrelated Y extends core::Object? = dynamic>.(self::A::•<core::int>))<dynamic>;
+static const field () → self::A<core::int> g1c = self::A::•<core::int>;
 static const field () → self::A<core::int> h1a = self::A::•<core::int>;
 static const field () → self::A<core::int> h1b = self::A::•<core::int>;
-static const field () → self::A<core::int> h1c = (<X extends core::Object? = dynamic, unrelated Y extends core::Object? = dynamic>.(self::A::•<X%>))<core::int, dynamic>;
+static const field () → self::A<core::int> h1c = self::A::•<core::int>;
 static method main() → dynamic
   ;
 static method test<T extends core::num>() → dynamic
diff --git a/pkg/front_end/testcases/constructor_tearoffs/issue47462.dart b/pkg/front_end/testcases/constructor_tearoffs/issue47462.dart
new file mode 100644
index 0000000..91be77e
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/issue47462.dart
@@ -0,0 +1,39 @@
+// 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.
+
+typedef MyList<T extends num> = List<T>;
+
+main() {}
+
+test() {
+  const c1 = MyList<num>.filled;
+  const c2 = MyList<num>.filled;
+  const c3 = (MyList.filled)<num>;
+
+  const c4 = identical(c1, c2);
+  const c5 = identical(c1, c3);
+
+  expect(true, c4);
+  expect(false, c5);
+
+  expect(true, identical(c1, c2));
+  expect(false, identical(c1, c3));
+
+  var v1 = MyList<num>.filled;
+  var v2 = MyList<num>.filled;
+  var v3 = (MyList.filled)<num>;
+
+  var v4 = identical(v1, v2);
+  var v5 = identical(v1, v3);
+
+  expect(true, v4);
+  expect(false, v5);
+
+  expect(true, identical(v1, v2));
+  expect(false, identical(v1, v3));
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/issue47462.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/issue47462.dart.strong.expect
new file mode 100644
index 0000000..313acc1
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/issue47462.dart.strong.expect
@@ -0,0 +1,34 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef MyList<T extends core::num> = core::List<T>;
+static method main() → dynamic {}
+static method test() → dynamic {
+  self::expect(true, #C1);
+  self::expect(false, #C2);
+  self::expect(true, core::identical(#C4, #C4));
+  self::expect(false, core::identical(#C4, #C6));
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v1 = #C4;
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v2 = #C4;
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v3 = #C6;
+  core::bool v4 = core::identical(v1, v2);
+  core::bool v5 = core::identical(v1, v3);
+  self::expect(true, v4);
+  self::expect(false, v5);
+  self::expect(true, core::identical(v1, v2));
+  self::expect(false, core::identical(v1, v3));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+
+constants  {
+  #C1 = true
+  #C2 = false
+  #C3 = constructor-tearoff core::List::filled
+  #C4 = instantiation #C3 <core::num>
+  #C5 = typedef-tearoff <T extends core::num>.(#C3<T>)
+  #C6 = instantiation #C5 <core::num>
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/issue47462.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/issue47462.dart.strong.transformed.expect
new file mode 100644
index 0000000..b1acc2d
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/issue47462.dart.strong.transformed.expect
@@ -0,0 +1,39 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef MyList<T extends core::num> = core::List<T>;
+static method main() → dynamic {}
+static method test() → dynamic {
+  self::expect(true, #C1);
+  self::expect(false, #C2);
+  self::expect(true, core::identical(#C4, #C4));
+  self::expect(false, core::identical(#C4, #C6));
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v1 = #C4;
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v2 = #C4;
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v3 = #C6;
+  core::bool v4 = core::identical(v1, v2);
+  core::bool v5 = core::identical(v1, v3);
+  self::expect(true, v4);
+  self::expect(false, v5);
+  self::expect(true, core::identical(v1, v2));
+  self::expect(false, core::identical(v1, v3));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+
+constants  {
+  #C1 = true
+  #C2 = false
+  #C3 = constructor-tearoff core::List::filled
+  #C4 = instantiation #C3 <core::num>
+  #C5 = typedef-tearoff <T extends core::num>.(#C3<T>)
+  #C6 = instantiation #C5 <core::num>
+}
+
+Extra constant evaluation status:
+Evaluated: StaticInvocation @ org-dartlang-testcase:///issue47462.dart:20:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///issue47462.dart:21:17 -> BoolConstant(false)
+Extra constant evaluation: evaluated: 32, effectively constant: 2
diff --git a/pkg/front_end/testcases/constructor_tearoffs/issue47462.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/issue47462.dart.textual_outline.expect
new file mode 100644
index 0000000..3730164
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/issue47462.dart.textual_outline.expect
@@ -0,0 +1,4 @@
+typedef MyList<T extends num> = List<T>;
+main() {}
+test() {}
+expect(expected, actual) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/issue47462.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/issue47462.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..10f9adf
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/issue47462.dart.textual_outline_modelled.expect
@@ -0,0 +1,4 @@
+expect(expected, actual) {}
+main() {}
+test() {}
+typedef MyList<T extends num> = List<T>;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/issue47462.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/issue47462.dart.weak.expect
new file mode 100644
index 0000000..ff4b5b0
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/issue47462.dart.weak.expect
@@ -0,0 +1,34 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef MyList<T extends core::num> = core::List<T>;
+static method main() → dynamic {}
+static method test() → dynamic {
+  self::expect(true, #C1);
+  self::expect(false, #C2);
+  self::expect(true, core::identical(#C4, #C4));
+  self::expect(false, core::identical(#C4, #C6));
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v1 = #C4;
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v2 = #C4;
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v3 = #C6;
+  core::bool v4 = core::identical(v1, v2);
+  core::bool v5 = core::identical(v1, v3);
+  self::expect(true, v4);
+  self::expect(false, v5);
+  self::expect(true, core::identical(v1, v2));
+  self::expect(false, core::identical(v1, v3));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+
+constants  {
+  #C1 = true
+  #C2 = false
+  #C3 = constructor-tearoff core::List::filled
+  #C4 = instantiation #C3 <core::num*>
+  #C5 = typedef-tearoff <T extends core::num>.(#C3<T>)
+  #C6 = instantiation #C5 <core::num*>
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/issue47462.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/issue47462.dart.weak.outline.expect
new file mode 100644
index 0000000..88959f9
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/issue47462.dart.weak.outline.expect
@@ -0,0 +1,11 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef MyList<T extends core::num> = core::List<T>;
+static method main() → dynamic
+  ;
+static method test() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/issue47462.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/issue47462.dart.weak.transformed.expect
new file mode 100644
index 0000000..285da40f
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/issue47462.dart.weak.transformed.expect
@@ -0,0 +1,39 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef MyList<T extends core::num> = core::List<T>;
+static method main() → dynamic {}
+static method test() → dynamic {
+  self::expect(true, #C1);
+  self::expect(false, #C2);
+  self::expect(true, core::identical(#C4, #C4));
+  self::expect(false, core::identical(#C4, #C6));
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v1 = #C4;
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v2 = #C4;
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v3 = #C6;
+  core::bool v4 = core::identical(v1, v2);
+  core::bool v5 = core::identical(v1, v3);
+  self::expect(true, v4);
+  self::expect(false, v5);
+  self::expect(true, core::identical(v1, v2));
+  self::expect(false, core::identical(v1, v3));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+
+constants  {
+  #C1 = true
+  #C2 = false
+  #C3 = constructor-tearoff core::List::filled
+  #C4 = instantiation #C3 <core::num*>
+  #C5 = typedef-tearoff <T extends core::num>.(#C3<T>)
+  #C6 = instantiation #C5 <core::num*>
+}
+
+Extra constant evaluation status:
+Evaluated: StaticInvocation @ org-dartlang-testcase:///issue47462.dart:20:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///issue47462.dart:21:17 -> BoolConstant(false)
+Extra constant evaluation: evaluated: 32, effectively constant: 2
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_non_proper_rename.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_non_proper_rename.dart.weak.outline.expect
index e982aa8..1d3da75 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_non_proper_rename.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_non_proper_rename.dart.weak.outline.expect
@@ -23,19 +23,19 @@
 static final field core::bool inSoundMode;
 static const field () → self::A<core::int> f1a = self::A::_#new#tearOff<core::int>;
 static const field () → self::A<core::int> f1b = self::A::_#new#tearOff<core::int>;
-static const field () → self::A<core::int> f1c = self::_#F#new#tearOff<core::int>;
+static const field () → self::A<core::int> f1c = self::A::_#new#tearOff<core::int>;
 static const field () → self::A<core::int> f1d = self::A::_#fact#tearOff<core::int>;
 static const field () → self::A<core::int> f1e = self::A::_#fact#tearOff<core::int>;
-static const field () → self::A<core::int> f1f = self::_#F#fact#tearOff<core::int>;
+static const field () → self::A<core::int> f1f = self::A::_#fact#tearOff<core::int>;
 static const field () → self::A<core::int> f1g = self::A::_#redirect#tearOff<core::int>;
 static const field () → self::A<core::int> f1h = self::A::_#redirect#tearOff<core::int>;
-static const field () → self::A<core::int> f1i = self::_#F#redirect#tearOff<core::int>;
+static const field () → self::A<core::int> f1i = self::A::_#redirect#tearOff<core::int>;
 static const field () → self::A<core::int> g1a = self::A::_#new#tearOff<core::int>;
 static const field () → self::A<core::int> g1b = self::A::_#new#tearOff<core::int>;
-static const field () → self::A<core::int> g1c = self::_#G#new#tearOff<dynamic>;
+static const field () → self::A<core::int> g1c = self::A::_#new#tearOff<core::int>;
 static const field () → self::A<core::int> h1a = self::A::_#new#tearOff<core::int>;
 static const field () → self::A<core::int> h1b = self::A::_#new#tearOff<core::int>;
-static const field () → self::A<core::int> h1c = self::_#H#new#tearOff<core::int, dynamic>;
+static const field () → self::A<core::int> h1c = self::A::_#new#tearOff<core::int>;
 static method main() → dynamic
   ;
 static method test<T extends core::num>() → dynamic
@@ -66,17 +66,17 @@
 Evaluated: ConstructorTearOff @ org-dartlang-testcase:///inferred_non_proper_rename.dart:7:7 -> ConstructorTearOffConstant(A.redirect)
 Evaluated: Instantiation @ org-dartlang-testcase:///inferred_non_proper_rename.dart:17:13 -> InstantiationConstant(A._#new#tearOff<int*>)
 Evaluated: Instantiation @ org-dartlang-testcase:///inferred_non_proper_rename.dart:18:13 -> InstantiationConstant(A._#new#tearOff<int*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///inferred_non_proper_rename.dart:19:31 -> InstantiationConstant(A._#new#tearOff<int*>)
+Evaluated: Instantiation @ org-dartlang-testcase:///inferred_non_proper_rename.dart:19:25 -> InstantiationConstant(A._#new#tearOff<int*>)
 Evaluated: Instantiation @ org-dartlang-testcase:///inferred_non_proper_rename.dart:20:13 -> InstantiationConstant(A._#fact#tearOff<int*>)
 Evaluated: Instantiation @ org-dartlang-testcase:///inferred_non_proper_rename.dart:21:13 -> InstantiationConstant(A._#fact#tearOff<int*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///inferred_non_proper_rename.dart:22:31 -> InstantiationConstant(A._#fact#tearOff<int*>)
+Evaluated: Instantiation @ org-dartlang-testcase:///inferred_non_proper_rename.dart:22:25 -> InstantiationConstant(A._#fact#tearOff<int*>)
 Evaluated: Instantiation @ org-dartlang-testcase:///inferred_non_proper_rename.dart:23:13 -> InstantiationConstant(A._#redirect#tearOff<int*>)
 Evaluated: Instantiation @ org-dartlang-testcase:///inferred_non_proper_rename.dart:24:13 -> InstantiationConstant(A._#redirect#tearOff<int*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///inferred_non_proper_rename.dart:25:31 -> InstantiationConstant(A._#redirect#tearOff<int*>)
+Evaluated: Instantiation @ org-dartlang-testcase:///inferred_non_proper_rename.dart:25:25 -> InstantiationConstant(A._#redirect#tearOff<int*>)
 Evaluated: Instantiation @ org-dartlang-testcase:///inferred_non_proper_rename.dart:27:13 -> InstantiationConstant(A._#new#tearOff<int*>)
 Evaluated: Instantiation @ org-dartlang-testcase:///inferred_non_proper_rename.dart:28:13 -> InstantiationConstant(A._#new#tearOff<int*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///inferred_non_proper_rename.dart:29:31 -> InstantiationConstant(A._#new#tearOff<int*>)
+Evaluated: Instantiation @ org-dartlang-testcase:///inferred_non_proper_rename.dart:29:25 -> InstantiationConstant(A._#new#tearOff<int*>)
 Evaluated: Instantiation @ org-dartlang-testcase:///inferred_non_proper_rename.dart:31:13 -> InstantiationConstant(A._#new#tearOff<int*>)
 Evaluated: Instantiation @ org-dartlang-testcase:///inferred_non_proper_rename.dart:32:13 -> InstantiationConstant(A._#new#tearOff<int*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///inferred_non_proper_rename.dart:33:31 -> InstantiationConstant(A._#new#tearOff<int*>)
+Evaluated: Instantiation @ org-dartlang-testcase:///inferred_non_proper_rename.dart:33:25 -> InstantiationConstant(A._#new#tearOff<int*>)
 Extra constant evaluation: evaluated: 30, effectively constant: 16
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/issue47462.dart b/pkg/front_end/testcases/constructor_tearoffs/lowering/issue47462.dart
new file mode 100644
index 0000000..17b9e38
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/issue47462.dart
@@ -0,0 +1,37 @@
+// 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.
+
+typedef MyList<T extends num> = List<T>;
+
+main() {
+  const c1 = MyList<num>.filled;
+  const c2 = MyList<num>.filled;
+  const c3 = (MyList.filled)<num>;
+
+  const c4 = identical(c1, c2);
+  const c5 = identical(c1, c3);
+
+  expect(true, c4);
+  expect(false, c5);
+
+  expect(true, identical(c1, c2));
+  expect(false, identical(c1, c3));
+
+  var v1 = MyList<num>.filled;
+  var v2 = MyList<num>.filled;
+  var v3 = (MyList.filled)<num>;
+
+  var v4 = identical(v1, v2);
+  var v5 = identical(v1, v3);
+
+  expect(true, v4);
+  expect(false, v5);
+
+  expect(true, identical(v1, v2));
+  expect(false, identical(v1, v3));
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/issue47462.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/issue47462.dart.strong.expect
new file mode 100644
index 0000000..672dbca
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/issue47462.dart.strong.expect
@@ -0,0 +1,48 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef MyList<T extends core::num> = core::List<T>;
+static method main() → dynamic {
+  self::expect(true, #C1);
+  self::expect(false, #C2);
+  self::expect(true, core::identical(#C4, #C4));
+  self::expect(false, core::identical(#C4, #C6));
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v1 = #C4;
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v2 = #C4;
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v3 = #C6;
+  core::bool v4 = core::identical(v1, v2);
+  core::bool v5 = core::identical(v1, v3);
+  self::expect(true, v4);
+  self::expect(false, v5);
+  self::expect(true, core::identical(v1, v2));
+  self::expect(false, core::identical(v1, v3));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#new#tearOff<T extends core::num>([core::int? length = #C7]) → core::List<self::_#MyList#new#tearOff::T>
+  return core::List::•<self::_#MyList#new#tearOff::T>(length);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#filled#tearOff<T extends core::num>(core::int length, self::_#MyList#filled#tearOff::T fill, {core::bool growable = #C2}) → core::List<self::_#MyList#filled#tearOff::T>
+  return core::List::filled<self::_#MyList#filled#tearOff::T>(length, fill, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#empty#tearOff<T extends core::num>({core::bool growable = #C2}) → core::List<self::_#MyList#empty#tearOff::T>
+  return core::List::empty<self::_#MyList#empty#tearOff::T>(growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#from#tearOff<T extends core::num>(core::Iterable<dynamic> elements, {core::bool growable = #C1}) → core::List<self::_#MyList#from#tearOff::T>
+  return core::List::from<self::_#MyList#from#tearOff::T>(elements, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#of#tearOff<T extends core::num>(core::Iterable<self::_#MyList#of#tearOff::T> elements, {core::bool growable = #C1}) → core::List<self::_#MyList#of#tearOff::T>
+  return core::List::of<self::_#MyList#of#tearOff::T>(elements, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#generate#tearOff<T extends core::num>(core::int length, (core::int) → self::_#MyList#generate#tearOff::T generator, {core::bool growable = #C1}) → core::List<self::_#MyList#generate#tearOff::T>
+  return core::List::generate<self::_#MyList#generate#tearOff::T>(length, generator, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#unmodifiable#tearOff<T extends core::num>(core::Iterable<dynamic> elements) → core::List<self::_#MyList#unmodifiable#tearOff::T>
+  return core::List::unmodifiable<self::_#MyList#unmodifiable#tearOff::T>(elements);
+
+constants  {
+  #C1 = true
+  #C2 = false
+  #C3 = constructor-tearoff core::List::filled
+  #C4 = instantiation #C3 <core::num>
+  #C5 = static-tearoff self::_#MyList#filled#tearOff
+  #C6 = instantiation #C5 <core::num>
+  #C7 = null
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/issue47462.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/issue47462.dart.strong.transformed.expect
new file mode 100644
index 0000000..36b8a3e
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/issue47462.dart.strong.transformed.expect
@@ -0,0 +1,53 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef MyList<T extends core::num> = core::List<T>;
+static method main() → dynamic {
+  self::expect(true, #C1);
+  self::expect(false, #C2);
+  self::expect(true, core::identical(#C4, #C4));
+  self::expect(false, core::identical(#C4, #C6));
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v1 = #C4;
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v2 = #C4;
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v3 = #C6;
+  core::bool v4 = core::identical(v1, v2);
+  core::bool v5 = core::identical(v1, v3);
+  self::expect(true, v4);
+  self::expect(false, v5);
+  self::expect(true, core::identical(v1, v2));
+  self::expect(false, core::identical(v1, v3));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#new#tearOff<T extends core::num>([core::int? length = #C7]) → core::List<self::_#MyList#new#tearOff::T>
+  return core::_List::•<self::_#MyList#new#tearOff::T>(length);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#filled#tearOff<T extends core::num>(core::int length, self::_#MyList#filled#tearOff::T fill, {core::bool growable = #C2}) → core::List<self::_#MyList#filled#tearOff::T>
+  return core::List::filled<self::_#MyList#filled#tearOff::T>(length, fill, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#empty#tearOff<T extends core::num>({core::bool growable = #C2}) → core::List<self::_#MyList#empty#tearOff::T>
+  return core::List::empty<self::_#MyList#empty#tearOff::T>(growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#from#tearOff<T extends core::num>(core::Iterable<dynamic> elements, {core::bool growable = #C1}) → core::List<self::_#MyList#from#tearOff::T>
+  return core::List::from<self::_#MyList#from#tearOff::T>(elements, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#of#tearOff<T extends core::num>(core::Iterable<self::_#MyList#of#tearOff::T> elements, {core::bool growable = #C1}) → core::List<self::_#MyList#of#tearOff::T>
+  return core::List::of<self::_#MyList#of#tearOff::T>(elements, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#generate#tearOff<T extends core::num>(core::int length, (core::int) → self::_#MyList#generate#tearOff::T generator, {core::bool growable = #C1}) → core::List<self::_#MyList#generate#tearOff::T>
+  return core::List::generate<self::_#MyList#generate#tearOff::T>(length, generator, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#unmodifiable#tearOff<T extends core::num>(core::Iterable<dynamic> elements) → core::List<self::_#MyList#unmodifiable#tearOff::T>
+  return core::List::unmodifiable<self::_#MyList#unmodifiable#tearOff::T>(elements);
+
+constants  {
+  #C1 = true
+  #C2 = false
+  #C3 = constructor-tearoff core::List::filled
+  #C4 = instantiation #C3 <core::num>
+  #C5 = static-tearoff self::_#MyList#filled#tearOff
+  #C6 = instantiation #C5 <core::num>
+  #C7 = null
+}
+
+Extra constant evaluation status:
+Evaluated: StaticInvocation @ org-dartlang-testcase:///issue47462.dart:18:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///issue47462.dart:19:17 -> BoolConstant(false)
+Extra constant evaluation: evaluated: 52, effectively constant: 2
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/issue47462.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/issue47462.dart.textual_outline.expect
new file mode 100644
index 0000000..f4c644d
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/issue47462.dart.textual_outline.expect
@@ -0,0 +1,3 @@
+typedef MyList<T extends num> = List<T>;
+main() {}
+expect(expected, actual) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/issue47462.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/issue47462.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..f083298
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/issue47462.dart.textual_outline_modelled.expect
@@ -0,0 +1,3 @@
+expect(expected, actual) {}
+main() {}
+typedef MyList<T extends num> = List<T>;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/issue47462.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/issue47462.dart.weak.expect
new file mode 100644
index 0000000..2a6bd0b
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/issue47462.dart.weak.expect
@@ -0,0 +1,48 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef MyList<T extends core::num> = core::List<T>;
+static method main() → dynamic {
+  self::expect(true, #C1);
+  self::expect(false, #C2);
+  self::expect(true, core::identical(#C4, #C4));
+  self::expect(false, core::identical(#C4, #C6));
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v1 = #C4;
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v2 = #C4;
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v3 = #C6;
+  core::bool v4 = core::identical(v1, v2);
+  core::bool v5 = core::identical(v1, v3);
+  self::expect(true, v4);
+  self::expect(false, v5);
+  self::expect(true, core::identical(v1, v2));
+  self::expect(false, core::identical(v1, v3));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#new#tearOff<T extends core::num>([core::int? length = #C7]) → core::List<self::_#MyList#new#tearOff::T>
+  return core::List::•<self::_#MyList#new#tearOff::T>(length);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#filled#tearOff<T extends core::num>(core::int length, self::_#MyList#filled#tearOff::T fill, {core::bool growable = #C2}) → core::List<self::_#MyList#filled#tearOff::T>
+  return core::List::filled<self::_#MyList#filled#tearOff::T>(length, fill, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#empty#tearOff<T extends core::num>({core::bool growable = #C2}) → core::List<self::_#MyList#empty#tearOff::T>
+  return core::List::empty<self::_#MyList#empty#tearOff::T>(growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#from#tearOff<T extends core::num>(core::Iterable<dynamic> elements, {core::bool growable = #C1}) → core::List<self::_#MyList#from#tearOff::T>
+  return core::List::from<self::_#MyList#from#tearOff::T>(elements, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#of#tearOff<T extends core::num>(core::Iterable<self::_#MyList#of#tearOff::T> elements, {core::bool growable = #C1}) → core::List<self::_#MyList#of#tearOff::T>
+  return core::List::of<self::_#MyList#of#tearOff::T>(elements, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#generate#tearOff<T extends core::num>(core::int length, (core::int) → self::_#MyList#generate#tearOff::T generator, {core::bool growable = #C1}) → core::List<self::_#MyList#generate#tearOff::T>
+  return core::List::generate<self::_#MyList#generate#tearOff::T>(length, generator, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#unmodifiable#tearOff<T extends core::num>(core::Iterable<dynamic> elements) → core::List<self::_#MyList#unmodifiable#tearOff::T>
+  return core::List::unmodifiable<self::_#MyList#unmodifiable#tearOff::T>(elements);
+
+constants  {
+  #C1 = true
+  #C2 = false
+  #C3 = constructor-tearoff core::List::filled
+  #C4 = instantiation #C3 <core::num*>
+  #C5 = static-tearoff self::_#MyList#filled#tearOff
+  #C6 = instantiation #C5 <core::num*>
+  #C7 = null
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/issue47462.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/issue47462.dart.weak.outline.expect
new file mode 100644
index 0000000..b89a67b
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/issue47462.dart.weak.outline.expect
@@ -0,0 +1,23 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef MyList<T extends core::num> = core::List<T>;
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#new#tearOff<T extends core::num>([core::int? length]) → core::List<self::_#MyList#new#tearOff::T>
+  return core::List::•<self::_#MyList#new#tearOff::T>(length);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#filled#tearOff<T extends core::num>(core::int length, self::_#MyList#filled#tearOff::T fill, {core::bool growable}) → core::List<self::_#MyList#filled#tearOff::T>
+  return core::List::filled<self::_#MyList#filled#tearOff::T>(length, fill, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#empty#tearOff<T extends core::num>({core::bool growable}) → core::List<self::_#MyList#empty#tearOff::T>
+  return core::List::empty<self::_#MyList#empty#tearOff::T>(growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#from#tearOff<T extends core::num>(core::Iterable<dynamic> elements, {core::bool growable}) → core::List<self::_#MyList#from#tearOff::T>
+  return core::List::from<self::_#MyList#from#tearOff::T>(elements, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#of#tearOff<T extends core::num>(core::Iterable<self::_#MyList#of#tearOff::T> elements, {core::bool growable}) → core::List<self::_#MyList#of#tearOff::T>
+  return core::List::of<self::_#MyList#of#tearOff::T>(elements, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#generate#tearOff<T extends core::num>(core::int length, (core::int) → self::_#MyList#generate#tearOff::T generator, {core::bool growable}) → core::List<self::_#MyList#generate#tearOff::T>
+  return core::List::generate<self::_#MyList#generate#tearOff::T>(length, generator, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#unmodifiable#tearOff<T extends core::num>(core::Iterable<dynamic> elements) → core::List<self::_#MyList#unmodifiable#tearOff::T>
+  return core::List::unmodifiable<self::_#MyList#unmodifiable#tearOff::T>(elements);
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/issue47462.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/issue47462.dart.weak.transformed.expect
new file mode 100644
index 0000000..9e2f5a1
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/issue47462.dart.weak.transformed.expect
@@ -0,0 +1,53 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef MyList<T extends core::num> = core::List<T>;
+static method main() → dynamic {
+  self::expect(true, #C1);
+  self::expect(false, #C2);
+  self::expect(true, core::identical(#C4, #C4));
+  self::expect(false, core::identical(#C4, #C6));
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v1 = #C4;
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v2 = #C4;
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v3 = #C6;
+  core::bool v4 = core::identical(v1, v2);
+  core::bool v5 = core::identical(v1, v3);
+  self::expect(true, v4);
+  self::expect(false, v5);
+  self::expect(true, core::identical(v1, v2));
+  self::expect(false, core::identical(v1, v3));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#new#tearOff<T extends core::num>([core::int? length = #C7]) → core::List<self::_#MyList#new#tearOff::T>
+  return core::_List::•<self::_#MyList#new#tearOff::T>(length);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#filled#tearOff<T extends core::num>(core::int length, self::_#MyList#filled#tearOff::T fill, {core::bool growable = #C2}) → core::List<self::_#MyList#filled#tearOff::T>
+  return core::List::filled<self::_#MyList#filled#tearOff::T>(length, fill, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#empty#tearOff<T extends core::num>({core::bool growable = #C2}) → core::List<self::_#MyList#empty#tearOff::T>
+  return core::List::empty<self::_#MyList#empty#tearOff::T>(growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#from#tearOff<T extends core::num>(core::Iterable<dynamic> elements, {core::bool growable = #C1}) → core::List<self::_#MyList#from#tearOff::T>
+  return core::List::from<self::_#MyList#from#tearOff::T>(elements, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#of#tearOff<T extends core::num>(core::Iterable<self::_#MyList#of#tearOff::T> elements, {core::bool growable = #C1}) → core::List<self::_#MyList#of#tearOff::T>
+  return core::List::of<self::_#MyList#of#tearOff::T>(elements, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#generate#tearOff<T extends core::num>(core::int length, (core::int) → self::_#MyList#generate#tearOff::T generator, {core::bool growable = #C1}) → core::List<self::_#MyList#generate#tearOff::T>
+  return core::List::generate<self::_#MyList#generate#tearOff::T>(length, generator, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#unmodifiable#tearOff<T extends core::num>(core::Iterable<dynamic> elements) → core::List<self::_#MyList#unmodifiable#tearOff::T>
+  return core::List::unmodifiable<self::_#MyList#unmodifiable#tearOff::T>(elements);
+
+constants  {
+  #C1 = true
+  #C2 = false
+  #C3 = constructor-tearoff core::List::filled
+  #C4 = instantiation #C3 <core::num*>
+  #C5 = static-tearoff self::_#MyList#filled#tearOff
+  #C6 = instantiation #C5 <core::num*>
+  #C7 = null
+}
+
+Extra constant evaluation status:
+Evaluated: StaticInvocation @ org-dartlang-testcase:///issue47462.dart:18:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///issue47462.dart:19:17 -> BoolConstant(false)
+Extra constant evaluation: evaluated: 52, effectively constant: 2
diff --git a/pkg/front_end/testcases/general/issue47462.dart b/pkg/front_end/testcases/general/issue47462.dart
new file mode 100644
index 0000000..17b9e38
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue47462.dart
@@ -0,0 +1,37 @@
+// 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.
+
+typedef MyList<T extends num> = List<T>;
+
+main() {
+  const c1 = MyList<num>.filled;
+  const c2 = MyList<num>.filled;
+  const c3 = (MyList.filled)<num>;
+
+  const c4 = identical(c1, c2);
+  const c5 = identical(c1, c3);
+
+  expect(true, c4);
+  expect(false, c5);
+
+  expect(true, identical(c1, c2));
+  expect(false, identical(c1, c3));
+
+  var v1 = MyList<num>.filled;
+  var v2 = MyList<num>.filled;
+  var v3 = (MyList.filled)<num>;
+
+  var v4 = identical(v1, v2);
+  var v5 = identical(v1, v3);
+
+  expect(true, v4);
+  expect(false, v5);
+
+  expect(true, identical(v1, v2));
+  expect(false, identical(v1, v3));
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
diff --git a/pkg/front_end/testcases/general/issue47462.dart.textual_outline.expect b/pkg/front_end/testcases/general/issue47462.dart.textual_outline.expect
new file mode 100644
index 0000000..f4c644d
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue47462.dart.textual_outline.expect
@@ -0,0 +1,3 @@
+typedef MyList<T extends num> = List<T>;
+main() {}
+expect(expected, actual) {}
diff --git a/pkg/front_end/testcases/general/issue47462.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/issue47462.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..f083298
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue47462.dart.textual_outline_modelled.expect
@@ -0,0 +1,3 @@
+expect(expected, actual) {}
+main() {}
+typedef MyList<T extends num> = List<T>;
diff --git a/pkg/front_end/testcases/general/issue47462.dart.weak.expect b/pkg/front_end/testcases/general/issue47462.dart.weak.expect
new file mode 100644
index 0000000..2a6bd0b
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue47462.dart.weak.expect
@@ -0,0 +1,48 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef MyList<T extends core::num> = core::List<T>;
+static method main() → dynamic {
+  self::expect(true, #C1);
+  self::expect(false, #C2);
+  self::expect(true, core::identical(#C4, #C4));
+  self::expect(false, core::identical(#C4, #C6));
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v1 = #C4;
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v2 = #C4;
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v3 = #C6;
+  core::bool v4 = core::identical(v1, v2);
+  core::bool v5 = core::identical(v1, v3);
+  self::expect(true, v4);
+  self::expect(false, v5);
+  self::expect(true, core::identical(v1, v2));
+  self::expect(false, core::identical(v1, v3));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#new#tearOff<T extends core::num>([core::int? length = #C7]) → core::List<self::_#MyList#new#tearOff::T>
+  return core::List::•<self::_#MyList#new#tearOff::T>(length);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#filled#tearOff<T extends core::num>(core::int length, self::_#MyList#filled#tearOff::T fill, {core::bool growable = #C2}) → core::List<self::_#MyList#filled#tearOff::T>
+  return core::List::filled<self::_#MyList#filled#tearOff::T>(length, fill, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#empty#tearOff<T extends core::num>({core::bool growable = #C2}) → core::List<self::_#MyList#empty#tearOff::T>
+  return core::List::empty<self::_#MyList#empty#tearOff::T>(growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#from#tearOff<T extends core::num>(core::Iterable<dynamic> elements, {core::bool growable = #C1}) → core::List<self::_#MyList#from#tearOff::T>
+  return core::List::from<self::_#MyList#from#tearOff::T>(elements, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#of#tearOff<T extends core::num>(core::Iterable<self::_#MyList#of#tearOff::T> elements, {core::bool growable = #C1}) → core::List<self::_#MyList#of#tearOff::T>
+  return core::List::of<self::_#MyList#of#tearOff::T>(elements, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#generate#tearOff<T extends core::num>(core::int length, (core::int) → self::_#MyList#generate#tearOff::T generator, {core::bool growable = #C1}) → core::List<self::_#MyList#generate#tearOff::T>
+  return core::List::generate<self::_#MyList#generate#tearOff::T>(length, generator, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#unmodifiable#tearOff<T extends core::num>(core::Iterable<dynamic> elements) → core::List<self::_#MyList#unmodifiable#tearOff::T>
+  return core::List::unmodifiable<self::_#MyList#unmodifiable#tearOff::T>(elements);
+
+constants  {
+  #C1 = true
+  #C2 = false
+  #C3 = constructor-tearoff core::List::filled
+  #C4 = instantiation #C3 <core::num*>
+  #C5 = static-tearoff self::_#MyList#filled#tearOff
+  #C6 = instantiation #C5 <core::num*>
+  #C7 = null
+}
diff --git a/pkg/front_end/testcases/general/issue47462.dart.weak.outline.expect b/pkg/front_end/testcases/general/issue47462.dart.weak.outline.expect
new file mode 100644
index 0000000..b89a67b
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue47462.dart.weak.outline.expect
@@ -0,0 +1,23 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef MyList<T extends core::num> = core::List<T>;
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#new#tearOff<T extends core::num>([core::int? length]) → core::List<self::_#MyList#new#tearOff::T>
+  return core::List::•<self::_#MyList#new#tearOff::T>(length);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#filled#tearOff<T extends core::num>(core::int length, self::_#MyList#filled#tearOff::T fill, {core::bool growable}) → core::List<self::_#MyList#filled#tearOff::T>
+  return core::List::filled<self::_#MyList#filled#tearOff::T>(length, fill, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#empty#tearOff<T extends core::num>({core::bool growable}) → core::List<self::_#MyList#empty#tearOff::T>
+  return core::List::empty<self::_#MyList#empty#tearOff::T>(growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#from#tearOff<T extends core::num>(core::Iterable<dynamic> elements, {core::bool growable}) → core::List<self::_#MyList#from#tearOff::T>
+  return core::List::from<self::_#MyList#from#tearOff::T>(elements, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#of#tearOff<T extends core::num>(core::Iterable<self::_#MyList#of#tearOff::T> elements, {core::bool growable}) → core::List<self::_#MyList#of#tearOff::T>
+  return core::List::of<self::_#MyList#of#tearOff::T>(elements, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#generate#tearOff<T extends core::num>(core::int length, (core::int) → self::_#MyList#generate#tearOff::T generator, {core::bool growable}) → core::List<self::_#MyList#generate#tearOff::T>
+  return core::List::generate<self::_#MyList#generate#tearOff::T>(length, generator, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#unmodifiable#tearOff<T extends core::num>(core::Iterable<dynamic> elements) → core::List<self::_#MyList#unmodifiable#tearOff::T>
+  return core::List::unmodifiable<self::_#MyList#unmodifiable#tearOff::T>(elements);
diff --git a/pkg/front_end/testcases/general/issue47462.dart.weak.transformed.expect b/pkg/front_end/testcases/general/issue47462.dart.weak.transformed.expect
new file mode 100644
index 0000000..9e2f5a1
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue47462.dart.weak.transformed.expect
@@ -0,0 +1,53 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef MyList<T extends core::num> = core::List<T>;
+static method main() → dynamic {
+  self::expect(true, #C1);
+  self::expect(false, #C2);
+  self::expect(true, core::identical(#C4, #C4));
+  self::expect(false, core::identical(#C4, #C6));
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v1 = #C4;
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v2 = #C4;
+  (core::int, core::num, {growable: core::bool}) → core::List<core::num> v3 = #C6;
+  core::bool v4 = core::identical(v1, v2);
+  core::bool v5 = core::identical(v1, v3);
+  self::expect(true, v4);
+  self::expect(false, v5);
+  self::expect(true, core::identical(v1, v2));
+  self::expect(false, core::identical(v1, v3));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#new#tearOff<T extends core::num>([core::int? length = #C7]) → core::List<self::_#MyList#new#tearOff::T>
+  return core::_List::•<self::_#MyList#new#tearOff::T>(length);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#filled#tearOff<T extends core::num>(core::int length, self::_#MyList#filled#tearOff::T fill, {core::bool growable = #C2}) → core::List<self::_#MyList#filled#tearOff::T>
+  return core::List::filled<self::_#MyList#filled#tearOff::T>(length, fill, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#empty#tearOff<T extends core::num>({core::bool growable = #C2}) → core::List<self::_#MyList#empty#tearOff::T>
+  return core::List::empty<self::_#MyList#empty#tearOff::T>(growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#from#tearOff<T extends core::num>(core::Iterable<dynamic> elements, {core::bool growable = #C1}) → core::List<self::_#MyList#from#tearOff::T>
+  return core::List::from<self::_#MyList#from#tearOff::T>(elements, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#of#tearOff<T extends core::num>(core::Iterable<self::_#MyList#of#tearOff::T> elements, {core::bool growable = #C1}) → core::List<self::_#MyList#of#tearOff::T>
+  return core::List::of<self::_#MyList#of#tearOff::T>(elements, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#generate#tearOff<T extends core::num>(core::int length, (core::int) → self::_#MyList#generate#tearOff::T generator, {core::bool growable = #C1}) → core::List<self::_#MyList#generate#tearOff::T>
+  return core::List::generate<self::_#MyList#generate#tearOff::T>(length, generator, growable: growable);
+static method /* from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/array_patch.dart */ _#MyList#unmodifiable#tearOff<T extends core::num>(core::Iterable<dynamic> elements) → core::List<self::_#MyList#unmodifiable#tearOff::T>
+  return core::List::unmodifiable<self::_#MyList#unmodifiable#tearOff::T>(elements);
+
+constants  {
+  #C1 = true
+  #C2 = false
+  #C3 = constructor-tearoff core::List::filled
+  #C4 = instantiation #C3 <core::num*>
+  #C5 = static-tearoff self::_#MyList#filled#tearOff
+  #C6 = instantiation #C5 <core::num*>
+  #C7 = null
+}
+
+Extra constant evaluation status:
+Evaluated: StaticInvocation @ org-dartlang-testcase:///issue47462.dart:18:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///issue47462.dart:19:17 -> BoolConstant(false)
+Extra constant evaluation: evaluated: 52, effectively constant: 2