[cfe] Support inference of extension type redirecting factories

Change-Id: If3582f3a9d31d57f9b67ceae1bdcb7ffbb59d36f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/328122
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/front_end/lib/src/fasta/kernel/macro/macro.dart b/pkg/front_end/lib/src/fasta/kernel/macro/macro.dart
index 19fcf46..5c65b08 100644
--- a/pkg/front_end/lib/src/fasta/kernel/macro/macro.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/macro/macro.dart
@@ -991,7 +991,8 @@
     List<List<macro.ParameterDeclarationImpl>> parameters =
         _createParameters(builder, builder.formals);
     macro.ParameterizedTypeDeclaration definingClass =
-        getClassDeclaration(builder.classBuilder);
+        // TODO(johnniwinther): Support extension type factories.
+        getClassDeclaration(builder.classBuilder!);
 
     return new macro.ConstructorDeclarationImpl(
       id: macro.RemoteInstance.uniqueId,
diff --git a/pkg/front_end/lib/src/fasta/source/source_factory_builder.dart b/pkg/front_end/lib/src/fasta/source/source_factory_builder.dart
index 1677959..1950b7b 100644
--- a/pkg/front_end/lib/src/fasta/source/source_factory_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_factory_builder.dart
@@ -108,8 +108,7 @@
   }
 
   @override
-  SourceClassBuilder get classBuilder =>
-      super.classBuilder as SourceClassBuilder;
+  DeclarationBuilder get declarationBuilder => super.declarationBuilder!;
 
   List<SourceFactoryBuilder>? get patchesForTesting => _patches;
 
@@ -307,7 +306,7 @@
 
   @override
   String get fullNameForErrors {
-    return "${flattenName(classBuilder.name, charOffset, fileUri)}"
+    return "${flattenName(declarationBuilder.name, charOffset, fileUri)}"
         "${name.isEmpty ? '' : '.$name'}";
   }
 
@@ -474,10 +473,10 @@
     if (typeArguments != null && typeArguments.any((t) => t is UnknownType)) {
       TypeInferrer inferrer = libraryBuilder.loader.typeInferenceEngine
           .createLocalTypeInferrer(
-              fileUri, classBuilder.thisType, libraryBuilder, null);
+              fileUri, declarationBuilder.thisType, libraryBuilder, null);
       InferenceHelper helper = libraryBuilder.loader
-          .createBodyBuilderForOutlineExpression(
-              libraryBuilder, bodyBuilderContext, classBuilder.scope, fileUri);
+          .createBodyBuilderForOutlineExpression(libraryBuilder,
+              bodyBuilderContext, declarationBuilder.scope, fileUri);
       Builder? targetBuilder = redirectionTarget.target;
       if (targetBuilder is SourceMemberBuilder) {
         // Ensure that target has been built.
@@ -503,7 +502,7 @@
         // Assume that the error is reported elsewhere, use 'dynamic' for
         // recovery.
         typeArguments = new List<DartType>.filled(
-            target.enclosingClass!.typeParameters.length, const DynamicType(),
+            declarationBuilder.typeVariablesCount, const DynamicType(),
             growable: true);
       }
 
