[cfe] Normalize handling of extension constructor
This normalizes the handling of extension constructor to make it similar
to constructors of other declarations. Extension constructors are
erroneous but were partially present in some parts of the processing of
builders. This change handles them fully, similar to extension type
constructors, and just avoids emitting them. It might be that this some
what prepares for the static extension feature as well.
Change-Id: Icee027a2edb45c1b42b1f92d90150d6827c45a80
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/432981
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
diff --git a/pkg/front_end/lib/src/fragment/constructor/declaration.dart b/pkg/front_end/lib/src/fragment/constructor/declaration.dart
index 837074e..90a5874 100644
--- a/pkg/front_end/lib/src/fragment/constructor/declaration.dart
+++ b/pkg/front_end/lib/src/fragment/constructor/declaration.dart
@@ -29,6 +29,7 @@
import '../../source/name_scheme.dart';
import '../../source/source_class_builder.dart';
import '../../source/source_constructor_builder.dart';
+import '../../source/source_extension_builder.dart';
import '../../source/source_extension_type_declaration_builder.dart';
import '../../source/source_function_builder.dart';
import '../../source/source_library_builder.dart';
@@ -129,7 +130,7 @@
void markAsErroneous();
}
-mixin ConstructorDeclarationMixin
+mixin _ConstructorDeclarationMixin
implements ConstructorDeclaration, ConstructorFragmentDeclaration {
bool get _hasSuperInitializingFormals;
@@ -604,9 +605,9 @@
}
}
-mixin RegularConstructorDeclarationMixin
- implements ConstructorDeclarationMixin, InferredTypeListener {
- RegularConstructorEncoding get _encoding;
+mixin _ConstructorEncodingMixin
+ implements ConstructorDeclaration, ConstructorFragmentDeclaration {
+ ConstructorEncoding get _encoding;
@override
FunctionNode get function => _encoding.function;
@@ -624,22 +625,6 @@
Reference get invokeTargetReference => _encoding.invokeTargetReference;
@override
- void registerFunctionBody(Statement value) {
- _encoding.registerFunctionBody(value);
- }
-
- @override
- void registerNoBodyConstructor() {
- _encoding.registerNoBodyConstructor();
- }
-
- @override
- VariableDeclaration? get thisVariable => null;
-
- @override
- List<TypeParameter>? get thisTypeParameters => null;
-
- @override
List<Initializer> get initializers => _encoding.initializers;
@override
@@ -663,6 +648,36 @@
}
@override
+ void markAsErroneous() {
+ _encoding.markAsErroneous();
+ }
+}
+
+mixin _RegularConstructorDeclarationMixin
+ implements
+ _ConstructorDeclarationMixin,
+ _ConstructorEncodingMixin,
+ InferredTypeListener {
+ @override
+ RegularConstructorEncoding get _encoding;
+
+ @override
+ void registerFunctionBody(Statement value) {
+ _encoding.registerFunctionBody(value);
+ }
+
+ @override
+ void registerNoBodyConstructor() {
+ _encoding.registerNoBodyConstructor();
+ }
+
+ @override
+ VariableDeclaration? get thisVariable => null;
+
+ @override
+ List<TypeParameter>? get thisTypeParameters => null;
+
+ @override
Substitution computeFieldTypeSubstitution(
DeclarationBuilder declarationBuilder) {
// Nothing to substitute. Regular generative constructors don't have their
@@ -750,15 +765,13 @@
}
}
}
-
- @override
- void markAsErroneous() {
- _encoding.markAsErroneous();
- }
}
class RegularConstructorDeclaration
- with ConstructorDeclarationMixin, RegularConstructorDeclarationMixin
+ with
+ _ConstructorDeclarationMixin,
+ _ConstructorEncodingMixin,
+ _RegularConstructorDeclarationMixin
implements ConstructorDeclaration, ConstructorFragmentDeclaration {
final ConstructorFragment _fragment;
final List<FormalParameterBuilder>? _syntheticFormals;
@@ -897,7 +910,10 @@
// Coverage-ignore(suite): Not run.
class PrimaryConstructorDeclaration
- with ConstructorDeclarationMixin, RegularConstructorDeclarationMixin
+ with
+ _ConstructorDeclarationMixin,
+ _ConstructorEncodingMixin,
+ _RegularConstructorDeclarationMixin
implements ConstructorDeclaration, ConstructorFragmentDeclaration {
final PrimaryConstructorFragment _fragment;
@@ -1017,7 +1033,10 @@
}
class DefaultEnumConstructorDeclaration
- with ConstructorDeclarationMixin, RegularConstructorDeclarationMixin
+ with
+ _ConstructorDeclarationMixin,
+ _ConstructorEncodingMixin,
+ _RegularConstructorDeclarationMixin
implements ConstructorDeclaration {
@override
final Uri fileUri;
@@ -1144,26 +1163,15 @@
}
}
-mixin ExtensionTypeConstructorDeclarationMixin
- implements ConstructorDeclarationMixin, InferredTypeListener {
+mixin _ExtensionTypeConstructorDeclarationMixin
+ implements
+ _ConstructorDeclarationMixin,
+ _ConstructorEncodingMixin,
+ InferredTypeListener {
+ @override
ExtensionTypeConstructorEncoding get _encoding;
@override
- FunctionNode get function => _encoding.function;
-
- @override
- Member get readTarget => _encoding.readTarget;
-
- @override
- Reference get readTargetReference => _encoding.readTargetReference;
-
- @override
- Member get invokeTarget => _encoding.invokeTarget;
-
- @override
- Reference get invokeTargetReference => _encoding.invokeTargetReference;
-
- @override
void registerFunctionBody(Statement value) {
_encoding.registerFunctionBody(value);
}
@@ -1180,34 +1188,11 @@
List<TypeParameter>? get thisTypeParameters => _encoding.thisTypeParameters;
@override
- List<Initializer> get initializers => _encoding.initializers;
-
- @override
- void prepareInitializers() {
- _encoding.prepareInitializers();
- }
-
- @override
- void prependInitializer(Initializer initializer) {
- _encoding.prependInitializer(initializer);
- }
-
- @override
void becomeNative(SourceLoader loader) {
throw new UnsupportedError("$runtimeType.becomeNative()");
}
@override
- VariableDeclaration getFormalParameter(int index) {
- return _encoding.getFormalParameter(index);
- }
-
- @override
- VariableDeclaration? getTearOffParameter(int index) {
- return _encoding.getTearOffParameter(index);
- }
-
- @override
Substitution computeFieldTypeSubstitution(
DeclarationBuilder declarationBuilder) {
if (_typeParameters != null) {
@@ -1304,15 +1289,13 @@
}
}
}
-
- @override
- void markAsErroneous() {
- _encoding.markAsErroneous();
- }
}
class ExtensionTypeConstructorDeclaration
- with ConstructorDeclarationMixin, ExtensionTypeConstructorDeclarationMixin
+ with
+ _ConstructorDeclarationMixin,
+ _ConstructorEncodingMixin,
+ _ExtensionTypeConstructorDeclarationMixin
implements ConstructorDeclaration, ConstructorFragmentDeclaration {
final ConstructorFragment _fragment;
@@ -1435,7 +1418,10 @@
}
class ExtensionTypePrimaryConstructorDeclaration
- with ConstructorDeclarationMixin, ExtensionTypeConstructorDeclarationMixin
+ with
+ _ConstructorDeclarationMixin,
+ _ConstructorEncodingMixin,
+ _ExtensionTypeConstructorDeclarationMixin
implements ConstructorDeclaration, ConstructorFragmentDeclaration {
final PrimaryConstructorFragment _fragment;
@@ -1550,6 +1536,275 @@
Uri get fileUri => _fragment.fileUri;
}
+mixin _ExtensionConstructorDeclarationMixin
+ implements
+ _ConstructorDeclarationMixin,
+ _ConstructorEncodingMixin,
+ InferredTypeListener {
+ @override
+ ExtensionConstructorEncoding get _encoding;
+
+ @override
+ // Coverage-ignore(suite): Not run.
+ void registerFunctionBody(Statement value) {
+ _encoding.registerFunctionBody(value);
+ }
+
+ @override
+ // Coverage-ignore(suite): Not run.
+ void registerNoBodyConstructor() {
+ _encoding.registerNoBodyConstructor();
+ }
+
+ @override
+ // Coverage-ignore(suite): Not run.
+ VariableDeclaration? get thisVariable => _encoding.thisVariable;
+
+ @override
+ // Coverage-ignore(suite): Not run.
+ List<TypeParameter>? get thisTypeParameters => _encoding.thisTypeParameters;
+
+ @override
+ void becomeNative(SourceLoader loader) {
+ throw new UnsupportedError("$runtimeType.becomeNative()");
+ }
+
+ @override
+ // Coverage-ignore(suite): Not run.
+ Substitution computeFieldTypeSubstitution(
+ DeclarationBuilder declarationBuilder) {
+ if (_typeParameters != null) {
+ assert(
+ declarationBuilder.typeParameters!.length == _typeParameters?.length);
+ return Substitution.fromPairs(
+ (declarationBuilder as SourceExtensionTypeDeclarationBuilder)
+ .extensionTypeDeclaration
+ .typeParameters,
+ new List<DartType>.generate(
+ declarationBuilder.typeParameters!.length,
+ (int index) => new TypeParameterType.withDefaultNullability(
+ function.typeParameters[index])));
+ } else {
+ return Substitution.empty;
+ }
+ }
+
+ @override
+ void buildBody() {
+ _encoding.buildBody();
+ }
+
+ @override
+ // Coverage-ignore(suite): Not run.
+ bool get isRedirecting {
+ for (Initializer initializer in initializers) {
+ if (initializer is ExtensionTypeRedirectingInitializer) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @override
+ late final bool _hasSuperInitializingFormals =
+ formals?.any((formal) => formal.isSuperInitializingFormal) ?? false;
+
+ @override
+ void _addSuperParameterDefaultValueCloners(
+ {required List<DelayedDefaultValueCloner> delayedDefaultValueCloners,
+ required Member superTarget,
+ required List<int?>? positionalSuperParameters,
+ required List<String>? namedSuperParameters,
+ required SourceLibraryBuilder libraryBuilder}) {
+ throw new UnsupportedError(
+ '$runtimeType.addSuperParameterDefaultValueCloners');
+ }
+
+ // Coverage-ignore(suite): Not run.
+ void _buildTypeParametersAndFormals({
+ required SourceLibraryBuilder libraryBuilder,
+ required DeclarationBuilder declarationBuilder,
+ required BodyBuilderContext bodyBuilderContext,
+ required ClassHierarchy classHierarchy,
+ required LookupScope typeParameterScope,
+ }) {
+ if (_typeParameters != null) {
+ for (int i = 0; i < _typeParameters!.length; i++) {
+ _typeParameters![i].buildOutlineExpressions(
+ libraryBuilder, bodyBuilderContext, classHierarchy);
+ }
+ }
+
+ if (formals != null) {
+ // For const constructors we need to include default parameter values
+ // into the outline. For all other formals we need to call
+ // buildOutlineExpressions to clear initializerToken to prevent
+ // consuming too much memory.
+ for (FormalParameterBuilder formal in formals!) {
+ formal.buildOutlineExpressions(libraryBuilder, declarationBuilder,
+ scope: typeParameterScope, buildDefaultValue: true);
+ }
+ }
+ }
+
+ @override
+ // Coverage-ignore(suite): Not run.
+ BodyBuilderContext createBodyBuilderContext(
+ SourceConstructorBuilder constructorBuilder) {
+ return _encoding.createBodyBuilderContext(constructorBuilder, this);
+ }
+
+ @override
+ void onInferredType(DartType type) {
+ function.returnType = type;
+ }
+
+ @override
+ void registerInferable(Inferable inferable) {
+ returnType.registerInferredTypeListener(this);
+ if (formals != null) {
+ for (FormalParameterBuilder formal in formals!) {
+ if (formal.isInitializingFormal || formal.isSuperInitializingFormal) {
+ // Coverage-ignore-block(suite): Not run.
+ formal.type.registerInferable(inferable);
+ }
+ }
+ }
+ }
+}
+
+class ExtensionConstructorDeclaration
+ with
+ _ConstructorDeclarationMixin,
+ _ConstructorEncodingMixin,
+ _ExtensionConstructorDeclarationMixin
+ implements ConstructorDeclaration, ConstructorFragmentDeclaration {
+ final ConstructorFragment _fragment;
+
+ @override
+ final List<SourceNominalParameterBuilder>? _typeParameters;
+
+ @override
+ final ExtensionConstructorEncoding _encoding;
+
+ @override
+ Token? _beginInitializers;
+
+ ExtensionConstructorDeclaration(this._fragment,
+ {required List<SourceNominalParameterBuilder>? typeParameters})
+ : _typeParameters = typeParameters,
+ _beginInitializers = _fragment.beginInitializers,
+ _encoding = new ExtensionConstructorEncoding(
+ isExternal: _fragment.modifiers.isExternal) {
+ _fragment.declaration = this;
+ }
+
+ @override
+ // Coverage-ignore(suite): Not run.
+ LookupScope get _typeParameterScope => _fragment.typeParameterScope;
+
+ @override
+ // Coverage-ignore(suite): Not run.
+ List<MetadataBuilder>? get metadata => _fragment.metadata;
+
+ @override
+ OmittedTypeBuilder get returnType => _fragment.returnType;
+
+ @override
+ List<FormalParameterBuilder>? get formals => _fragment.formals;
+
+ @override
+ // Coverage-ignore(suite): Not run.
+ bool get isConst => _fragment.modifiers.isConst;
+
+ @override
+ bool get isExternal => _fragment.modifiers.isExternal;
+
+ @override
+ void createNode(
+ {required String name,
+ required SourceLibraryBuilder libraryBuilder,
+ required NameScheme nameScheme,
+ required Reference? constructorReference,
+ required Reference? tearOffReference}) {
+ _encoding.createNode(
+ name: name,
+ libraryBuilder: libraryBuilder,
+ nameScheme: nameScheme,
+ constructorReference: constructorReference,
+ tearOffReference: tearOffReference,
+ fileUri: _fragment.fileUri,
+ fileOffset: _fragment.fullNameOffset,
+ endOffset: _fragment.endOffset,
+ forAbstractClassOrEnumOrMixin: _fragment.forAbstractClassOrMixin);
+ }
+
+ @override
+ void buildOutlineNodes(BuildNodesCallback f,
+ {required SourceConstructorBuilder constructorBuilder,
+ required SourceLibraryBuilder libraryBuilder,
+ required Member declarationConstructor,
+ required List<DelayedDefaultValueCloner> delayedDefaultValueCloners}) {
+ _encoding.buildOutlineNodes(f,
+ constructorBuilder: constructorBuilder,
+ libraryBuilder: libraryBuilder,
+ declarationBuilder:
+ constructorBuilder.declarationBuilder as SourceExtensionBuilder,
+ declarationConstructor: declarationConstructor,
+ fileOffset: _fragment.fullNameOffset,
+ formalsOffset: _fragment.formalsOffset,
+ isConst: _fragment.modifiers.isConst,
+ returnType: returnType,
+ typeParameters: _typeParameters,
+ formals: formals,
+ delayedDefaultValueCloners: delayedDefaultValueCloners);
+ }
+
+ @override
+ // Coverage-ignore(suite): Not run.
+ void _buildMetadataForOutlineExpressions(
+ {required Iterable<Annotatable> annotatables,
+ required Uri annotatablesFileUri,
+ required SourceLibraryBuilder libraryBuilder,
+ required DeclarationBuilder declarationBuilder,
+ required SourceConstructorBuilder constructorBuilder,
+ required BodyBuilderContext bodyBuilderContext,
+ required ClassHierarchy classHierarchy}) {
+ for (Annotatable annotatable in annotatables) {
+ MetadataBuilder.buildAnnotations(
+ annotatable: annotatable,
+ annotatableFileUri: annotatablesFileUri,
+ metadata: _fragment.metadata,
+ bodyBuilderContext: bodyBuilderContext,
+ libraryBuilder: libraryBuilder,
+ scope: _fragment.enclosingScope);
+ }
+ }
+
+ @override
+ // Coverage-ignore(suite): Not run.
+ void _buildTypeParametersAndFormalsForOutlineExpressions(
+ {required SourceLibraryBuilder libraryBuilder,
+ required DeclarationBuilder declarationBuilder,
+ required BodyBuilderContext bodyBuilderContext,
+ required ClassHierarchy classHierarchy}) {
+ _buildTypeParametersAndFormals(
+ libraryBuilder: libraryBuilder,
+ declarationBuilder: declarationBuilder,
+ bodyBuilderContext: bodyBuilderContext,
+ classHierarchy: classHierarchy,
+ typeParameterScope: _fragment.typeParameterScope);
+ }
+
+ @override
+ // Coverage-ignore(suite): Not run.
+ int get fileOffset => _fragment.fullNameOffset;
+
+ @override
+ // Coverage-ignore(suite): Not run.
+ Uri get fileUri => _fragment.fileUri;
+}
+
/// Interface for using a [ConstructorFragment] or [PrimaryConstructorFragment]
/// to create a [BodyBuilderContext].
abstract class ConstructorFragmentDeclaration {
diff --git a/pkg/front_end/lib/src/fragment/constructor/encoding.dart b/pkg/front_end/lib/src/fragment/constructor/encoding.dart
index 8844cf3..254a54a 100644
--- a/pkg/front_end/lib/src/fragment/constructor/encoding.dart
+++ b/pkg/front_end/lib/src/fragment/constructor/encoding.dart
@@ -3,8 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:kernel/ast.dart';
+import 'package:kernel/type_algebra.dart';
import '../../api_prototype/lowering_predicates.dart';
+import '../../builder/declaration_builders.dart';
import '../../builder/formal_parameter_builder.dart';
import '../../builder/omitted_type_builder.dart';
import '../../builder/type_builder.dart';
@@ -15,6 +17,7 @@
import '../../source/name_scheme.dart';
import '../../source/source_class_builder.dart';
import '../../source/source_constructor_builder.dart';
+import '../../source/source_extension_builder.dart';
import '../../source/source_extension_type_declaration_builder.dart';
import '../../source/source_function_builder.dart';
import '../../source/source_library_builder.dart';
@@ -25,7 +28,36 @@
import 'body_builder_context.dart';
import 'declaration.dart';
-class RegularConstructorEncoding {
+abstract class ConstructorEncoding {
+ FunctionNode get function;
+
+ Member get readTarget;
+
+ Reference get readTargetReference;
+
+ Member get invokeTarget;
+
+ Reference get invokeTargetReference;
+
+ List<Initializer> get initializers;
+
+ void prepareInitializers();
+
+ void prependInitializer(Initializer initializer);
+
+ VariableDeclaration getFormalParameter(int index);
+
+ VariableDeclaration? getTearOffParameter(int index);
+
+ /// Mark the constructor as erroneous.
+ ///
+ /// This is used during the compilation phase to set the appropriate flag on
+ /// the input AST node. The flag helps the verifier to skip apriori erroneous
+ /// members and to avoid reporting cascading errors.
+ void markAsErroneous();
+}
+
+class RegularConstructorEncoding implements ConstructorEncoding {
late final Constructor _constructor;
late final Procedure? _constructorTearOff;
@@ -41,17 +73,21 @@
: _isExternal = isExternal,
_isEnumConstructor = isEnumConstructor;
+ @override
Member get readTarget =>
_constructorTearOff ??
// The case is need to ensure that the upper bound is [Member] and not
// [GenericFunction].
_constructor as Member;
+ @override
Reference get readTargetReference =>
(_constructorTearOff ?? _constructor).reference;
+ @override
Member get invokeTarget => _constructor;
+ @override
Reference get invokeTargetReference => _constructor.reference;
void registerFunctionBody(Statement value) {
@@ -64,6 +100,7 @@
}
}
+ @override
FunctionNode get function => _constructor.function;
void createNode(
@@ -105,6 +142,7 @@
// Coverage-ignore(suite): Not run.
Procedure? get constructorTearOff => _constructorTearOff;
+ @override
List<Initializer> get initializers => _constructor.initializers;
void buildOutlineNodes(
@@ -207,6 +245,7 @@
}
}
+ @override
void prepareInitializers() {
// For const constructors we parse initializers already at the outlining
// stage, there is no easy way to make body building stage skip initializer
@@ -218,10 +257,13 @@
// Note: this method clears both initializers from the target Kernel node
// and internal state associated with parsing initializers.
_constructor.initializers = [];
+ // TODO(johnniwinther): Can these be moved here from the
+ // [SourceConstructorBuilder]?
//redirectingInitializer = null;
//superInitializer = null;
}
+ @override
void prependInitializer(Initializer initializer) {
initializer.parent = _constructor;
_constructor.initializers.insert(0, initializer);
@@ -233,6 +275,7 @@
loader.addNativeAnnotation(_constructor, nativeMethodName);
}
+ @override
VariableDeclaration getFormalParameter(int index) {
if (_isEnumConstructor) {
// Skip synthetic parameters for index and name.
@@ -247,6 +290,7 @@
}
}
+ @override
VariableDeclaration? getTearOffParameter(int index) {
Procedure? constructorTearOff = _constructorTearOff;
if (constructorTearOff != null) {
@@ -299,22 +343,23 @@
constructorBuilder, constructorDeclaration, _constructor);
}
- /// Mark the constructor as erroneous.
- ///
- /// This is used during the compilation phase to set the appropriate flag on
- /// the input AST node. The flag helps the verifier to skip apriori erroneous
- /// members and to avoid reporting cascading errors.
+ @override
void markAsErroneous() {
_constructor.isErroneous = true;
}
}
-class ExtensionTypeConstructorEncoding {
+mixin _ExtensionTypeConstructorEncodingMixin<T extends DeclarationBuilder>
+ implements ConstructorEncoding {
late final Procedure _constructor;
late final Procedure? _constructorTearOff;
- final bool _isExternal;
+ bool get _isExternal;
+
+ bool get _isExtensionMember;
+
+ bool get _isExtensionTypeMember;
Statement? bodyInternal;
@@ -328,24 +373,28 @@
/// from the extension/extension type declaration.
List<TypeParameter>? _thisTypeParameters;
- List<Initializer> initializers = [];
+ List<Initializer> _initializers = [];
- ExtensionTypeConstructorEncoding({required bool isExternal})
- : _isExternal = isExternal;
-
+ @override
Member get readTarget =>
_constructorTearOff ?? // Coverage-ignore(suite): Not run.
_constructor;
+ @override
Reference get readTargetReference =>
(_constructorTearOff ?? // Coverage-ignore(suite): Not run.
_constructor)
.reference;
+ @override
Member get invokeTarget => _constructor;
+ @override
Reference get invokeTargetReference => _constructor.reference;
+ @override
+ List<Initializer> get initializers => _initializers;
+
void registerFunctionBody(Statement value) {
function.body = value..parent = function;
}
@@ -356,6 +405,7 @@
}
}
+ @override
FunctionNode get function => _constructor.function;
void createNode(
@@ -384,53 +434,18 @@
tearOffReference,
forAbstractClassOrEnumOrMixin: forAbstractClassOrEnumOrMixin,
forceCreateLowering: true)
- ?..isExtensionTypeMember = true;
- }
-
- // Coverage-ignore(suite): Not run.
- Member get constructor => _constructor;
-
- // Coverage-ignore(suite): Not run.
- Procedure? get constructorTearOff => _constructorTearOff;
-
- void buildOutlineNodes(
- BuildNodesCallback f, {
- required SourceConstructorBuilder constructorBuilder,
- required SourceLibraryBuilder libraryBuilder,
- required SourceExtensionTypeDeclarationBuilder declarationBuilder,
- required Member declarationConstructor,
- required int fileOffset,
- required int formalsOffset,
- required bool isConst,
- required TypeBuilder returnType,
- required List<SourceNominalParameterBuilder>? typeParameters,
- required List<FormalParameterBuilder>? formals,
- required List<DelayedDefaultValueCloner> delayedDefaultValueCloners,
- }) {
- _build(
- constructorBuilder: constructorBuilder,
- libraryBuilder: libraryBuilder,
- declarationBuilder: declarationBuilder,
- declarationConstructor: declarationConstructor,
- fileOffset: fileOffset,
- formalsOffset: formalsOffset,
- isConst: isConst,
- returnType: returnType,
- typeParameters: typeParameters,
- formals: formals,
- delayedDefaultValueCloners: delayedDefaultValueCloners);
- f(
- member: _constructor,
- tearOff: _constructorTearOff,
- kind: BuiltMemberKind.ExtensionTypeConstructor);
+ ?..isExtensionMember = _isExtensionMember
+ ..isExtensionTypeMember = _isExtensionTypeMember;
}
bool _hasBeenBuilt = false;
+ DartType _computeThisType(T declarationBuilder, List<DartType> typeArguments);
+
void _build({
required SourceConstructorBuilder constructorBuilder,
required SourceLibraryBuilder libraryBuilder,
- required SourceExtensionTypeDeclarationBuilder declarationBuilder,
+ required T declarationBuilder,
required Member declarationConstructor,
required int fileOffset,
required int formalsOffset,
@@ -464,12 +479,9 @@
typeArguments = [];
}
- ExtensionTypeDeclaration extensionTypeDeclaration =
- declarationBuilder.extensionTypeDeclaration;
_thisVariable = new VariableDeclarationImpl(syntheticThisName,
isFinal: true,
- type: new ExtensionType(
- extensionTypeDeclaration, Nullability.nonNullable, typeArguments))
+ type: _computeThisType(declarationBuilder, typeArguments))
..fileOffset = fileOffset
..isLowered = true;
@@ -479,15 +491,15 @@
typeParameterTypes
.add(new TypeParameterType.withDefaultNullability(typeParameter));
}
- ExtensionType type = new ExtensionType(extensionTypeDeclaration,
- Nullability.nonNullable, typeParameterTypes);
- returnType.registerInferredType(type);
+ returnType.registerInferredType(
+ _computeThisType(declarationBuilder, typeParameterTypes));
_constructor.function.fileOffset = formalsOffset;
_constructor.function.fileEndOffset = _constructor.fileEndOffset;
_constructor.isConst = isConst;
_constructor.isExternal = _isExternal;
_constructor.isStatic = true;
- _constructor.isExtensionTypeMember = true;
+ _constructor.isExtensionMember = _isExtensionMember;
+ _constructor.isExtensionTypeMember = _isExtensionTypeMember;
if (_constructorTearOff != null) {
delayedDefaultValueCloners.add(buildConstructorTearOffProcedure(
@@ -532,6 +544,7 @@
return _thisTypeParameters;
}
+ @override
void prepareInitializers() {
// For const constructors we parse initializers already at the outlining
// stage, there is no easy way to make body building stage skip initializer
@@ -542,15 +555,19 @@
// compile), and so we also clear them.
// Note: this method clears both initializers from the target Kernel node
// and internal state associated with parsing initializers.
- initializers = [];
+ _initializers = [];
+ // TODO(johnniwinther): Can these be moved here from the
+ // [SourceConstructorBuilder]?
//redirectingInitializer = null;
//superInitializer = null;
}
+ @override
void prependInitializer(Initializer initializer) {
- initializers.insert(0, initializer);
+ _initializers.insert(0, initializer);
}
+ @override
VariableDeclaration getFormalParameter(int index) {
if (index < function.positionalParameters.length) {
return function.positionalParameters[index];
@@ -561,6 +578,7 @@
}
}
+ @override
VariableDeclaration? getTearOffParameter(int index) {
Procedure? constructorTearOff = _constructorTearOff;
if (constructorTearOff != null) {
@@ -588,7 +606,7 @@
ExtensionTypeInitializerToStatementConverter visitor =
new ExtensionTypeInitializerToStatementConverter(
statements, thisVariable);
- for (Initializer initializer in initializers) {
+ for (Initializer initializer in _initializers) {
initializer.accept(visitor);
}
if (function.body != null && function.body is! EmptyStatement) {
@@ -607,12 +625,123 @@
constructorBuilder, constructorDeclaration, _constructor);
}
- /// Mark the constructor as erroneous.
- ///
- /// This is used during the compilation phase to set the appropriate flag on
- /// the input AST node. The flag helps the verifier to skip apriori erroneous
- /// members and to avoid reporting cascading errors.
+ @override
void markAsErroneous() {
_constructor.isErroneous = true;
}
}
+
+class ExtensionTypeConstructorEncoding
+ with
+ _ExtensionTypeConstructorEncodingMixin<
+ SourceExtensionTypeDeclarationBuilder>
+ implements
+ ConstructorEncoding {
+ @override
+ final bool _isExternal;
+
+ ExtensionTypeConstructorEncoding({required bool isExternal})
+ : _isExternal = isExternal;
+
+ @override
+ DartType _computeThisType(
+ SourceExtensionTypeDeclarationBuilder declarationBuilder,
+ List<DartType> typeArguments) {
+ ExtensionTypeDeclaration extensionTypeDeclaration =
+ declarationBuilder.extensionTypeDeclaration;
+ return new ExtensionType(
+ extensionTypeDeclaration, Nullability.nonNullable, typeArguments);
+ }
+
+ void buildOutlineNodes(
+ BuildNodesCallback f, {
+ required SourceConstructorBuilder constructorBuilder,
+ required SourceLibraryBuilder libraryBuilder,
+ required SourceExtensionTypeDeclarationBuilder declarationBuilder,
+ required Member declarationConstructor,
+ required int fileOffset,
+ required int formalsOffset,
+ required bool isConst,
+ required TypeBuilder returnType,
+ required List<SourceNominalParameterBuilder>? typeParameters,
+ required List<FormalParameterBuilder>? formals,
+ required List<DelayedDefaultValueCloner> delayedDefaultValueCloners,
+ }) {
+ _build(
+ constructorBuilder: constructorBuilder,
+ libraryBuilder: libraryBuilder,
+ declarationBuilder: declarationBuilder,
+ declarationConstructor: declarationConstructor,
+ fileOffset: fileOffset,
+ formalsOffset: formalsOffset,
+ isConst: isConst,
+ returnType: returnType,
+ typeParameters: typeParameters,
+ formals: formals,
+ delayedDefaultValueCloners: delayedDefaultValueCloners);
+ f(
+ member: _constructor,
+ tearOff: _constructorTearOff,
+ kind: BuiltMemberKind.ExtensionTypeConstructor);
+ }
+
+ @override
+ bool get _isExtensionMember => false;
+
+ @override
+ bool get _isExtensionTypeMember => true;
+}
+
+class ExtensionConstructorEncoding
+ with _ExtensionTypeConstructorEncodingMixin<SourceExtensionBuilder>
+ implements ConstructorEncoding {
+ @override
+ final bool _isExternal;
+
+ ExtensionConstructorEncoding({required bool isExternal})
+ : _isExternal = isExternal;
+
+ void buildOutlineNodes(
+ BuildNodesCallback f, {
+ required SourceConstructorBuilder constructorBuilder,
+ required SourceLibraryBuilder libraryBuilder,
+ required SourceExtensionBuilder declarationBuilder,
+ required Member declarationConstructor,
+ required int fileOffset,
+ required int formalsOffset,
+ required bool isConst,
+ required TypeBuilder returnType,
+ required List<SourceNominalParameterBuilder>? typeParameters,
+ required List<FormalParameterBuilder>? formals,
+ required List<DelayedDefaultValueCloner> delayedDefaultValueCloners,
+ }) {
+ _build(
+ constructorBuilder: constructorBuilder,
+ libraryBuilder: libraryBuilder,
+ declarationBuilder: declarationBuilder,
+ declarationConstructor: declarationConstructor,
+ fileOffset: fileOffset,
+ formalsOffset: formalsOffset,
+ isConst: isConst,
+ returnType: returnType,
+ typeParameters: typeParameters,
+ formals: formals,
+ delayedDefaultValueCloners: delayedDefaultValueCloners);
+ // Extension constructors are erroneous and are therefore not added to the
+ // AST.
+ }
+
+ @override
+ bool get _isExtensionMember => true;
+
+ @override
+ bool get _isExtensionTypeMember => false;
+
+ @override
+ DartType _computeThisType(
+ SourceExtensionBuilder declarationBuilder, List<DartType> typeArguments) {
+ Extension extension = declarationBuilder.extension;
+ return Substitution.fromPairs(extension.typeParameters, typeArguments)
+ .substituteType(extension.onType);
+ }
+}
diff --git a/pkg/front_end/lib/src/fragment/factory/encoding.dart b/pkg/front_end/lib/src/fragment/factory/encoding.dart
index ad25256..a4b90c1 100644
--- a/pkg/front_end/lib/src/fragment/factory/encoding.dart
+++ b/pkg/front_end/lib/src/fragment/factory/encoding.dart
@@ -183,16 +183,20 @@
libraryBuilder: libraryBuilder);
}
}
- f(
- member: _procedure,
- tearOff: _tearOff,
- kind: factoryBuilder.isExtensionTypeMember
- ? (_redirectionTarget != null
- ? BuiltMemberKind.ExtensionTypeRedirectingFactory
- : BuiltMemberKind.ExtensionTypeFactory)
- : (_redirectionTarget != null
- ? BuiltMemberKind.RedirectingFactory
- : BuiltMemberKind.Factory));
+ if (!factoryBuilder.isExtensionMember) {
+ // Extension factory constructors are erroneous and are therefore not
+ // added to the AST.
+ f(
+ member: _procedure,
+ tearOff: _tearOff,
+ kind: factoryBuilder.isExtensionTypeMember
+ ? (_redirectionTarget != null
+ ? BuiltMemberKind.ExtensionTypeRedirectingFactory
+ : BuiltMemberKind.ExtensionTypeFactory)
+ : (_redirectionTarget != null
+ ? BuiltMemberKind.RedirectingFactory
+ : BuiltMemberKind.Factory));
+ }
}
void buildOutlineExpressions(
diff --git a/pkg/front_end/lib/src/source/source_extension_builder.dart b/pkg/front_end/lib/src/source/source_extension_builder.dart
index 72f9c3f..1dfbcf7 100644
--- a/pkg/front_end/lib/src/source/source_extension_builder.dart
+++ b/pkg/front_end/lib/src/source/source_extension_builder.dart
@@ -149,7 +149,6 @@
indexedContainer: null,
containerType: ContainerType.Extension,
containerName: extensionName,
- includeConstructors: false,
constructorBuilders: _constructorBuilders,
memberBuilders: _memberBuilders);
}
diff --git a/pkg/front_end/lib/src/source/source_loader.dart b/pkg/front_end/lib/src/source/source_loader.dart
index caf0d7e..49e792c 100644
--- a/pkg/front_end/lib/src/source/source_loader.dart
+++ b/pkg/front_end/lib/src/source/source_loader.dart
@@ -2581,14 +2581,6 @@
if (redirectingFactoryBuilders != null) {
for (SourceFactoryBuilder redirectingFactoryBuilder
in redirectingFactoryBuilders) {
- if (redirectingFactoryBuilder.declarationBuilder
- is ExtensionBuilder) {
- // Extensions don't build their redirecting factories so we can't
- // process them. Once they are added in
- // [DeclarationNameSpaceBuilder.buildNameSpace] this skipping can
- // likely be removed.
- continue;
- }
registerConstructorToBeInferred(new InferableRedirectingFactory(
redirectingFactoryBuilder,
hierarchy,
diff --git a/pkg/front_end/lib/src/source/type_parameter_scope_builder.dart b/pkg/front_end/lib/src/source/type_parameter_scope_builder.dart
index 7d71d74..1731ff0 100644
--- a/pkg/front_end/lib/src/source/type_parameter_scope_builder.dart
+++ b/pkg/front_end/lib/src/source/type_parameter_scope_builder.dart
@@ -1964,7 +1964,6 @@
required IndexedContainer? indexedContainer,
required ContainerType containerType,
required ContainerName containerName,
- bool includeConstructors = true,
required List<SourceMemberBuilder> constructorBuilders,
required List<SourceMemberBuilder> memberBuilders}) {
List<NominalParameterBuilder> unboundNominalParameters = [];
@@ -1991,9 +1990,7 @@
messageMemberWithSameNameAsClass, uriOffset);
}
if (isConstructor) {
- if (includeConstructors) {
- constructorBuilders.add(declaration as SourceMemberBuilder);
- }
+ constructorBuilders.add(declaration as SourceMemberBuilder);
} else {
memberBuilders.add(declaration as SourceMemberBuilder);
}
@@ -2084,15 +2081,7 @@
.registerUnboundNominalParameters(unboundNominalParameters);
return new SourceDeclarationNameSpace(
- content: content,
- // TODO(johnniwinther): Handle constructors in extensions consistently.
- // Currently they are not part of the name space but still processed
- // for instance when inferring redirecting factories.
- // They are part of the name space for extension types though.
- // Note that we have to remove [SourceFactoryBuilder]s in
- // [SourceLoader.inferRedirectingFactories] as we don't build them
- // because we don't add them here.
- constructors: includeConstructors ? constructors : null);
+ content: content, constructors: constructors);
}
}
@@ -2880,10 +2869,8 @@
fragment.typeParameterNameSpace.addTypeParameters(
problemReporting, typeParameters,
ownerName: fragment.name, allowNameConflict: true);
- return new RegularConstructorDeclaration(fragment,
- typeParameters: typeParameters,
- syntheticFormals: null,
- isEnumConstructor: false);
+ return new ExtensionConstructorDeclaration(fragment,
+ typeParameters: typeParameters);
}
}
diff --git a/pkg/front_end/test/coverage_suite_expected.dart b/pkg/front_end/test/coverage_suite_expected.dart
index 4ced17b..30cf9dd 100644
--- a/pkg/front_end/test/coverage_suite_expected.dart
+++ b/pkg/front_end/test/coverage_suite_expected.dart
@@ -505,12 +505,12 @@
),
// 100.0%.
"package:front_end/src/fragment/constructor/declaration.dart": (
- hitCount: 733,
+ hitCount: 757,
missCount: 0,
),
// 100.0%.
"package:front_end/src/fragment/constructor/encoding.dart": (
- hitCount: 381,
+ hitCount: 405,
missCount: 0,
),
// 100.0%.
@@ -550,7 +550,7 @@
),
// 100.0%.
"package:front_end/src/fragment/factory/encoding.dart": (
- hitCount: 536,
+ hitCount: 537,
missCount: 0,
),
// 100.0%.
@@ -991,7 +991,7 @@
),
// 100.0%.
"package:front_end/src/source/source_loader.dart": (
- hitCount: 1797,
+ hitCount: 1795,
missCount: 0,
),
// 100.0%.