[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