[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