[cfe] Eagerly canonicalize instantiations
With the constructor-tearoff feature, effectively constant
instantiations are canonicalized.
Change-Id: I4e83fef47e5a404da19667ccfb1d13a3b00d632f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/204960
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Dmitry Stefantsov <dmitryas@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 1c7f034..737f649 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -86,6 +86,7 @@
required bool desugarSets,
required bool enableTripleShift,
required bool enableConstFunctions,
+ required bool enableConstructorTearOff,
required bool errorOnUnevaluatedConstant,
CoreTypes? coreTypes,
ClassHierarchy? hierarchy}) {
@@ -99,6 +100,8 @@
assert(enableConstFunctions != null);
// ignore: unnecessary_null_comparison
assert(errorOnUnevaluatedConstant != null);
+ // ignore: unnecessary_null_comparison
+ assert(enableConstructorTearOff != null);
coreTypes ??= new CoreTypes(component);
hierarchy ??= new ClassHierarchy(component, coreTypes);
@@ -110,7 +113,8 @@
enableTripleShift: enableTripleShift,
enableConstFunctions: enableConstFunctions,
errorOnUnevaluatedConstant: errorOnUnevaluatedConstant,
- evaluateAnnotations: evaluateAnnotations);
+ evaluateAnnotations: evaluateAnnotations,
+ enableConstructorTearOff: enableConstructorTearOff);
return component;
}
@@ -124,7 +128,8 @@
{required bool evaluateAnnotations,
required bool enableTripleShift,
required bool enableConstFunctions,
- required bool errorOnUnevaluatedConstant}) {
+ required bool errorOnUnevaluatedConstant,
+ required bool enableConstructorTearOff}) {
// ignore: unnecessary_null_comparison
assert(evaluateAnnotations != null);
// ignore: unnecessary_null_comparison
@@ -133,12 +138,15 @@
assert(enableConstFunctions != null);
// ignore: unnecessary_null_comparison
assert(errorOnUnevaluatedConstant != null);
+ // ignore: unnecessary_null_comparison
+ assert(enableConstructorTearOff != null);
final ConstantsTransformer constantsTransformer = new ConstantsTransformer(
backend,
environmentDefines,
evaluateAnnotations,
enableTripleShift,
enableConstFunctions,
+ enableConstructorTearOff,
errorOnUnevaluatedConstant,
typeEnvironment,
errorReporter,
@@ -156,10 +164,11 @@
TypeEnvironment typeEnvironment,
ErrorReporter errorReporter,
EvaluationMode evaluationMode,
- {bool evaluateAnnotations: true,
- bool enableTripleShift: false,
- bool enableConstFunctions: false,
- bool errorOnUnevaluatedConstant: false}) {
+ {required bool evaluateAnnotations,
+ required bool enableTripleShift,
+ required bool enableConstFunctions,
+ required bool enableConstructorTearOff,
+ required bool errorOnUnevaluatedConstant}) {
// ignore: unnecessary_null_comparison
assert(evaluateAnnotations != null);
// ignore: unnecessary_null_comparison
@@ -168,12 +177,15 @@
assert(enableConstFunctions != null);
// ignore: unnecessary_null_comparison
assert(errorOnUnevaluatedConstant != null);
+ // ignore: unnecessary_null_comparison
+ assert(enableConstructorTearOff != null);
final ConstantsTransformer constantsTransformer = new ConstantsTransformer(
backend,
environmentDefines,
evaluateAnnotations,
enableTripleShift,
enableConstFunctions,
+ enableConstructorTearOff,
errorOnUnevaluatedConstant,
typeEnvironment,
errorReporter,
@@ -360,6 +372,7 @@
final bool evaluateAnnotations;
final bool enableTripleShift;
final bool enableConstFunctions;
+ final bool enableConstructorTearOff;
final bool errorOnUnevaluatedConstant;
ConstantsTransformer(
@@ -368,6 +381,7 @@
this.evaluateAnnotations,
this.enableTripleShift,
this.enableConstFunctions,
+ this.enableConstructorTearOff,
this.errorOnUnevaluatedConstant,
this.typeEnvironment,
ErrorReporter errorReporter,
@@ -696,6 +710,18 @@
}
@override
+ TreeNode visitInstantiation(Instantiation node, TreeNode? removalSentinel) {
+ Instantiation result =
+ super.visitInstantiation(node, removalSentinel) as Instantiation;
+ if (enableConstructorTearOff &&
+ result.expression is ConstantExpression &&
+ result.typeArguments.every(isInstantiated)) {
+ return evaluateAndTransformWithContext(node, result);
+ }
+ return node;
+ }
+
+ @override
TreeNode visitSwitchCase(SwitchCase node, TreeNode? removalSentinel) {
transformExpressions(node.expressions, node);
return super.visitSwitchCase(node, removalSentinel);
@@ -872,9 +898,6 @@
final bool enableTripleShift;
final bool enableConstFunctions;
- final bool Function(DartType) isInstantiated =
- new IsInstantiatedVisitor().isInstantiated;
-
final Map<Constant, Constant> canonicalizationCache;
final Map<Node, Constant?> nodeCache;
final CloneVisitorNotMembers cloner = new CloneVisitorNotMembers();
@@ -4479,6 +4502,10 @@
}
}
+bool isInstantiated(DartType type) {
+ return type.accept(new IsInstantiatedVisitor());
+}
+
class IsInstantiatedVisitor extends DartTypeVisitor<bool> {
final _availableVariables = new Set<TypeParameter>();
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index eb47f3f..3fe1f73 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -1214,6 +1214,8 @@
isExperimentEnabledGlobally(ExperimentalFlag.tripleShift),
enableConstFunctions:
isExperimentEnabledGlobally(ExperimentalFlag.constFunctions),
+ enableConstructorTearOff:
+ isExperimentEnabledGlobally(ExperimentalFlag.constructorTearoffs),
errorOnUnevaluatedConstant: errorOnUnevaluatedConstant);
ticker.logMs("Evaluated constants");
@@ -1255,18 +1257,21 @@
constants.EvaluationMode evaluationMode = _getConstantEvaluationMode();
constants.transformProcedure(
- procedure,
- backendTarget.constantsBackend(loader.coreTypes),
- environmentDefines,
- environment,
- new KernelConstantErrorReporter(loader),
- evaluationMode,
- evaluateAnnotations: true,
- enableTripleShift:
- isExperimentEnabledGlobally(ExperimentalFlag.tripleShift),
- enableConstFunctions:
- isExperimentEnabledGlobally(ExperimentalFlag.constFunctions),
- errorOnUnevaluatedConstant: errorOnUnevaluatedConstant);
+ procedure,
+ backendTarget.constantsBackend(loader.coreTypes),
+ environmentDefines,
+ environment,
+ new KernelConstantErrorReporter(loader),
+ evaluationMode,
+ evaluateAnnotations: true,
+ enableTripleShift:
+ isExperimentEnabledGlobally(ExperimentalFlag.tripleShift),
+ enableConstFunctions:
+ isExperimentEnabledGlobally(ExperimentalFlag.constFunctions),
+ enableConstructorTearOff:
+ isExperimentEnabledGlobally(ExperimentalFlag.constructorTearoffs),
+ errorOnUnevaluatedConstant: errorOnUnevaluatedConstant,
+ );
ticker.logMs("Evaluated constants");
backendTarget.performTransformationsOnProcedure(
diff --git a/pkg/front_end/test/constant_evaluator_benchmark.dart b/pkg/front_end/test/constant_evaluator_benchmark.dart
index c1eb8fb..4595cf8 100644
--- a/pkg/front_end/test/constant_evaluator_benchmark.dart
+++ b/pkg/front_end/test/constant_evaluator_benchmark.dart
@@ -103,6 +103,8 @@
.isExperimentEnabledGlobally(ExperimentalFlag.tripleShift),
enableConstFunctions: target
.isExperimentEnabledGlobally(ExperimentalFlag.constFunctions),
+ enableConstructorTearOff: target.isExperimentEnabledGlobally(
+ ExperimentalFlag.constructorTearoffs),
errorOnUnevaluatedConstant:
incrementalCompiler.context.options.errorOnUnevaluatedConstant);
print("Transformed constants with $environmentDefinesDescription"
diff --git a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.strong.expect
index 912e906..efd5a53 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.strong.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.strong.expect
@@ -12,8 +12,8 @@
method inst<T extends core::Object? = dynamic>(self::C::inst::T% value) → self::C::inst::T%
return value;
method method() → void {
- (core::int) → core::int f1 = #C1<core::int>;
- core::String f1TypeName = (#C1<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+ (core::int) → core::int f1 = #C2;
+ core::String f1TypeName = (#C2).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f2 = this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
core::String f2TypeName = (this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f3 = this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
@@ -26,8 +26,8 @@
method minst<T extends core::Object? = dynamic>(self::M::minst::T% value) → self::M::minst::T%
return value;
method mmethod() → void {
- (core::int) → core::int f1 = #C2<core::int>;
- core::String f1TypeName = (#C2<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+ (core::int) → core::int f1 = #C4;
+ core::String f1TypeName = (#C4).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f2 = this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
core::String f2TypeName = (this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f3 = this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
@@ -68,8 +68,8 @@
static method Ext|get#einst(lowered final self::C #this) → <T extends core::Object? = dynamic>(T%) → T%
return <T extends core::Object? = dynamic>(T% value) → T% => self::Ext|einst<T%>(#this, value);
static method Ext|emethod(lowered final self::C #this) → void {
- (core::int) → core::int f1 = #C3<core::int>;
- core::String f1TypeName = (#C3<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+ (core::int) → core::int f1 = #C6;
+ core::String f1TypeName = (#C6).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f2 = self::Ext|get#einst(#this)<core::int>;
core::String f2TypeName = (self::Ext|get#einst(#this)<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f3 = self::Ext|get#einst(#this)<core::int>;
@@ -78,8 +78,8 @@
static method Ext|get#emethod(lowered final self::C #this) → () → void
return () → void => self::Ext|emethod(#this);
static method main() → void {
- core::Type t1 = #C4;
- core::Type t2 = #C5;
+ core::Type t1 = #C7;
+ core::Type t2 = #C8;
function local<T extends core::Object? = dynamic>(T% value) → T%
return value;
(core::int) → core::int f3 = local<core::int>;
@@ -87,14 +87,17 @@
(core::int) → core::int f4 = d.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
(core::int) → core::int f5 = d.{self::_D&C&M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
(core::int) → core::int f6 = self::Ext|get#einst(d)<core::int>;
- core::String typeName = (#C4).{core::Type::toString}(){() → core::String};
+ core::String typeName = (#C7).{core::Type::toString}(){() → core::String};
core::String functionTypeName = (local<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
}
constants {
#C1 = tearoff self::C::stat
- #C2 = tearoff self::M::mstat
- #C3 = tearoff self::Ext|estat
- #C4 = TypeLiteralConstant(core::List<core::int>)
- #C5 = TypeLiteralConstant(core::List<core::List<core::int>>)
+ #C2 = partial-instantiation self::C::stat <core::int>
+ #C3 = tearoff self::M::mstat
+ #C4 = partial-instantiation self::M::mstat <core::int>
+ #C5 = tearoff self::Ext|estat
+ #C6 = partial-instantiation self::Ext|estat <core::int>
+ #C7 = TypeLiteralConstant(core::List<core::int>)
+ #C8 = TypeLiteralConstant(core::List<core::List<core::int>>)
}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.strong.transformed.expect
index 3ed377b..ba6e6f0 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.strong.transformed.expect
@@ -12,8 +12,8 @@
method inst<T extends core::Object? = dynamic>(self::C::inst::T% value) → self::C::inst::T%
return value;
method method() → void {
- (core::int) → core::int f1 = #C1<core::int>;
- core::String f1TypeName = (#C1<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+ (core::int) → core::int f1 = #C2;
+ core::String f1TypeName = (#C2).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f2 = this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
core::String f2TypeName = (this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f3 = this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
@@ -26,8 +26,8 @@
method minst<T extends core::Object? = dynamic>(self::M::minst::T% value) → self::M::minst::T%
return value;
method mmethod() → void {
- (core::int) → core::int f1 = #C2<core::int>;
- core::String f1TypeName = (#C2<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+ (core::int) → core::int f1 = #C4;
+ core::String f1TypeName = (#C4).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f2 = this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
core::String f2TypeName = (this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f3 = this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
@@ -41,8 +41,8 @@
method minst<T extends core::Object? = dynamic>(self::_D&C&M::minst::T% value) → self::_D&C&M::minst::T%
return value;
method mmethod() → void {
- (core::int) → core::int f1 = #C2<core::int>;
- core::String f1TypeName = (#C2<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+ (core::int) → core::int f1 = #C4;
+ core::String f1TypeName = (#C4).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f2 = this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
core::String f2TypeName = (this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f3 = this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
@@ -76,8 +76,8 @@
static method Ext|get#einst(lowered final self::C #this) → <T extends core::Object? = dynamic>(T%) → T%
return <T extends core::Object? = dynamic>(T% value) → T% => self::Ext|einst<T%>(#this, value);
static method Ext|emethod(lowered final self::C #this) → void {
- (core::int) → core::int f1 = #C3<core::int>;
- core::String f1TypeName = (#C3<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+ (core::int) → core::int f1 = #C6;
+ core::String f1TypeName = (#C6).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f2 = self::Ext|get#einst(#this)<core::int>;
core::String f2TypeName = (self::Ext|get#einst(#this)<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f3 = self::Ext|get#einst(#this)<core::int>;
@@ -86,8 +86,8 @@
static method Ext|get#emethod(lowered final self::C #this) → () → void
return () → void => self::Ext|emethod(#this);
static method main() → void {
- core::Type t1 = #C4;
- core::Type t2 = #C5;
+ core::Type t1 = #C7;
+ core::Type t2 = #C8;
function local<T extends core::Object? = dynamic>(T% value) → T%
return value;
(core::int) → core::int f3 = local<core::int>;
@@ -95,25 +95,17 @@
(core::int) → core::int f4 = d.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
(core::int) → core::int f5 = d.{self::_D&C&M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
(core::int) → core::int f6 = self::Ext|get#einst(d)<core::int>;
- core::String typeName = (#C4).{core::Type::toString}(){() → core::String};
+ core::String typeName = (#C7).{core::Type::toString}(){() → core::String};
core::String functionTypeName = (local<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
}
constants {
#C1 = tearoff self::C::stat
- #C2 = tearoff self::M::mstat
- #C3 = tearoff self::Ext|estat
- #C4 = TypeLiteralConstant(core::List<core::int>)
- #C5 = TypeLiteralConstant(core::List<core::List<core::int>>)
+ #C2 = partial-instantiation self::C::stat <core::int>
+ #C3 = tearoff self::M::mstat
+ #C4 = partial-instantiation self::M::mstat <core::int>
+ #C5 = tearoff self::Ext|estat
+ #C6 = partial-instantiation self::Ext|estat <core::int>
+ #C7 = TypeLiteralConstant(core::List<core::int>)
+ #C8 = TypeLiteralConstant(core::List<core::List<core::int>>)
}
-
-Extra constant evaluation status:
-Evaluated: Instantiation @ org-dartlang-testcase:///explicit_instantiation.dart:13:18 -> PartialInstantiationConstant(C.stat<int>)
-Evaluated: Instantiation @ org-dartlang-testcase:///explicit_instantiation.dart:14:26 -> PartialInstantiationConstant(C.stat<int>)
-Evaluated: Instantiation @ org-dartlang-testcase:///explicit_instantiation.dart:26:19 -> PartialInstantiationConstant(M.mstat<int>)
-Evaluated: Instantiation @ org-dartlang-testcase:///explicit_instantiation.dart:27:27 -> PartialInstantiationConstant(M.mstat<int>)
-Evaluated: Instantiation @ org-dartlang-testcase:///explicit_instantiation.dart:26:19 -> PartialInstantiationConstant(M.mstat<int>)
-Evaluated: Instantiation @ org-dartlang-testcase:///explicit_instantiation.dart:27:27 -> PartialInstantiationConstant(M.mstat<int>)
-Evaluated: Instantiation @ org-dartlang-testcase:///explicit_instantiation.dart:39:19 -> PartialInstantiationConstant(Ext|estat<int>)
-Evaluated: Instantiation @ org-dartlang-testcase:///explicit_instantiation.dart:40:27 -> PartialInstantiationConstant(Ext|estat<int>)
-Extra constant evaluation: evaluated: 120, effectively constant: 8
diff --git a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.weak.expect
index 56a00ef..70f8b63 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.weak.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.weak.expect
@@ -12,8 +12,8 @@
method inst<T extends core::Object? = dynamic>(self::C::inst::T% value) → self::C::inst::T%
return value;
method method() → void {
- (core::int) → core::int f1 = #C1<core::int>;
- core::String f1TypeName = (#C1<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+ (core::int) → core::int f1 = #C2;
+ core::String f1TypeName = (#C2).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f2 = this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
core::String f2TypeName = (this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f3 = this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
@@ -26,8 +26,8 @@
method minst<T extends core::Object? = dynamic>(self::M::minst::T% value) → self::M::minst::T%
return value;
method mmethod() → void {
- (core::int) → core::int f1 = #C2<core::int>;
- core::String f1TypeName = (#C2<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+ (core::int) → core::int f1 = #C4;
+ core::String f1TypeName = (#C4).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f2 = this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
core::String f2TypeName = (this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f3 = this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
@@ -68,8 +68,8 @@
static method Ext|get#einst(lowered final self::C #this) → <T extends core::Object? = dynamic>(T%) → T%
return <T extends core::Object? = dynamic>(T% value) → T% => self::Ext|einst<T%>(#this, value);
static method Ext|emethod(lowered final self::C #this) → void {
- (core::int) → core::int f1 = #C3<core::int>;
- core::String f1TypeName = (#C3<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+ (core::int) → core::int f1 = #C6;
+ core::String f1TypeName = (#C6).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f2 = self::Ext|get#einst(#this)<core::int>;
core::String f2TypeName = (self::Ext|get#einst(#this)<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f3 = self::Ext|get#einst(#this)<core::int>;
@@ -78,8 +78,8 @@
static method Ext|get#emethod(lowered final self::C #this) → () → void
return () → void => self::Ext|emethod(#this);
static method main() → void {
- core::Type t1 = #C4;
- core::Type t2 = #C5;
+ core::Type t1 = #C7;
+ core::Type t2 = #C8;
function local<T extends core::Object? = dynamic>(T% value) → T%
return value;
(core::int) → core::int f3 = local<core::int>;
@@ -87,14 +87,17 @@
(core::int) → core::int f4 = d.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
(core::int) → core::int f5 = d.{self::_D&C&M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
(core::int) → core::int f6 = self::Ext|get#einst(d)<core::int>;
- core::String typeName = (#C4).{core::Type::toString}(){() → core::String};
+ core::String typeName = (#C7).{core::Type::toString}(){() → core::String};
core::String functionTypeName = (local<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
}
constants {
#C1 = tearoff self::C::stat
- #C2 = tearoff self::M::mstat
- #C3 = tearoff self::Ext|estat
- #C4 = TypeLiteralConstant(core::List<core::int*>*)
- #C5 = TypeLiteralConstant(core::List<core::List<core::int*>*>*)
+ #C2 = partial-instantiation self::C::stat <core::int*>
+ #C3 = tearoff self::M::mstat
+ #C4 = partial-instantiation self::M::mstat <core::int*>
+ #C5 = tearoff self::Ext|estat
+ #C6 = partial-instantiation self::Ext|estat <core::int*>
+ #C7 = TypeLiteralConstant(core::List<core::int*>*)
+ #C8 = TypeLiteralConstant(core::List<core::List<core::int*>*>*)
}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.weak.transformed.expect
index bb7ef4c..217f0b6 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation.dart.weak.transformed.expect
@@ -12,8 +12,8 @@
method inst<T extends core::Object? = dynamic>(self::C::inst::T% value) → self::C::inst::T%
return value;
method method() → void {
- (core::int) → core::int f1 = #C1<core::int>;
- core::String f1TypeName = (#C1<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+ (core::int) → core::int f1 = #C2;
+ core::String f1TypeName = (#C2).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f2 = this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
core::String f2TypeName = (this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f3 = this.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
@@ -26,8 +26,8 @@
method minst<T extends core::Object? = dynamic>(self::M::minst::T% value) → self::M::minst::T%
return value;
method mmethod() → void {
- (core::int) → core::int f1 = #C2<core::int>;
- core::String f1TypeName = (#C2<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+ (core::int) → core::int f1 = #C4;
+ core::String f1TypeName = (#C4).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f2 = this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
core::String f2TypeName = (this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f3 = this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
@@ -41,8 +41,8 @@
method minst<T extends core::Object? = dynamic>(self::_D&C&M::minst::T% value) → self::_D&C&M::minst::T%
return value;
method mmethod() → void {
- (core::int) → core::int f1 = #C2<core::int>;
- core::String f1TypeName = (#C2<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+ (core::int) → core::int f1 = #C4;
+ core::String f1TypeName = (#C4).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f2 = this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
core::String f2TypeName = (this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f3 = this.{self::M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
@@ -76,8 +76,8 @@
static method Ext|get#einst(lowered final self::C #this) → <T extends core::Object? = dynamic>(T%) → T%
return <T extends core::Object? = dynamic>(T% value) → T% => self::Ext|einst<T%>(#this, value);
static method Ext|emethod(lowered final self::C #this) → void {
- (core::int) → core::int f1 = #C3<core::int>;
- core::String f1TypeName = (#C3<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
+ (core::int) → core::int f1 = #C6;
+ core::String f1TypeName = (#C6).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f2 = self::Ext|get#einst(#this)<core::int>;
core::String f2TypeName = (self::Ext|get#einst(#this)<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
(core::int) → core::int f3 = self::Ext|get#einst(#this)<core::int>;
@@ -86,8 +86,8 @@
static method Ext|get#emethod(lowered final self::C #this) → () → void
return () → void => self::Ext|emethod(#this);
static method main() → void {
- core::Type t1 = #C4;
- core::Type t2 = #C5;
+ core::Type t1 = #C7;
+ core::Type t2 = #C8;
function local<T extends core::Object? = dynamic>(T% value) → T%
return value;
(core::int) → core::int f3 = local<core::int>;
@@ -95,25 +95,17 @@
(core::int) → core::int f4 = d.{self::C::inst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
(core::int) → core::int f5 = d.{self::_D&C&M::minst}{<T extends core::Object? = dynamic>(T%) → T%}<core::int>;
(core::int) → core::int f6 = self::Ext|get#einst(d)<core::int>;
- core::String typeName = (#C4).{core::Type::toString}(){() → core::String};
+ core::String typeName = (#C7).{core::Type::toString}(){() → core::String};
core::String functionTypeName = (local<core::int>).{core::Object::runtimeType}{core::Type}.{core::Type::toString}(){() → core::String};
}
constants {
#C1 = tearoff self::C::stat
- #C2 = tearoff self::M::mstat
- #C3 = tearoff self::Ext|estat
- #C4 = TypeLiteralConstant(core::List<core::int*>*)
- #C5 = TypeLiteralConstant(core::List<core::List<core::int*>*>*)
+ #C2 = partial-instantiation self::C::stat <core::int*>
+ #C3 = tearoff self::M::mstat
+ #C4 = partial-instantiation self::M::mstat <core::int*>
+ #C5 = tearoff self::Ext|estat
+ #C6 = partial-instantiation self::Ext|estat <core::int*>
+ #C7 = TypeLiteralConstant(core::List<core::int*>*)
+ #C8 = TypeLiteralConstant(core::List<core::List<core::int*>*>*)
}
-
-Extra constant evaluation status:
-Evaluated: Instantiation @ org-dartlang-testcase:///explicit_instantiation.dart:13:18 -> PartialInstantiationConstant(C.stat<int*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///explicit_instantiation.dart:14:26 -> PartialInstantiationConstant(C.stat<int*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///explicit_instantiation.dart:26:19 -> PartialInstantiationConstant(M.mstat<int*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///explicit_instantiation.dart:27:27 -> PartialInstantiationConstant(M.mstat<int*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///explicit_instantiation.dart:26:19 -> PartialInstantiationConstant(M.mstat<int*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///explicit_instantiation.dart:27:27 -> PartialInstantiationConstant(M.mstat<int*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///explicit_instantiation.dart:39:19 -> PartialInstantiationConstant(Ext|estat<int*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///explicit_instantiation.dart:40:27 -> PartialInstantiationConstant(Ext|estat<int*>)
-Extra constant evaluation: evaluated: 120, effectively constant: 8
diff --git a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.strong.expect
index 1724a92..7d47228 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.strong.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.strong.expect
@@ -57,7 +57,7 @@
static field <X extends core::Object? = dynamic>(X%) → X% a = #C1;
static field (core::int) → core::int b = self::a<core::int>;
-static field (core::int) → core::int c = #C1<core::int>;
+static field (core::int) → core::int c = #C2;
static field invalid-type d = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:25:11: Error: Too many type arguments: 1 allowed, but 2 found.
Try removing the extra type arguments.
var d = id<int, String>; // error - too many args
@@ -74,7 +74,7 @@
Try changing the operand or remove the type arguments.
var g = main<int>; // error - non-generic function type operand
^";
-static field (core::String) → core::String h = #C2<core::String>;
+static field (core::String) → core::String h = #C4;
static method id<X extends core::Object? = dynamic>(self::id::X% x) → self::id::X%
return x;
static method method<X extends core::Object? = dynamic, Y extends core::Object? = dynamic>() → void {}
@@ -83,7 +83,7 @@
static method test() → dynamic {
<X extends core::Object? = dynamic>(X%) → X% a = #C1;
(core::int) → core::int b = a<core::int>;
- (core::int) → core::int c = #C1<core::int>;
+ (core::int) → core::int c = #C2;
invalid-type d = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:15:13: Error: Too many type arguments: 1 allowed, but 2 found.
Try removing the extra type arguments.
var d = id<int, String>; // error - too many args
@@ -100,11 +100,13 @@
Try changing the operand or remove the type arguments.
var g = main<int>; // error - non-generic function type operand
^";
- (core::String) → core::String h = #C2<core::String>;
+ (core::String) → core::String h = #C4;
}
static method main() → dynamic {}
constants {
#C1 = tearoff self::id
- #C2 = tearoff self::boundedMethod
+ #C2 = partial-instantiation self::id <core::int>
+ #C3 = tearoff self::boundedMethod
+ #C4 = partial-instantiation self::boundedMethod <core::String>
}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.strong.transformed.expect
new file mode 100644
index 0000000..7d47228
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.strong.transformed.expect
@@ -0,0 +1,112 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:15:13: Error: Too many type arguments: 1 allowed, but 2 found.
+// Try removing the extra type arguments.
+// var d = id<int, String>; // error - too many args
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:16:17: Error: Too few type arguments: 2 required, 1 given.
+// Try adding the missing type arguments.
+// var e = method<int>; // error - too few args
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:17:12: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int'.
+// Try changing the operand or remove the type arguments.
+// var f = 0<int>; // error - non-function type operand
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:18:15: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic Function()'.
+// Try changing the operand or remove the type arguments.
+// var g = main<int>; // error - non-generic function type operand
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:19:24: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'X' on 'X Function<X extends num>(X)'.
+// Try changing type arguments so that they conform to the bounds.
+// var h = boundedMethod<String>; // error - invalid bound
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:25:11: Error: Too many type arguments: 1 allowed, but 2 found.
+// Try removing the extra type arguments.
+// var d = id<int, String>; // error - too many args
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:26:15: Error: Too few type arguments: 2 required, 1 given.
+// Try adding the missing type arguments.
+// var e = method<int>; // error - too few args
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:27:10: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int'.
+// Try changing the operand or remove the type arguments.
+// var f = 0<int>; // error - non-function type operand
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:28:13: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic Function()'.
+// Try changing the operand or remove the type arguments.
+// var g = main<int>; // error - non-generic function type operand
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:29:22: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'X' on 'X Function<X extends num>(X)'.
+// Try changing type arguments so that they conform to the bounds.
+// var h = boundedMethod<String>; // error - invalid bound
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+static field <X extends core::Object? = dynamic>(X%) → X% a = #C1;
+static field (core::int) → core::int b = self::a<core::int>;
+static field (core::int) → core::int c = #C2;
+static field invalid-type d = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:25:11: Error: Too many type arguments: 1 allowed, but 2 found.
+Try removing the extra type arguments.
+var d = id<int, String>; // error - too many args
+ ^";
+static field invalid-type e = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:26:15: Error: Too few type arguments: 2 required, 1 given.
+Try adding the missing type arguments.
+var e = method<int>; // error - too few args
+ ^";
+static field invalid-type f = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:27:10: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int'.
+Try changing the operand or remove the type arguments.
+var f = 0<int>; // error - non-function type operand
+ ^";
+static field invalid-type g = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:28:13: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic Function()'.
+Try changing the operand or remove the type arguments.
+var g = main<int>; // error - non-generic function type operand
+ ^";
+static field (core::String) → core::String h = #C4;
+static method id<X extends core::Object? = dynamic>(self::id::X% x) → self::id::X%
+ return x;
+static method method<X extends core::Object? = dynamic, Y extends core::Object? = dynamic>() → void {}
+static method boundedMethod<X extends core::num>(self::boundedMethod::X x) → self::boundedMethod::X
+ return x;
+static method test() → dynamic {
+ <X extends core::Object? = dynamic>(X%) → X% a = #C1;
+ (core::int) → core::int b = a<core::int>;
+ (core::int) → core::int c = #C2;
+ invalid-type d = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:15:13: Error: Too many type arguments: 1 allowed, but 2 found.
+Try removing the extra type arguments.
+ var d = id<int, String>; // error - too many args
+ ^";
+ invalid-type e = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:16:17: Error: Too few type arguments: 2 required, 1 given.
+Try adding the missing type arguments.
+ var e = method<int>; // error - too few args
+ ^";
+ invalid-type f = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:17:12: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int'.
+Try changing the operand or remove the type arguments.
+ var f = 0<int>; // error - non-function type operand
+ ^";
+ invalid-type g = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:18:15: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic Function()'.
+Try changing the operand or remove the type arguments.
+ var g = main<int>; // error - non-generic function type operand
+ ^";
+ (core::String) → core::String h = #C4;
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = tearoff self::id
+ #C2 = partial-instantiation self::id <core::int>
+ #C3 = tearoff self::boundedMethod
+ #C4 = partial-instantiation self::boundedMethod <core::String>
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.weak.expect
index 1724a92..c32e295 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.weak.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.weak.expect
@@ -57,7 +57,7 @@
static field <X extends core::Object? = dynamic>(X%) → X% a = #C1;
static field (core::int) → core::int b = self::a<core::int>;
-static field (core::int) → core::int c = #C1<core::int>;
+static field (core::int) → core::int c = #C2;
static field invalid-type d = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:25:11: Error: Too many type arguments: 1 allowed, but 2 found.
Try removing the extra type arguments.
var d = id<int, String>; // error - too many args
@@ -74,7 +74,7 @@
Try changing the operand or remove the type arguments.
var g = main<int>; // error - non-generic function type operand
^";
-static field (core::String) → core::String h = #C2<core::String>;
+static field (core::String) → core::String h = #C4;
static method id<X extends core::Object? = dynamic>(self::id::X% x) → self::id::X%
return x;
static method method<X extends core::Object? = dynamic, Y extends core::Object? = dynamic>() → void {}
@@ -83,7 +83,7 @@
static method test() → dynamic {
<X extends core::Object? = dynamic>(X%) → X% a = #C1;
(core::int) → core::int b = a<core::int>;
- (core::int) → core::int c = #C1<core::int>;
+ (core::int) → core::int c = #C2;
invalid-type d = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:15:13: Error: Too many type arguments: 1 allowed, but 2 found.
Try removing the extra type arguments.
var d = id<int, String>; // error - too many args
@@ -100,11 +100,13 @@
Try changing the operand or remove the type arguments.
var g = main<int>; // error - non-generic function type operand
^";
- (core::String) → core::String h = #C2<core::String>;
+ (core::String) → core::String h = #C4;
}
static method main() → dynamic {}
constants {
#C1 = tearoff self::id
- #C2 = tearoff self::boundedMethod
+ #C2 = partial-instantiation self::id <core::int*>
+ #C3 = tearoff self::boundedMethod
+ #C4 = partial-instantiation self::boundedMethod <core::String*>
}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.weak.transformed.expect
new file mode 100644
index 0000000..c32e295
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart.weak.transformed.expect
@@ -0,0 +1,112 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:15:13: Error: Too many type arguments: 1 allowed, but 2 found.
+// Try removing the extra type arguments.
+// var d = id<int, String>; // error - too many args
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:16:17: Error: Too few type arguments: 2 required, 1 given.
+// Try adding the missing type arguments.
+// var e = method<int>; // error - too few args
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:17:12: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int'.
+// Try changing the operand or remove the type arguments.
+// var f = 0<int>; // error - non-function type operand
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:18:15: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic Function()'.
+// Try changing the operand or remove the type arguments.
+// var g = main<int>; // error - non-generic function type operand
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:19:24: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'X' on 'X Function<X extends num>(X)'.
+// Try changing type arguments so that they conform to the bounds.
+// var h = boundedMethod<String>; // error - invalid bound
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:25:11: Error: Too many type arguments: 1 allowed, but 2 found.
+// Try removing the extra type arguments.
+// var d = id<int, String>; // error - too many args
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:26:15: Error: Too few type arguments: 2 required, 1 given.
+// Try adding the missing type arguments.
+// var e = method<int>; // error - too few args
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:27:10: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int'.
+// Try changing the operand or remove the type arguments.
+// var f = 0<int>; // error - non-function type operand
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:28:13: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic Function()'.
+// Try changing the operand or remove the type arguments.
+// var g = main<int>; // error - non-generic function type operand
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:29:22: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'X' on 'X Function<X extends num>(X)'.
+// Try changing type arguments so that they conform to the bounds.
+// var h = boundedMethod<String>; // error - invalid bound
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+static field <X extends core::Object? = dynamic>(X%) → X% a = #C1;
+static field (core::int) → core::int b = self::a<core::int>;
+static field (core::int) → core::int c = #C2;
+static field invalid-type d = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:25:11: Error: Too many type arguments: 1 allowed, but 2 found.
+Try removing the extra type arguments.
+var d = id<int, String>; // error - too many args
+ ^";
+static field invalid-type e = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:26:15: Error: Too few type arguments: 2 required, 1 given.
+Try adding the missing type arguments.
+var e = method<int>; // error - too few args
+ ^";
+static field invalid-type f = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:27:10: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int'.
+Try changing the operand or remove the type arguments.
+var f = 0<int>; // error - non-function type operand
+ ^";
+static field invalid-type g = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:28:13: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic Function()'.
+Try changing the operand or remove the type arguments.
+var g = main<int>; // error - non-generic function type operand
+ ^";
+static field (core::String) → core::String h = #C4;
+static method id<X extends core::Object? = dynamic>(self::id::X% x) → self::id::X%
+ return x;
+static method method<X extends core::Object? = dynamic, Y extends core::Object? = dynamic>() → void {}
+static method boundedMethod<X extends core::num>(self::boundedMethod::X x) → self::boundedMethod::X
+ return x;
+static method test() → dynamic {
+ <X extends core::Object? = dynamic>(X%) → X% a = #C1;
+ (core::int) → core::int b = a<core::int>;
+ (core::int) → core::int c = #C2;
+ invalid-type d = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:15:13: Error: Too many type arguments: 1 allowed, but 2 found.
+Try removing the extra type arguments.
+ var d = id<int, String>; // error - too many args
+ ^";
+ invalid-type e = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:16:17: Error: Too few type arguments: 2 required, 1 given.
+Try adding the missing type arguments.
+ var e = method<int>; // error - too few args
+ ^";
+ invalid-type f = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:17:12: Error: The static type of the explicit instantiation operand must be a generic function type but is 'int'.
+Try changing the operand or remove the type arguments.
+ var f = 0<int>; // error - non-function type operand
+ ^";
+ invalid-type g = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/explicit_instantiation_errors.dart:18:15: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic Function()'.
+Try changing the operand or remove the type arguments.
+ var g = main<int>; // error - non-generic function type operand
+ ^";
+ (core::String) → core::String h = #C4;
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = tearoff self::id
+ #C2 = partial-instantiation self::id <core::int*>
+ #C3 = tearoff self::boundedMethod
+ #C4 = partial-instantiation self::boundedMethod <core::String*>
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart
new file mode 100644
index 0000000..6cb7494
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart
@@ -0,0 +1,54 @@
+// 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.
+
+T id<T>(T t) => t;
+
+int Function(int) implicitInstantiation = id;
+var explicitInstantiation = id<int>;
+const int Function(int) implicitConstInstantiation = id;
+const explicitConstInstantiation = id<int>;
+
+T Function(T) create<T>() => id<T>;
+
+main() {
+ expect(true, identical(implicitInstantiation, implicitInstantiation));
+ expect(true, identical(implicitInstantiation, explicitInstantiation));
+ expect(true, identical(implicitInstantiation, implicitConstInstantiation));
+ expect(true, identical(implicitInstantiation, explicitConstInstantiation));
+ expect(true, identical(implicitInstantiation, id<int>));
+ expect(false, identical(implicitInstantiation, id<String>));
+ expect(false, identical(implicitInstantiation, create<int>()));
+
+ expect(true, identical(explicitInstantiation, implicitInstantiation));
+ expect(true, identical(explicitInstantiation, explicitInstantiation));
+ expect(true, identical(explicitInstantiation, implicitConstInstantiation));
+ expect(true, identical(explicitInstantiation, explicitConstInstantiation));
+ expect(true, identical(explicitInstantiation, id<int>));
+ expect(false, identical(explicitInstantiation, id<String>));
+ expect(false, identical(explicitInstantiation, create<int>()));
+
+ expect(true, identical(implicitConstInstantiation, implicitInstantiation));
+ expect(true, identical(implicitConstInstantiation, explicitInstantiation));
+ expect(true, identical(implicitConstInstantiation,
+ implicitConstInstantiation));
+ expect(true, identical(implicitConstInstantiation,
+ explicitConstInstantiation));
+ expect(true, identical(implicitConstInstantiation, id<int>));
+ expect(false, identical(implicitConstInstantiation, id<String>));
+ expect(false, identical(implicitConstInstantiation, create<int>()));
+
+ expect(true, identical(explicitConstInstantiation, implicitInstantiation));
+ expect(true, identical(explicitConstInstantiation, explicitInstantiation));
+ expect(true, identical(explicitConstInstantiation,
+ implicitConstInstantiation));
+ expect(true, identical(explicitConstInstantiation,
+ explicitConstInstantiation));
+ expect(true, identical(explicitConstInstantiation, id<int>));
+ expect(false, identical(explicitConstInstantiation, id<String>));
+ expect(false, identical(explicitConstInstantiation, create<int>()));
+}
+
+expect(expected, actual) {
+ if (expected != actual) throw 'Expected $expected, actual $actual';
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.strong.expect
new file mode 100644
index 0000000..8df289d3
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.strong.expect
@@ -0,0 +1,52 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static field (core::int) → core::int implicitInstantiation = #C2;
+static field (core::int) → core::int explicitInstantiation = #C2;
+static const field (core::int) → core::int implicitConstInstantiation = #C2;
+static const field (core::int) → core::int explicitConstInstantiation = #C2;
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+ return t;
+static method create<T extends core::Object? = dynamic>() → (self::create::T%) → self::create::T%
+ return #C1<self::create::T%>;
+static method main() → dynamic {
+ self::expect(true, core::identical(self::implicitInstantiation, self::implicitInstantiation));
+ self::expect(true, core::identical(self::implicitInstantiation, self::explicitInstantiation));
+ self::expect(true, core::identical(self::implicitInstantiation, #C2));
+ self::expect(true, core::identical(self::implicitInstantiation, #C2));
+ self::expect(true, core::identical(self::implicitInstantiation, #C2));
+ self::expect(false, core::identical(self::implicitInstantiation, #C3));
+ self::expect(false, core::identical(self::implicitInstantiation, self::create<core::int>()));
+ self::expect(true, core::identical(self::explicitInstantiation, self::implicitInstantiation));
+ self::expect(true, core::identical(self::explicitInstantiation, self::explicitInstantiation));
+ self::expect(true, core::identical(self::explicitInstantiation, #C2));
+ self::expect(true, core::identical(self::explicitInstantiation, #C2));
+ self::expect(true, core::identical(self::explicitInstantiation, #C2));
+ self::expect(false, core::identical(self::explicitInstantiation, #C3));
+ self::expect(false, core::identical(self::explicitInstantiation, self::create<core::int>()));
+ self::expect(true, core::identical(#C2, self::implicitInstantiation));
+ self::expect(true, core::identical(#C2, self::explicitInstantiation));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(false, core::identical(#C2, #C3));
+ self::expect(false, core::identical(#C2, self::create<core::int>()));
+ self::expect(true, core::identical(#C2, self::implicitInstantiation));
+ self::expect(true, core::identical(#C2, self::explicitInstantiation));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(false, core::identical(#C2, #C3));
+ self::expect(false, core::identical(#C2, self::create<core::int>()));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+
+constants {
+ #C1 = tearoff self::id
+ #C2 = partial-instantiation self::id <core::int>
+ #C3 = partial-instantiation self::id <core::String>
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.strong.transformed.expect
new file mode 100644
index 0000000..3afa4cf
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.strong.transformed.expect
@@ -0,0 +1,63 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static field (core::int) → core::int implicitInstantiation = #C2;
+static field (core::int) → core::int explicitInstantiation = #C2;
+static const field (core::int) → core::int implicitConstInstantiation = #C2;
+static const field (core::int) → core::int explicitConstInstantiation = #C2;
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+ return t;
+static method create<T extends core::Object? = dynamic>() → (self::create::T%) → self::create::T%
+ return #C1<self::create::T%>;
+static method main() → dynamic {
+ self::expect(true, core::identical(self::implicitInstantiation, self::implicitInstantiation));
+ self::expect(true, core::identical(self::implicitInstantiation, self::explicitInstantiation));
+ self::expect(true, core::identical(self::implicitInstantiation, #C2));
+ self::expect(true, core::identical(self::implicitInstantiation, #C2));
+ self::expect(true, core::identical(self::implicitInstantiation, #C2));
+ self::expect(false, core::identical(self::implicitInstantiation, #C3));
+ self::expect(false, core::identical(self::implicitInstantiation, self::create<core::int>()));
+ self::expect(true, core::identical(self::explicitInstantiation, self::implicitInstantiation));
+ self::expect(true, core::identical(self::explicitInstantiation, self::explicitInstantiation));
+ self::expect(true, core::identical(self::explicitInstantiation, #C2));
+ self::expect(true, core::identical(self::explicitInstantiation, #C2));
+ self::expect(true, core::identical(self::explicitInstantiation, #C2));
+ self::expect(false, core::identical(self::explicitInstantiation, #C3));
+ self::expect(false, core::identical(self::explicitInstantiation, self::create<core::int>()));
+ self::expect(true, core::identical(#C2, self::implicitInstantiation));
+ self::expect(true, core::identical(#C2, self::explicitInstantiation));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(false, core::identical(#C2, #C3));
+ self::expect(false, core::identical(#C2, self::create<core::int>()));
+ self::expect(true, core::identical(#C2, self::implicitInstantiation));
+ self::expect(true, core::identical(#C2, self::explicitInstantiation));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(false, core::identical(#C2, #C3));
+ self::expect(false, core::identical(#C2, self::create<core::int>()));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+
+constants {
+ #C1 = tearoff self::id
+ #C2 = partial-instantiation self::id <core::int>
+ #C3 = partial-instantiation self::id <core::String>
+}
+
+Extra constant evaluation status:
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:33:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:35:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:37:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:38:17 -> BoolConstant(false)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:43:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:45:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:47:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:48:17 -> BoolConstant(false)
+Extra constant evaluation: evaluated: 92, effectively constant: 8
diff --git a/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.textual_outline.expect
new file mode 100644
index 0000000..558b2b1
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.textual_outline.expect
@@ -0,0 +1,8 @@
+T id<T>(T t) => t;
+int Function(int) implicitInstantiation = id;
+var explicitInstantiation = id<int>;
+const int Function(int) implicitConstInstantiation = id;
+const explicitConstInstantiation = id<int>;
+T Function(T) create<T>() => id<T>;
+main() {}
+expect(expected, actual) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.weak.expect
new file mode 100644
index 0000000..c33a355
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.weak.expect
@@ -0,0 +1,52 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static field (core::int) → core::int implicitInstantiation = #C2;
+static field (core::int) → core::int explicitInstantiation = #C2;
+static const field (core::int) → core::int implicitConstInstantiation = #C2;
+static const field (core::int) → core::int explicitConstInstantiation = #C2;
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+ return t;
+static method create<T extends core::Object? = dynamic>() → (self::create::T%) → self::create::T%
+ return #C1<self::create::T%>;
+static method main() → dynamic {
+ self::expect(true, core::identical(self::implicitInstantiation, self::implicitInstantiation));
+ self::expect(true, core::identical(self::implicitInstantiation, self::explicitInstantiation));
+ self::expect(true, core::identical(self::implicitInstantiation, #C2));
+ self::expect(true, core::identical(self::implicitInstantiation, #C2));
+ self::expect(true, core::identical(self::implicitInstantiation, #C2));
+ self::expect(false, core::identical(self::implicitInstantiation, #C3));
+ self::expect(false, core::identical(self::implicitInstantiation, self::create<core::int>()));
+ self::expect(true, core::identical(self::explicitInstantiation, self::implicitInstantiation));
+ self::expect(true, core::identical(self::explicitInstantiation, self::explicitInstantiation));
+ self::expect(true, core::identical(self::explicitInstantiation, #C2));
+ self::expect(true, core::identical(self::explicitInstantiation, #C2));
+ self::expect(true, core::identical(self::explicitInstantiation, #C2));
+ self::expect(false, core::identical(self::explicitInstantiation, #C3));
+ self::expect(false, core::identical(self::explicitInstantiation, self::create<core::int>()));
+ self::expect(true, core::identical(#C2, self::implicitInstantiation));
+ self::expect(true, core::identical(#C2, self::explicitInstantiation));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(false, core::identical(#C2, #C3));
+ self::expect(false, core::identical(#C2, self::create<core::int>()));
+ self::expect(true, core::identical(#C2, self::implicitInstantiation));
+ self::expect(true, core::identical(#C2, self::explicitInstantiation));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(false, core::identical(#C2, #C3));
+ self::expect(false, core::identical(#C2, self::create<core::int>()));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+
+constants {
+ #C1 = tearoff self::id
+ #C2 = partial-instantiation self::id <core::int*>
+ #C3 = partial-instantiation self::id <core::String*>
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.weak.outline.expect
new file mode 100644
index 0000000..d3f2e88
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.weak.outline.expect
@@ -0,0 +1,22 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static field (core::int) → core::int implicitInstantiation;
+static field (core::int) → core::int explicitInstantiation;
+static const field (core::int) → core::int implicitConstInstantiation = self::id<core::int>;
+static const field (core::int) → core::int explicitConstInstantiation = self::id<core::int>;
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+ ;
+static method create<T extends core::Object? = dynamic>() → (self::create::T%) → self::create::T%
+ ;
+static method main() → dynamic
+ ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+ ;
+
+
+Extra constant evaluation status:
+Evaluated: Instantiation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:9:54 -> PartialInstantiationConstant(id<int*>)
+Evaluated: Instantiation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:10:38 -> PartialInstantiationConstant(id<int*>)
+Extra constant evaluation: evaluated: 2, effectively constant: 2
diff --git a/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.weak.transformed.expect
new file mode 100644
index 0000000..9cdfa3c
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/identical_instantiated_function_tearoffs.dart.weak.transformed.expect
@@ -0,0 +1,63 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static field (core::int) → core::int implicitInstantiation = #C2;
+static field (core::int) → core::int explicitInstantiation = #C2;
+static const field (core::int) → core::int implicitConstInstantiation = #C2;
+static const field (core::int) → core::int explicitConstInstantiation = #C2;
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+ return t;
+static method create<T extends core::Object? = dynamic>() → (self::create::T%) → self::create::T%
+ return #C1<self::create::T%>;
+static method main() → dynamic {
+ self::expect(true, core::identical(self::implicitInstantiation, self::implicitInstantiation));
+ self::expect(true, core::identical(self::implicitInstantiation, self::explicitInstantiation));
+ self::expect(true, core::identical(self::implicitInstantiation, #C2));
+ self::expect(true, core::identical(self::implicitInstantiation, #C2));
+ self::expect(true, core::identical(self::implicitInstantiation, #C2));
+ self::expect(false, core::identical(self::implicitInstantiation, #C3));
+ self::expect(false, core::identical(self::implicitInstantiation, self::create<core::int>()));
+ self::expect(true, core::identical(self::explicitInstantiation, self::implicitInstantiation));
+ self::expect(true, core::identical(self::explicitInstantiation, self::explicitInstantiation));
+ self::expect(true, core::identical(self::explicitInstantiation, #C2));
+ self::expect(true, core::identical(self::explicitInstantiation, #C2));
+ self::expect(true, core::identical(self::explicitInstantiation, #C2));
+ self::expect(false, core::identical(self::explicitInstantiation, #C3));
+ self::expect(false, core::identical(self::explicitInstantiation, self::create<core::int>()));
+ self::expect(true, core::identical(#C2, self::implicitInstantiation));
+ self::expect(true, core::identical(#C2, self::explicitInstantiation));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(false, core::identical(#C2, #C3));
+ self::expect(false, core::identical(#C2, self::create<core::int>()));
+ self::expect(true, core::identical(#C2, self::implicitInstantiation));
+ self::expect(true, core::identical(#C2, self::explicitInstantiation));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(false, core::identical(#C2, #C3));
+ self::expect(false, core::identical(#C2, self::create<core::int>()));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+
+constants {
+ #C1 = tearoff self::id
+ #C2 = partial-instantiation self::id <core::int*>
+ #C3 = partial-instantiation self::id <core::String*>
+}
+
+Extra constant evaluation status:
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:33:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:35:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:37:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:38:17 -> BoolConstant(false)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:43:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:45:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:47:16 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:48:17 -> BoolConstant(false)
+Extra constant evaluation: evaluated: 92, effectively constant: 8
diff --git a/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart
new file mode 100644
index 0000000..955feff
--- /dev/null
+++ b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart
@@ -0,0 +1,34 @@
+// 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.
+
+// @dart=2.13
+
+// This test is similar to
+//
+// constructor_tearoffs/identical_instantiated_function_tearoffs.dart
+//
+// but verifies that before the constructor-tearoffs experiment was enabled,
+// instantiations in non-constant context were not canonicalized.
+
+T id<T>(T t) => t;
+
+int Function(int) implicitInstantiation = id;
+const int Function(int) implicitConstInstantiation = id;
+
+T Function(T) create<T>() => id;
+
+main() {
+ expect(true, identical(implicitInstantiation, implicitInstantiation));
+ expect(false, identical(implicitInstantiation, implicitConstInstantiation));
+ expect(false, identical(implicitInstantiation, create<int>()));
+
+ expect(false, identical(implicitConstInstantiation, implicitInstantiation));
+ expect(
+ true, identical(implicitConstInstantiation, implicitConstInstantiation));
+ expect(false, identical(implicitConstInstantiation, create<int>()));
+}
+
+expect(expected, actual) {
+ if (expected != actual) throw 'Expected $expected, actual $actual';
+}
diff --git a/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.textual_outline.expect b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.textual_outline.expect
new file mode 100644
index 0000000..90e26eb
--- /dev/null
+++ b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.textual_outline.expect
@@ -0,0 +1,7 @@
+// @dart = 2.13
+T id<T>(T t) => t;
+int Function(int) implicitInstantiation = id;
+const int Function(int) implicitConstInstantiation = id;
+T Function(T) create<T>() => id;
+main() {}
+expect(expected, actual) {}
diff --git a/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..a0e9251
--- /dev/null
+++ b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.textual_outline_modelled.expect
@@ -0,0 +1,7 @@
+// @dart = 2.13
+T Function(T) create<T>() => id;
+T id<T>(T t) => t;
+const int Function(int) implicitConstInstantiation = id;
+expect(expected, actual) {}
+int Function(int) implicitInstantiation = id;
+main() {}
diff --git a/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.expect b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.expect
new file mode 100644
index 0000000..daf6f36
--- /dev/null
+++ b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.expect
@@ -0,0 +1,27 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static field (core::int) → core::int implicitInstantiation = #C1<core::int>;
+static const field (core::int) → core::int implicitConstInstantiation = #C2;
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+ return t;
+static method create<T extends core::Object? = dynamic>() → (self::create::T%) → self::create::T%
+ return #C1<self::create::T%>;
+static method main() → dynamic {
+ self::expect(true, core::identical(self::implicitInstantiation, self::implicitInstantiation));
+ self::expect(false, core::identical(self::implicitInstantiation, #C2));
+ self::expect(false, core::identical(self::implicitInstantiation, self::create<core::int>()));
+ self::expect(false, core::identical(#C2, self::implicitInstantiation));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(false, core::identical(#C2, self::create<core::int>()));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+
+constants {
+ #C1 = tearoff self::id
+ #C2 = partial-instantiation self::id <core::int*>
+}
diff --git a/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.outline.expect b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.outline.expect
new file mode 100644
index 0000000..02a352f
--- /dev/null
+++ b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.outline.expect
@@ -0,0 +1,19 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static field (core::int) → core::int implicitInstantiation;
+static const field (core::int) → core::int implicitConstInstantiation = self::id<core::int>;
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+ ;
+static method create<T extends core::Object? = dynamic>() → (self::create::T%) → self::create::T%
+ ;
+static method main() → dynamic
+ ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+ ;
+
+
+Extra constant evaluation status:
+Evaluated: Instantiation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:17:54 -> PartialInstantiationConstant(id<int*>)
+Extra constant evaluation: evaluated: 1, effectively constant: 1
diff --git a/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.transformed.expect b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.transformed.expect
new file mode 100644
index 0000000..ad67316
--- /dev/null
+++ b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.transformed.expect
@@ -0,0 +1,32 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static field (core::int) → core::int implicitInstantiation = #C1<core::int>;
+static const field (core::int) → core::int implicitConstInstantiation = #C2;
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+ return t;
+static method create<T extends core::Object? = dynamic>() → (self::create::T%) → self::create::T%
+ return #C1<self::create::T%>;
+static method main() → dynamic {
+ self::expect(true, core::identical(self::implicitInstantiation, self::implicitInstantiation));
+ self::expect(false, core::identical(self::implicitInstantiation, #C2));
+ self::expect(false, core::identical(self::implicitInstantiation, self::create<core::int>()));
+ self::expect(false, core::identical(#C2, self::implicitInstantiation));
+ self::expect(true, core::identical(#C2, #C2));
+ self::expect(false, core::identical(#C2, self::create<core::int>()));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+
+constants {
+ #C1 = tearoff self::id
+ #C2 = partial-instantiation self::id <core::int*>
+}
+
+Extra constant evaluation status:
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:28:13 -> BoolConstant(true)
+Evaluated: Instantiation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:16:43 -> PartialInstantiationConstant(id<int*>)
+Extra constant evaluation: evaluated: 30, effectively constant: 2
diff --git a/pkg/front_end/testcases/strong.status b/pkg/front_end/testcases/strong.status
index ecea6cc..cfb0715 100644
--- a/pkg/front_end/testcases/strong.status
+++ b/pkg/front_end/testcases/strong.status
@@ -8,7 +8,6 @@
dart2js/late_statics: SemiFuzzFailure # dartbug.com/45854
-constructor_tearoffs/explicit_instantiation_errors: TypeCheckError
constructor_tearoffs/redirecting_constructors: RuntimeError
extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.
extension_types/issue45775: ExpectationFileMismatchSerialized # Expected.
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index eb861df..c7df9c9 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -6,7 +6,6 @@
# the round trip for Kernel textual serialization where the initial binary
# Kernel files are produced by compiling Dart code via Fasta.
-constructor_tearoffs/explicit_instantiation_errors: TypeCheckError
constructor_tearoffs/redirecting_constructors: RuntimeError
extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.
extension_types/issue45775: ExpectationFileMismatchSerialized # Expected.
diff --git a/pkg/front_end/testcases/textual_outline.status b/pkg/front_end/testcases/textual_outline.status
index 8d66bab..29acb62 100644
--- a/pkg/front_end/testcases/textual_outline.status
+++ b/pkg/front_end/testcases/textual_outline.status
@@ -26,6 +26,7 @@
constructor_tearoffs/explicit_instantiation_errors: FormatterCrash
constructor_tearoffs/generic_tearoff_with_context: FormatterCrash
constructor_tearoffs/generic_tearoff_without_context: FormatterCrash
+constructor_tearoffs/identical_instantiated_function_tearoffs: FormatterCrash
constructor_tearoffs/instantiation: FormatterCrash
constructor_tearoffs/nongeneric_tearoff_with_context: FormatterCrash
constructor_tearoffs/nongeneric_tearoff_without_context: FormatterCrash
diff --git a/pkg/front_end/testcases/weak.status b/pkg/front_end/testcases/weak.status
index 96f77b8..82c2ba6 100644
--- a/pkg/front_end/testcases/weak.status
+++ b/pkg/front_end/testcases/weak.status
@@ -11,7 +11,6 @@
regress/utf_16_le_content.crash: SemiFuzzCrash
dart2js/late_statics: SemiFuzzFailure # dartbug.com/45854
-constructor_tearoffs/explicit_instantiation_errors: TypeCheckError
constructor_tearoffs/redirecting_constructors: RuntimeError
extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.
extension_types/issue45775: ExpectationFileMismatchSerialized # Expected.