@@ -736,7 +735,7 @@
       libraryBuilder.addProblemForRedirectingFactory(
           this,
           templateCyclicRedirectingFactoryConstructors
-              .withArguments("${classBuilder.name}"
+              .withArguments("${declarationBuilder.name}"
                   "${name == '' ? '' : '.${name}'}"),
           charOffset,
           noLength,
@@ -784,7 +783,7 @@
 
     // Redirection to generative enum constructors is forbidden and is reported
     // as an error elsewhere.
-    if (!(classBuilder.cls.isEnum &&
+    if (!((classBuilder?.cls.isEnum ?? false) &&
         (redirectionTarget.target?.isConstructor ?? false))) {
       // Check whether [redirecteeType] <: [factoryType].
       if (!typeEnvironment.isSubtypeOf(
diff --git a/pkg/front_end/testcases/extension_types/generic_factory.dart b/pkg/front_end/testcases/extension_types/generic_factory.dart
new file mode 100644
index 0000000..b1047ac
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/generic_factory.dart
@@ -0,0 +1,8 @@
+// Copyright (c) 2023, 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.
+
+extension type const ET3<T extends num>(int id) {
+  const ET3.c1() : this(0);
+  factory ET3.f1() = ET3.c1;
+}
diff --git a/pkg/front_end/testcases/extension_types/generic_factory.dart.strong.expect b/pkg/front_end/testcases/extension_types/generic_factory.dart.strong.expect
new file mode 100644
index 0000000..f255397
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/generic_factory.dart.strong.expect
@@ -0,0 +1,29 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+extension type ET3<T extends core::num>(core::int id) {
+  constructor • = self::ET3|constructor#;
+  constructor tearoff • = self::ET3|constructor#_#new#tearOff;
+  constructor c1 = self::ET3|constructor#c1;
+  constructor tearoff c1 = self::ET3|constructor#_#c1#tearOff;
+  static redirecting-factory f1 = self::ET3|constructor#f1;
+  static redirecting-factory tearoff f1 = self::ET3|constructor#_#f1#tearOff;
+}
+static inline-class-member method ET3|constructor#<T extends core::num>(core::int id) → self::ET3<self::ET3|constructor#::T> /* = core::int */ {
+  lowered final self::ET3<self::ET3|constructor#::T> /* = core::int */ #this = id;
+  return #this;
+}
+static inline-class-member method ET3|constructor#_#new#tearOff<T extends core::num>(core::int id) → self::ET3<self::ET3|constructor#_#new#tearOff::T> /* = core::int */
+  return self::ET3|constructor#<self::ET3|constructor#_#new#tearOff::T>(id);
+static inline-class-member method ET3|constructor#c1<T extends core::num>() → self::ET3<self::ET3|constructor#c1::T> /* = core::int */ {
+  lowered final self::ET3<self::ET3|constructor#c1::T> /* = core::int */ #this;
+  #this = self::ET3|constructor#<self::ET3|constructor#c1::T>(0);
+  return #this;
+}
+static inline-class-member method ET3|constructor#_#c1#tearOff<T extends core::num>() → self::ET3<self::ET3|constructor#_#c1#tearOff::T> /* = core::int */
+  return self::ET3|constructor#c1<self::ET3|constructor#_#c1#tearOff::T>();
+static inline-class-member method ET3|constructor#f1<T extends core::num>() → self::ET3<self::ET3|constructor#f1::T> /* = core::int */ /* redirection-target: self::ET3|constructor#c1<dynamic>*/
+  return self::ET3|constructor#c1<dynamic>();
+static inline-class-member method ET3|constructor#_#f1#tearOff<T extends core::num>() → self::ET3<self::ET3|constructor#_#f1#tearOff::T> /* = core::int */
+  return self::ET3|constructor#c1<dynamic>();
diff --git a/pkg/front_end/testcases/extension_types/generic_factory.dart.strong.transformed.expect b/pkg/front_end/testcases/extension_types/generic_factory.dart.strong.transformed.expect
new file mode 100644
index 0000000..a7a6f08
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/generic_factory.dart.strong.transformed.expect
@@ -0,0 +1,35 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+extension type ET3<T extends core::num>(core::int id) {
+  constructor • = self::ET3|constructor#;
+  constructor tearoff • = self::ET3|constructor#_#new#tearOff;
+  constructor c1 = self::ET3|constructor#c1;
+  constructor tearoff c1 = self::ET3|constructor#_#c1#tearOff;
+  static redirecting-factory f1 = self::ET3|constructor#f1;
+  static redirecting-factory tearoff f1 = self::ET3|constructor#_#f1#tearOff;
+}
+static inline-class-member method ET3|constructor#<T extends core::num>(core::int id) → self::ET3<self::ET3|constructor#::T> /* = core::int */ {
+  lowered final self::ET3<self::ET3|constructor#::T> /* = core::int */ #this = id;
+  return #this;
+}
+static inline-class-member method ET3|constructor#_#new#tearOff<T extends core::num>(core::int id) → self::ET3<self::ET3|constructor#_#new#tearOff::T> /* = core::int */
+  return self::ET3|constructor#<self::ET3|constructor#_#new#tearOff::T>(id);
+static inline-class-member method ET3|constructor#c1<T extends core::num>() → self::ET3<self::ET3|constructor#c1::T> /* = core::int */ {
+  lowered final self::ET3<self::ET3|constructor#c1::T> /* = core::int */ #this;
+  #this = self::ET3|constructor#<self::ET3|constructor#c1::T>(0);
+  return #this;
+}
+static inline-class-member method ET3|constructor#_#c1#tearOff<T extends core::num>() → self::ET3<self::ET3|constructor#_#c1#tearOff::T> /* = core::int */
+  return self::ET3|constructor#c1<self::ET3|constructor#_#c1#tearOff::T>();
+static inline-class-member method ET3|constructor#f1<T extends core::num>() → self::ET3<self::ET3|constructor#f1::T> /* = core::int */ /* redirection-target: self::ET3|constructor#c1<dynamic>*/
+  return self::ET3|constructor#c1<dynamic>();
+static inline-class-member method ET3|constructor#_#f1#tearOff<T extends core::num>() → self::ET3<self::ET3|constructor#_#f1#tearOff::T> /* = core::int */
+  return self::ET3|constructor#c1<dynamic>();
+
+
+Extra constant evaluation status:
+Evaluated: StaticInvocation @ org-dartlang-testcase:///generic_factory.dart:7:17 -> IntConstant(0)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///generic_factory.dart:7:11 -> IntConstant(0)
+Extra constant evaluation: evaluated: 10, effectively constant: 2
diff --git a/pkg/front_end/testcases/extension_types/generic_factory.dart.textual_outline.expect b/pkg/front_end/testcases/extension_types/generic_factory.dart.textual_outline.expect
new file mode 100644
index 0000000..6bb69ca
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/generic_factory.dart.textual_outline.expect
@@ -0,0 +1,4 @@
+extension type const ET3<T extends num>(int id) {
+  const ET3.c1() : this(0);
+  factory ET3.f1() = ET3.c1;
+}
diff --git a/pkg/front_end/testcases/extension_types/generic_factory.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/extension_types/generic_factory.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..6bb69ca
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/generic_factory.dart.textual_outline_modelled.expect
@@ -0,0 +1,4 @@
+extension type const ET3<T extends num>(int id) {
+  const ET3.c1() : this(0);
+  factory ET3.f1() = ET3.c1;
+}
diff --git a/pkg/front_end/testcases/extension_types/generic_factory.dart.weak.expect b/pkg/front_end/testcases/extension_types/generic_factory.dart.weak.expect
new file mode 100644
index 0000000..f255397
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/generic_factory.dart.weak.expect
@@ -0,0 +1,29 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+extension type ET3<T extends core::num>(core::int id) {
+  constructor • = self::ET3|constructor#;
+  constructor tearoff • = self::ET3|constructor#_#new#tearOff;
+  constructor c1 = self::ET3|constructor#c1;
+  constructor tearoff c1 = self::ET3|constructor#_#c1#tearOff;
+  static redirecting-factory f1 = self::ET3|constructor#f1;
+  static redirecting-factory tearoff f1 = self::ET3|constructor#_#f1#tearOff;
+}
+static inline-class-member method ET3|constructor#<T extends core::num>(core::int id) → self::ET3<self::ET3|constructor#::T> /* = core::int */ {
+  lowered final self::ET3<self::ET3|constructor#::T> /* = core::int */ #this = id;
+  return #this;
+}
+static inline-class-member method ET3|constructor#_#new#tearOff<T extends core::num>(core::int id) → self::ET3<self::ET3|constructor#_#new#tearOff::T> /* = core::int */
+  return self::ET3|constructor#<self::ET3|constructor#_#new#tearOff::T>(id);
+static inline-class-member method ET3|constructor#c1<T extends core::num>() → self::ET3<self::ET3|constructor#c1::T> /* = core::int */ {
+  lowered final self::ET3<self::ET3|constructor#c1::T> /* = core::int */ #this;
+  #this = self::ET3|constructor#<self::ET3|constructor#c1::T>(0);
+  return #this;
+}
+static inline-class-member method ET3|constructor#_#c1#tearOff<T extends core::num>() → self::ET3<self::ET3|constructor#_#c1#tearOff::T> /* = core::int */
+  return self::ET3|constructor#c1<self::ET3|constructor#_#c1#tearOff::T>();
+static inline-class-member method ET3|constructor#f1<T extends core::num>() → self::ET3<self::ET3|constructor#f1::T> /* = core::int */ /* redirection-target: self::ET3|constructor#c1<dynamic>*/
+  return self::ET3|constructor#c1<dynamic>();
+static inline-class-member method ET3|constructor#_#f1#tearOff<T extends core::num>() → self::ET3<self::ET3|constructor#_#f1#tearOff::T> /* = core::int */
+  return self::ET3|constructor#c1<dynamic>();
diff --git a/pkg/front_end/testcases/extension_types/generic_factory.dart.weak.modular.expect b/pkg/front_end/testcases/extension_types/generic_factory.dart.weak.modular.expect
new file mode 100644
index 0000000..f255397
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/generic_factory.dart.weak.modular.expect
@@ -0,0 +1,29 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+extension type ET3<T extends core::num>(core::int id) {
+  constructor • = self::ET3|constructor#;
+  constructor tearoff • = self::ET3|constructor#_#new#tearOff;
+  constructor c1 = self::ET3|constructor#c1;
+  constructor tearoff c1 = self::ET3|constructor#_#c1#tearOff;
+  static redirecting-factory f1 = self::ET3|constructor#f1;
+  static redirecting-factory tearoff f1 = self::ET3|constructor#_#f1#tearOff;
+}
+static inline-class-member method ET3|constructor#<T extends core::num>(core::int id) → self::ET3<self::ET3|constructor#::T> /* = core::int */ {
+  lowered final self::ET3<self::ET3|constructor#::T> /* = core::int */ #this = id;
+  return #this;
+}
+static inline-class-member method ET3|constructor#_#new#tearOff<T extends core::num>(core::int id) → self::ET3<self::ET3|constructor#_#new#tearOff::T> /* = core::int */
+  return self::ET3|constructor#<self::ET3|constructor#_#new#tearOff::T>(id);
+static inline-class-member method ET3|constructor#c1<T extends core::num>() → self::ET3<self::ET3|constructor#c1::T> /* = core::int */ {
+  lowered final self::ET3<self::ET3|constructor#c1::T> /* = core::int */ #this;
+  #this = self::ET3|constructor#<self::ET3|constructor#c1::T>(0);
+  return #this;
+}
+static inline-class-member method ET3|constructor#_#c1#tearOff<T extends core::num>() → self::ET3<self::ET3|constructor#_#c1#tearOff::T> /* = core::int */
+  return self::ET3|constructor#c1<self::ET3|constructor#_#c1#tearOff::T>();
+static inline-class-member method ET3|constructor#f1<T extends core::num>() → self::ET3<self::ET3|constructor#f1::T> /* = core::int */ /* redirection-target: self::ET3|constructor#c1<dynamic>*/
+  return self::ET3|constructor#c1<dynamic>();
+static inline-class-member method ET3|constructor#_#f1#tearOff<T extends core::num>() → self::ET3<self::ET3|constructor#_#f1#tearOff::T> /* = core::int */
+  return self::ET3|constructor#c1<dynamic>();
diff --git a/pkg/front_end/testcases/extension_types/generic_factory.dart.weak.outline.expect b/pkg/front_end/testcases/extension_types/generic_factory.dart.weak.outline.expect
new file mode 100644
index 0000000..926ec69
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/generic_factory.dart.weak.outline.expect
@@ -0,0 +1,24 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+extension type ET3<T extends core::num>(core::int id) {
+  constructor • = self::ET3|constructor#;
+  constructor tearoff • = self::ET3|constructor#_#new#tearOff;
+  constructor c1 = self::ET3|constructor#c1;
+  constructor tearoff c1 = self::ET3|constructor#_#c1#tearOff;
+  static redirecting-factory f1 = self::ET3|constructor#f1;
+  static redirecting-factory tearoff f1 = self::ET3|constructor#_#f1#tearOff;
+}
+static inline-class-member method ET3|constructor#<T extends core::num>(core::int id) → self::ET3<self::ET3|constructor#::T> /* = core::int */
+  ;
+static inline-class-member method ET3|constructor#_#new#tearOff<T extends core::num>(core::int id) → self::ET3<self::ET3|constructor#_#new#tearOff::T> /* = core::int */
+  return self::ET3|constructor#<self::ET3|constructor#_#new#tearOff::T>(id);
+static inline-class-member method ET3|constructor#c1<T extends core::num>() → self::ET3<self::ET3|constructor#c1::T> /* = core::int */
+  ;
+static inline-class-member method ET3|constructor#_#c1#tearOff<T extends core::num>() → self::ET3<self::ET3|constructor#_#c1#tearOff::T> /* = core::int */
+  return self::ET3|constructor#c1<self::ET3|constructor#_#c1#tearOff::T>();
+static inline-class-member method ET3|constructor#f1<T extends core::num>() → self::ET3<self::ET3|constructor#f1::T> /* = core::int */ /* redirection-target: self::ET3|constructor#c1<dynamic>*/
+  return self::ET3|constructor#c1<dynamic>();
+static inline-class-member method ET3|constructor#_#f1#tearOff<T extends core::num>() → self::ET3<self::ET3|constructor#_#f1#tearOff::T> /* = core::int */
+  return self::ET3|constructor#c1<dynamic>();
diff --git a/pkg/front_end/testcases/extension_types/generic_factory.dart.weak.transformed.expect b/pkg/front_end/testcases/extension_types/generic_factory.dart.weak.transformed.expect
new file mode 100644
index 0000000..a7a6f08
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/generic_factory.dart.weak.transformed.expect
@@ -0,0 +1,35 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+extension type ET3<T extends core::num>(core::int id) {
+  constructor • = self::ET3|constructor#;
+  constructor tearoff • = self::ET3|constructor#_#new#tearOff;
+  constructor c1 = self::ET3|constructor#c1;
+  constructor tearoff c1 = self::ET3|constructor#_#c1#tearOff;
+  static redirecting-factory f1 = self::ET3|constructor#f1;
+  static redirecting-factory tearoff f1 = self::ET3|constructor#_#f1#tearOff;
+}
+static inline-class-member method ET3|constructor#<T extends core::num>(core::int id) → self::ET3<self::ET3|constructor#::T> /* = core::int */ {
+  lowered final self::ET3<self::ET3|constructor#::T> /* = core::int */ #this = id;
+  return #this;
+}
+static inline-class-member method ET3|constructor#_#new#tearOff<T extends core::num>(core::int id) → self::ET3<self::ET3|constructor#_#new#tearOff::T> /* = core::int */
+  return self::ET3|constructor#<self::ET3|constructor#_#new#tearOff::T>(id);
+static inline-class-member method ET3|constructor#c1<T extends core::num>() → self::ET3<self::ET3|constructor#c1::T> /* = core::int */ {
+  lowered final self::ET3<self::ET3|constructor#c1::T> /* = core::int */ #this;
+  #this = self::ET3|constructor#<self::ET3|constructor#c1::T>(0);
+  return #this;
+}
+static inline-class-member method ET3|constructor#_#c1#tearOff<T extends core::num>() → self::ET3<self::ET3|constructor#_#c1#tearOff::T> /* = core::int */
+  return self::ET3|constructor#c1<self::ET3|constructor#_#c1#tearOff::T>();
+static inline-class-member method ET3|constructor#f1<T extends core::num>() → self::ET3<self::ET3|constructor#f1::T> /* = core::int */ /* redirection-target: self::ET3|constructor#c1<dynamic>*/
+  return self::ET3|constructor#c1<dynamic>();
+static inline-class-member method ET3|constructor#_#f1#tearOff<T extends core::num>() → self::ET3<self::ET3|constructor#_#f1#tearOff::T> /* = core::int */
+  return self::ET3|constructor#c1<dynamic>();
+
+
+Extra constant evaluation status:
+Evaluated: StaticInvocation @ org-dartlang-testcase:///generic_factory.dart:7:17 -> IntConstant(0)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///generic_factory.dart:7:11 -> IntConstant(0)
+Extra constant evaluation: evaluated: 10, effectively constant: 2