From a78235cf01aa46cecfcf7a77848dfa458ac6a674 Mon Sep 17 00:00:00 2001 From: Johnni Winther Date: Mon, 10 Feb 2025 07:09:07 -0800 Subject: [PATCH] [cfe] Create constructors through fragments Change-Id: If2a7095c09dcf2d73d326b6ba6d796acfa882c55 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/408780 Reviewed-by: Chloe Stefantsova Commit-Queue: Johnni Winther --- .../src/builder/formal_parameter_builder.dart | 2 +- .../lib/src/fragment/constructor.dart | 9 +- .../src/fragment/constructor/declaration.dart | 677 ++++++++ .../src/fragment/constructor/encoding.dart | 564 +++++++ pkg/front_end/lib/src/fragment/getter.dart | 2 +- pkg/front_end/lib/src/fragment/method.dart | 2 +- .../lib/src/fragment/primary_constructor.dart | 6 +- pkg/front_end/lib/src/fragment/setter.dart | 2 +- .../lib/src/kernel/body_builder.dart | 4 +- .../lib/src/kernel/body_builder_context.dart | 67 +- .../lib/src/kernel/kernel_target.dart | 63 +- .../src/source/constructor_declaration.dart | 2 +- .../lib/src/source/source_class_builder.dart | 2 +- .../source/source_constructor_builder.dart | 1385 +++++------------ .../lib/src/source/source_enum_builder.dart | 129 +- ...ce_extension_type_declaration_builder.dart | 4 +- .../src/source/source_factory_builder.dart | 2 +- .../source/type_parameter_scope_builder.dart | 307 ++-- .../src/type_inference/inference_visitor.dart | 2 +- .../lib/src/type_inference/type_inferrer.dart | 20 +- .../test/coverage_suite_expected.dart | 22 +- .../test/patching/patching_test.dart | 2 +- .../issue53212.dart.strong.outline.expect | 24 +- .../issue53625.dart.strong.outline.expect | 6 +- 24 files changed, 1957 insertions(+), 1348 deletions(-) create mode 100644 pkg/front_end/lib/src/fragment/constructor/declaration.dart create mode 100644 pkg/front_end/lib/src/fragment/constructor/encoding.dart diff --git a/pkg/front_end/lib/src/builder/formal_parameter_builder.dart b/pkg/front_end/lib/src/builder/formal_parameter_builder.dart index 68aa737bea7..07193732663 100644 --- a/pkg/front_end/lib/src/builder/formal_parameter_builder.dart +++ b/pkg/front_end/lib/src/builder/formal_parameter_builder.dart @@ -225,7 +225,7 @@ class FormalParameterBuilder extends BuilderImpl void finalizeInitializingFormal( DeclarationBuilder declarationBuilder, - ConstructorDeclaration constructorDeclaration, + ConstructorDeclarationBuilder constructorDeclaration, ClassHierarchyBase hierarchy) { String fieldName = isWildcardLoweredFormalParameter(name) ? '_' : name; Builder? fieldBuilder = declarationBuilder.lookupLocalMember(fieldName); diff --git a/pkg/front_end/lib/src/fragment/constructor.dart b/pkg/front_end/lib/src/fragment/constructor.dart index 55ce76fef34..d35939c45ef 100644 --- a/pkg/front_end/lib/src/fragment/constructor.dart +++ b/pkg/front_end/lib/src/fragment/constructor.dart @@ -22,7 +22,7 @@ class ConstructorFragment implements Fragment, FunctionFragment { final bool forAbstractClassOrMixin; Token? _beginInitializers; - AbstractSourceConstructorBuilder? _builder; + SourceConstructorBuilderImpl? _builder; ConstructorFragment( {required this.constructorName, @@ -55,12 +55,12 @@ class ConstructorFragment implements Fragment, FunctionFragment { } @override - AbstractSourceConstructorBuilder get builder { + SourceConstructorBuilderImpl get builder { assert(_builder != null, "Builder has not been computed for $this."); return _builder!; } - void set builder(AbstractSourceConstructorBuilder value) { + void set builder(SourceConstructorBuilderImpl value) { assert(_builder == null, "Builder has already been computed for $this."); _builder = value; } @@ -91,8 +91,7 @@ class _ConstructorBodyBuildingContext implements FunctionBodyBuildingContext { // constructor body. An error is reported by the parser but we skip // the body here to avoid overwriting the already lowering const // constructor. - !(_fragment.builder is SourceExtensionTypeConstructorBuilder && - _fragment.modifiers.isConst); + !(_fragment.builder.isExtensionTypeMember && _fragment.modifiers.isConst); @override LocalScope computeFormalParameterScope(LookupScope typeParameterScope) { diff --git a/pkg/front_end/lib/src/fragment/constructor/declaration.dart b/pkg/front_end/lib/src/fragment/constructor/declaration.dart new file mode 100644 index 00000000000..f0e51ea9f67 --- /dev/null +++ b/pkg/front_end/lib/src/fragment/constructor/declaration.dart @@ -0,0 +1,677 @@ +// Copyright (c) 2025, 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. + +import 'package:kernel/ast.dart'; +import 'package:kernel/type_algebra.dart'; + +import '../../builder/declaration_builders.dart'; +import '../../builder/formal_parameter_builder.dart'; +import '../../builder/metadata_builder.dart'; +import '../../builder/type_builder.dart'; +import '../../kernel/internal_ast.dart'; +import '../../kernel/kernel_helper.dart'; +import '../../source/name_scheme.dart'; +import '../../source/source_class_builder.dart'; +import '../../source/source_constructor_builder.dart'; +import '../../source/source_extension_type_declaration_builder.dart'; +import '../../source/source_library_builder.dart'; +import '../../source/source_member_builder.dart'; +import '../fragment.dart'; +import 'encoding.dart'; + +abstract class ConstructorDeclaration { + List? get metadata; + + OmittedTypeBuilder get returnType; + + List? get typeParameters; + + List? get formals; + + Member get constructor; + + Procedure? get tearOff; + + FunctionNode get function; + + Member get readTarget; + + Reference get readTargetReference; + + Member get invokeTarget; + + Reference get invokeTargetReference; + + void registerFunctionBody(Statement value); + + void registerNoBodyConstructor(); + + VariableDeclaration? get thisVariable; + + List? get thisTypeParameters; + + List get initializers; + + void createNode( + {required String name, + required SourceLibraryBuilder libraryBuilder, + required NameScheme nameScheme, + required Reference? constructorReference, + required Reference? tearOffReference}); + + void buildOutlineNodes( + BuildNodesCallback f, { + required SourceConstructorBuilder constructorBuilder, + required SourceLibraryBuilder libraryBuilder, + required Member declarationConstructor, + required List delayedDefaultValueCloners, + }); + + void prepareInitializers(); + + void prependInitializer(Initializer initializer); + + void becomeNative(); + + VariableDeclaration? getTearOffParameter(int index); + + void finishAugmentation(SourceConstructorBuilder origin); + + Substitution computeFieldTypeSubstitution( + DeclarationBuilder declarationBuilder); + + void buildBody(); + + bool get isRedirecting; + + bool get hasSuperInitializingFormals; + + void addSuperParameterDefaultValueCloners( + {required List delayedDefaultValueCloners, + required Member superTarget, + required List? positionalSuperParameters, + required List? namedSuperParameters, + required SourceLibraryBuilder libraryBuilder}); +} + +mixin RegularConstructorDeclarationMixin implements ConstructorDeclaration { + RegularConstructorEncoding get _encoding; + + @override + // Coverage-ignore(suite): Not run. + Member get constructor => _encoding.constructor; + + @override + // Coverage-ignore(suite): Not run. + Procedure? get tearOff => _encoding.constructorTearOff; + + @override + FunctionNode get function => _encoding.function; + + @override + Member get readTarget => _encoding.readTarget; + + @override + // Coverage-ignore(suite): Not run. + Reference get readTargetReference => _encoding.readTargetReference; + + @override + Member get invokeTarget => _encoding.invokeTarget; + + @override + // Coverage-ignore(suite): Not run. + 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? get thisTypeParameters => null; + + @override + List get initializers => _encoding.initializers; + + @override + void prepareInitializers() { + _encoding.prepareInitializers(); + } + + @override + void prependInitializer(Initializer initializer) { + _encoding.prependInitializer(initializer); + } + + @override + void becomeNative() { + _encoding.becomeNative(); + } + + @override + VariableDeclaration? getTearOffParameter(int index) { + return _encoding.getTearOffParameter(index); + } + + @override + void finishAugmentation(SourceConstructorBuilder origin) { + _encoding.finishAugmentation(origin); + } + + @override + Substitution computeFieldTypeSubstitution( + DeclarationBuilder declarationBuilder) { + // Nothing to substitute. Regular generative constructors don't have their + // own type parameters. + return Substitution.empty; + } + + @override + void buildBody() {} + + @override + bool get isRedirecting { + for (Initializer initializer in initializers) { + if (initializer is RedirectingInitializer) { + return true; + } + } + return false; + } + + @override + late final bool hasSuperInitializingFormals = + formals?.any((formal) => formal.isSuperInitializingFormal) ?? false; + + @override + void addSuperParameterDefaultValueCloners( + {required List delayedDefaultValueCloners, + required Member superTarget, + required List? positionalSuperParameters, + required List? namedSuperParameters, + required SourceLibraryBuilder libraryBuilder}) { + _encoding.addSuperParameterDefaultValueCloners( + delayedDefaultValueCloners: delayedDefaultValueCloners, + superTarget: superTarget, + positionalSuperParameters: positionalSuperParameters, + namedSuperParameters: namedSuperParameters, + libraryBuilder: libraryBuilder); + } +} + +class RegularConstructorDeclaration + with RegularConstructorDeclarationMixin + implements ConstructorDeclaration { + final ConstructorFragment _fragment; + final List? _syntheticFormals; + + @override + final RegularConstructorEncoding _encoding; + + @override + final List? typeParameters; + + RegularConstructorDeclaration(this._fragment, + {required List? syntheticFormals, + required this.typeParameters}) + : _syntheticFormals = syntheticFormals, + _encoding = new RegularConstructorEncoding( + isExternal: _fragment.modifiers.isExternal); + + @override + List? get metadata => _fragment.metadata; + + @override + OmittedTypeBuilder get returnType => _fragment.returnType; + + @override + late final List? formals = _syntheticFormals != null + ? [..._syntheticFormals, ...?_fragment.formals] + : _fragment.formals; + + @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, + startOffset: _fragment.startOffset, + fileOffset: _fragment.fullNameOffset, + endOffset: _fragment.endOffset, + isSynthetic: false, + forAbstractClassOrEnumOrMixin: _fragment.forAbstractClassOrMixin); + } + + @override + void buildOutlineNodes(BuildNodesCallback f, + {required SourceConstructorBuilder constructorBuilder, + required SourceLibraryBuilder libraryBuilder, + required Member declarationConstructor, + required List delayedDefaultValueCloners}) { + _encoding.buildOutlineNodes(f, + constructorBuilder: constructorBuilder, + libraryBuilder: libraryBuilder, + declarationBuilder: + constructorBuilder.declarationBuilder as SourceClassBuilder, + declarationConstructor: declarationConstructor, + formalsOffset: _fragment.formalsOffset, + isConst: _fragment.modifiers.isConst, + returnType: returnType, + typeParameters: typeParameters, + formals: formals, + delayedDefaultValueCloners: delayedDefaultValueCloners); + } +} + +// Coverage-ignore(suite): Not run. +class PrimaryConstructorDeclaration + with RegularConstructorDeclarationMixin + implements ConstructorDeclaration { + final PrimaryConstructorFragment _fragment; + + @override + final RegularConstructorEncoding _encoding; + + PrimaryConstructorDeclaration(this._fragment) + : _encoding = new RegularConstructorEncoding( + isExternal: _fragment.modifiers.isExternal); + + @override + OmittedTypeBuilder get returnType => _fragment.returnType; + + @override + List? get metadata => null; + + @override + List? get formals => _fragment.formals; + + @override + List? get typeParameters => null; + + @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, + startOffset: _fragment.startOffset, + fileOffset: _fragment.fileOffset, + // TODO(johnniwinther): Provide `endOffset`. + endOffset: _fragment.formalsOffset, + isSynthetic: false, + forAbstractClassOrEnumOrMixin: _fragment.forAbstractClassOrMixin); + } + + @override + void buildOutlineNodes(BuildNodesCallback f, + {required SourceConstructorBuilder constructorBuilder, + required SourceLibraryBuilder libraryBuilder, + required Member declarationConstructor, + required List delayedDefaultValueCloners}) { + _encoding.buildOutlineNodes(f, + constructorBuilder: constructorBuilder, + libraryBuilder: libraryBuilder, + declarationBuilder: + constructorBuilder.declarationBuilder as SourceClassBuilder, + declarationConstructor: declarationConstructor, + formalsOffset: _fragment.formalsOffset, + isConst: _fragment.modifiers.isConst, + returnType: returnType, + typeParameters: typeParameters, + formals: formals, + delayedDefaultValueCloners: delayedDefaultValueCloners); + } +} + +class DefaultEnumConstructorDeclaration + with RegularConstructorDeclarationMixin + implements ConstructorDeclaration { + final Uri _fileUri; + final int _fileOffset; + + @override + final OmittedTypeBuilder returnType; + + @override + final List formals; + + @override + final RegularConstructorEncoding _encoding = + new RegularConstructorEncoding(isExternal: false); + + DefaultEnumConstructorDeclaration( + {required this.returnType, + required this.formals, + required Uri fileUri, + required int fileOffset}) + : _fileUri = fileUri, + _fileOffset = fileOffset; + + @override + List? get metadata => null; + + @override + List? get typeParameters => null; + + @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: _fileUri, + startOffset: _fileOffset, + fileOffset: _fileOffset, + endOffset: _fileOffset, + isSynthetic: true, + forAbstractClassOrEnumOrMixin: true); + } + + @override + void buildOutlineNodes(BuildNodesCallback f, + {required SourceConstructorBuilder constructorBuilder, + required SourceLibraryBuilder libraryBuilder, + required Member declarationConstructor, + required List delayedDefaultValueCloners}) { + _encoding.buildOutlineNodes(f, + constructorBuilder: constructorBuilder, + libraryBuilder: libraryBuilder, + declarationBuilder: + constructorBuilder.declarationBuilder as SourceClassBuilder, + declarationConstructor: declarationConstructor, + formalsOffset: _fileOffset, + isConst: true, + returnType: returnType, + typeParameters: typeParameters, + formals: formals, + delayedDefaultValueCloners: delayedDefaultValueCloners); + } +} + +mixin ExtensionTypeConstructorDeclarationMixin + implements ConstructorDeclaration { + ExtensionTypeConstructorEncoding get _encoding; + + @override + // Coverage-ignore(suite): Not run. + Member get constructor => _encoding.constructor; + + @override + // Coverage-ignore(suite): Not run. + Procedure? get tearOff => _encoding.constructorTearOff; + + @override + FunctionNode get function => _encoding.function; + + @override + Member get readTarget => _encoding.readTarget; + + @override + // Coverage-ignore(suite): Not run. + Reference get readTargetReference => _encoding.readTargetReference; + + @override + Member get invokeTarget => _encoding.invokeTarget; + + @override + // Coverage-ignore(suite): Not run. + Reference get invokeTargetReference => _encoding.invokeTargetReference; + + @override + void registerFunctionBody(Statement value) { + _encoding.registerFunctionBody(value); + } + + @override + void registerNoBodyConstructor() { + _encoding.registerNoBodyConstructor(); + } + + @override + VariableDeclaration? get thisVariable => _encoding.thisVariable; + + @override + List? get thisTypeParameters => _encoding.thisTypeParameters; + + @override + List get initializers => _encoding.initializers; + + @override + void prepareInitializers() { + _encoding.prepareInitializers(); + } + + @override + void prependInitializer(Initializer initializer) { + _encoding.prependInitializer(initializer); + } + + @override + void becomeNative() { + throw new UnsupportedError("$runtimeType.becomeNative()"); + } + + @override + VariableDeclaration? getTearOffParameter(int index) { + return _encoding.getTearOffParameter(index); + } + + @override + void finishAugmentation(SourceConstructorBuilder origin) { + throw new UnsupportedError('$runtimeType.finishAugmentation'); + } + + @override + Substitution computeFieldTypeSubstitution( + DeclarationBuilder declarationBuilder) { + if (typeParameters != null) { + assert( + declarationBuilder.typeParameters!.length == typeParameters?.length); + return Substitution.fromPairs( + (declarationBuilder as SourceExtensionTypeDeclarationBuilder) + .extensionTypeDeclaration + .typeParameters, + new List.generate( + declarationBuilder.typeParameters!.length, + (int index) => new TypeParameterType.withDefaultNullability( + function.typeParameters[index]))); + } else { + return Substitution.empty; + } + } + + @override + void buildBody() { + _encoding.buildBody(); + } + + @override + 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 delayedDefaultValueCloners, + required Member superTarget, + required List? positionalSuperParameters, + required List? namedSuperParameters, + required SourceLibraryBuilder libraryBuilder}) { + throw new UnsupportedError( + '$runtimeType.addSuperParameterDefaultValueCloners'); + } +} + +class ExtensionTypeConstructorDeclaration + with ExtensionTypeConstructorDeclarationMixin + implements ConstructorDeclaration { + final ConstructorFragment _fragment; + + @override + final List? typeParameters; + + @override + final ExtensionTypeConstructorEncoding _encoding; + + ExtensionTypeConstructorDeclaration(this._fragment, + {required this.typeParameters}) + : _encoding = new ExtensionTypeConstructorEncoding( + isExternal: _fragment.modifiers.isExternal); + + @override + List? get metadata => _fragment.metadata; + + @override + OmittedTypeBuilder get returnType => _fragment.returnType; + + @override + List? get formals => _fragment.formals; + + @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 delayedDefaultValueCloners}) { + _encoding.buildOutlineNodes(f, + constructorBuilder: constructorBuilder, + libraryBuilder: libraryBuilder, + declarationBuilder: constructorBuilder.declarationBuilder + as SourceExtensionTypeDeclarationBuilder, + declarationConstructor: declarationConstructor, + fileOffset: _fragment.fullNameOffset, + formalsOffset: _fragment.formalsOffset, + isConst: _fragment.modifiers.isConst, + returnType: returnType, + typeParameters: typeParameters, + formals: formals, + delayedDefaultValueCloners: delayedDefaultValueCloners); + } +} + +class ExtensionTypePrimaryConstructorDeclaration + with ExtensionTypeConstructorDeclarationMixin + implements ConstructorDeclaration { + final PrimaryConstructorFragment _fragment; + + @override + final List? typeParameters; + + @override + final ExtensionTypeConstructorEncoding _encoding; + + ExtensionTypePrimaryConstructorDeclaration(this._fragment, + {required this.typeParameters}) + : _encoding = new ExtensionTypeConstructorEncoding( + isExternal: _fragment.modifiers.isExternal); + + @override + List? get metadata => null; + + @override + OmittedTypeBuilder get returnType => _fragment.returnType; + + @override + List? get formals => _fragment.formals; + + @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.fileOffset, + // TODO(johnniwinther): Provide `endOffset`. + endOffset: _fragment.formalsOffset, + forAbstractClassOrEnumOrMixin: _fragment.forAbstractClassOrMixin); + } + + @override + void buildOutlineNodes(BuildNodesCallback f, + {required SourceConstructorBuilder constructorBuilder, + required SourceLibraryBuilder libraryBuilder, + required Member declarationConstructor, + required List delayedDefaultValueCloners}) { + _encoding.buildOutlineNodes(f, + constructorBuilder: constructorBuilder, + libraryBuilder: libraryBuilder, + declarationBuilder: constructorBuilder.declarationBuilder + as SourceExtensionTypeDeclarationBuilder, + declarationConstructor: declarationConstructor, + fileOffset: _fragment.fileOffset, + formalsOffset: _fragment.formalsOffset, + isConst: _fragment.modifiers.isConst, + returnType: returnType, + typeParameters: typeParameters, + formals: formals, + delayedDefaultValueCloners: delayedDefaultValueCloners); + } +} diff --git a/pkg/front_end/lib/src/fragment/constructor/encoding.dart b/pkg/front_end/lib/src/fragment/constructor/encoding.dart new file mode 100644 index 00000000000..2ac19d020ee --- /dev/null +++ b/pkg/front_end/lib/src/fragment/constructor/encoding.dart @@ -0,0 +1,564 @@ +// Copyright (c) 2025, 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. + +import 'package:kernel/ast.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'; +import '../../kernel/constructor_tearoff_lowering.dart'; +import '../../kernel/internal_ast.dart'; +import '../../kernel/kernel_helper.dart'; +import '../../source/name_scheme.dart'; +import '../../source/source_class_builder.dart'; +import '../../source/source_constructor_builder.dart'; +import '../../source/source_extension_type_declaration_builder.dart'; +import '../../source/source_function_builder.dart'; +import '../../source/source_library_builder.dart'; +import '../../source/source_member_builder.dart'; +import '../../type_inference/type_schema.dart'; + +class RegularConstructorEncoding { + late final Constructor _constructor; + + late final Procedure? _constructorTearOff; + + final bool _isExternal; + + Statement? bodyInternal; + + RegularConstructorEncoding({required bool isExternal}) + : _isExternal = isExternal; + + Member get readTarget => + _constructorTearOff ?? + // The case is need to ensure that the upper bound is [Member] and not + // [GenericFunction]. + _constructor as Member; + + // Coverage-ignore(suite): Not run. + Reference get readTargetReference => + (_constructorTearOff ?? _constructor).reference; + + Member get invokeTarget => _constructor; + + // Coverage-ignore(suite): Not run. + Reference get invokeTargetReference => _constructor.reference; + + void registerFunctionBody(Statement value) { + function.body = value..parent = function; + } + + void registerNoBodyConstructor() { + if (!_isExternal) { + registerFunctionBody(new EmptyStatement()); + } + } + + FunctionNode get function => _constructor.function; + + void createNode( + {required String name, + required SourceLibraryBuilder libraryBuilder, + required NameScheme nameScheme, + required Reference? constructorReference, + required Reference? tearOffReference, + required Uri fileUri, + required int startOffset, + required int fileOffset, + required int endOffset, + required bool isSynthetic, + required bool forAbstractClassOrEnumOrMixin}) { + _constructor = new Constructor( + new FunctionNode(_isExternal ? null : new EmptyStatement()), + name: dummyName, + fileUri: fileUri, + reference: constructorReference, + isSynthetic: isSynthetic) + ..startFileOffset = startOffset + ..fileOffset = fileOffset + ..fileEndOffset = endOffset; + nameScheme + .getConstructorMemberName(name, isTearOff: false) + .attachMember(_constructor); + _constructorTearOff = createConstructorTearOffProcedure( + nameScheme.getConstructorMemberName(name, isTearOff: true), + libraryBuilder, + fileUri, + fileOffset, + tearOffReference, + forAbstractClassOrEnumOrMixin: forAbstractClassOrEnumOrMixin); + } + + // Coverage-ignore(suite): Not run. + Member get constructor => _constructor; + + // Coverage-ignore(suite): Not run. + Procedure? get constructorTearOff => _constructorTearOff; + + List get initializers => _constructor.initializers; + + void buildOutlineNodes( + BuildNodesCallback f, { + required SourceConstructorBuilder constructorBuilder, + required SourceLibraryBuilder libraryBuilder, + required SourceClassBuilder declarationBuilder, + required Member declarationConstructor, + required int formalsOffset, + required bool isConst, + required TypeBuilder returnType, + required List? typeParameters, + required List? formals, + required List delayedDefaultValueCloners, + }) { + _build( + constructorBuilder: constructorBuilder, + libraryBuilder: libraryBuilder, + classBuilder: declarationBuilder, + declarationConstructor: declarationConstructor, + formalsOffset: formalsOffset, + isConst: isConst, + returnType: returnType, + typeParameters: typeParameters, + formals: formals, + delayedDefaultValueCloners: delayedDefaultValueCloners); + f( + member: _constructor, + tearOff: _constructorTearOff, + kind: BuiltMemberKind.Constructor); + } + + bool _hasBeenBuilt = false; + + void _build({ + required SourceConstructorBuilder constructorBuilder, + required SourceLibraryBuilder libraryBuilder, + required SourceClassBuilder classBuilder, + required Member declarationConstructor, + required int formalsOffset, + required bool isConst, + required TypeBuilder returnType, + required List? typeParameters, + required List? formals, + required List delayedDefaultValueCloners, + }) { + if (!_hasBeenBuilt) { + // According to the specification §9.3 the return type of a constructor + // function is its enclosing class. + function.asyncMarker = AsyncMarker.Sync; + buildTypeParametersAndFormals( + libraryBuilder, function, typeParameters, formals, + classTypeParameters: null, supportsTypeParameters: false); + Class enclosingClass = classBuilder.cls; + List typeParameterTypes = []; + for (int i = 0; i < enclosingClass.typeParameters.length; i++) { + TypeParameter typeParameter = enclosingClass.typeParameters[i]; + typeParameterTypes + .add(new TypeParameterType.withDefaultNullability(typeParameter)); + } + InterfaceType type = new InterfaceType( + enclosingClass, Nullability.nonNullable, typeParameterTypes); + returnType.registerInferredType(type); + _constructor.function.fileOffset = formalsOffset; + _constructor.function.fileEndOffset = _constructor.fileEndOffset; + _constructor.function.typeParameters = const []; + _constructor.isConst = isConst; + _constructor.isExternal = _isExternal; + + if (_constructorTearOff != null) { + DelayedDefaultValueCloner delayedDefaultValueCloner = + buildConstructorTearOffProcedure( + tearOff: _constructorTearOff, + declarationConstructor: declarationConstructor, + implementationConstructor: _constructor, + enclosingDeclarationTypeParameters: + classBuilder.cls.typeParameters, + libraryBuilder: libraryBuilder); + delayedDefaultValueCloners.add(delayedDefaultValueCloner); + } + + _hasBeenBuilt = true; + } + if (formals != null) { + bool needsInference = false; + for (FormalParameterBuilder formal in formals) { + if (formal.type is InferableTypeBuilder && + (formal.isInitializingFormal || formal.isSuperInitializingFormal)) { + formal.variable!.type = const UnknownType(); + needsInference = true; + } else if (!formal.hasDeclaredInitializer && + formal.isSuperInitializingFormal) { + needsInference = true; + } + } + if (needsInference) { + libraryBuilder.loader + .registerConstructorToBeInferred(_constructor, constructorBuilder); + } + } + } + + 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 + // parsing, so we simply clear parsed initializers and rebuild them + // again. + // For when doing an experimental incremental compilation they are also + // potentially done more than once (because it rebuilds the bodies of an old + // 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. + _constructor.initializers = []; + //redirectingInitializer = null; + //superInitializer = null; + } + + void prependInitializer(Initializer initializer) { + initializer.parent = _constructor; + _constructor.initializers.insert(0, initializer); + } + + void becomeNative() { + _constructor.isExternal = true; + } + + VariableDeclaration? getTearOffParameter(int index) { + Procedure? constructorTearOff = _constructorTearOff; + if (constructorTearOff != null) { + if (index < constructorTearOff.function.positionalParameters.length) { + return constructorTearOff.function.positionalParameters[index]; + } else { + index -= constructorTearOff.function.positionalParameters.length; + if (index < constructorTearOff.function.namedParameters.length) { + return constructorTearOff.function.namedParameters[index]; + } + } + } + return null; + } + + void finishAugmentation(SourceConstructorBuilder origin) { + finishConstructorAugmentation( + origin.invokeTarget as Constructor, _constructor); + + if (_constructorTearOff != null) { + finishProcedureAugmentation( + origin.readTarget as Procedure, _constructorTearOff); + } + } + + bool _hasAddedDefaultValueCloners = false; + + void addSuperParameterDefaultValueCloners( + {required List delayedDefaultValueCloners, + required Member superTarget, + required List? positionalSuperParameters, + required List? namedSuperParameters, + required SourceLibraryBuilder libraryBuilder}) { + if (!_hasAddedDefaultValueCloners) { + // If this constructor formals are part of a cyclic dependency this + // might be called more than once. + delayedDefaultValueCloners.add(new DelayedDefaultValueCloner( + superTarget, invokeTarget, + positionalSuperParameters: positionalSuperParameters ?? const [], + namedSuperParameters: namedSuperParameters ?? const [], + isOutlineNode: true, + libraryBuilder: libraryBuilder)); + if (_constructorTearOff != null) { + delayedDefaultValueCloners.add(new DelayedDefaultValueCloner( + superTarget, _constructorTearOff, + positionalSuperParameters: + positionalSuperParameters ?? const [], + namedSuperParameters: namedSuperParameters ?? const [], + isOutlineNode: true, + libraryBuilder: libraryBuilder)); + } + _hasAddedDefaultValueCloners = true; + } + } +} + +class ExtensionTypeConstructorEncoding { + late final Procedure _constructor; + + late final Procedure? _constructorTearOff; + + final bool _isExternal; + + Statement? bodyInternal; + + /// If this procedure is an extension instance member or extension type + /// instance member, [_thisVariable] holds the synthetically added `this` + /// parameter. + VariableDeclaration? _thisVariable; + + /// If this procedure is an extension instance member or extension type + /// instance member, [_thisTypeParameters] holds the type parameters copied + /// from the extension/extension type declaration. + List? _thisTypeParameters; + + List initializers = []; + + ExtensionTypeConstructorEncoding({required bool isExternal}) + : _isExternal = isExternal; + + Member get readTarget => + _constructorTearOff ?? // Coverage-ignore(suite): Not run. + _constructor; + + // Coverage-ignore(suite): Not run. + Reference get readTargetReference => + (_constructorTearOff ?? _constructor).reference; + + Member get invokeTarget => _constructor; + + // Coverage-ignore(suite): Not run. + Reference get invokeTargetReference => _constructor.reference; + + void registerFunctionBody(Statement value) { + function.body = value..parent = function; + } + + void registerNoBodyConstructor() { + if (!_hasBuiltBody && !_isExternal) { + registerFunctionBody(new EmptyStatement()); + } + } + + FunctionNode get function => _constructor.function; + + void createNode( + {required String name, + required SourceLibraryBuilder libraryBuilder, + required NameScheme nameScheme, + required Reference? constructorReference, + required Reference? tearOffReference, + required Uri fileUri, + required int fileOffset, + required int endOffset, + required bool forAbstractClassOrEnumOrMixin}) { + _constructor = new Procedure(dummyName, ProcedureKind.Method, + new FunctionNode(_isExternal ? null : new EmptyStatement()), + fileUri: fileUri, reference: constructorReference) + ..fileOffset = fileOffset + ..fileEndOffset = endOffset; + nameScheme + .getConstructorMemberName(name, isTearOff: false) + .attachMember(_constructor); + _constructorTearOff = createConstructorTearOffProcedure( + nameScheme.getConstructorMemberName(name, isTearOff: true), + libraryBuilder, + fileUri, + fileOffset, + 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? typeParameters, + required List? formals, + required List 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); + } + + bool _hasBeenBuilt = false; + + void _build({ + 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? typeParameters, + required List? formals, + required List delayedDefaultValueCloners, + }) { + if (!_hasBeenBuilt) { + // According to the specification §9.3 the return type of a constructor + // function is its enclosing class. + function.asyncMarker = AsyncMarker.Sync; + buildTypeParametersAndFormals( + libraryBuilder, function, typeParameters, formals, + classTypeParameters: null, supportsTypeParameters: true); + + if (declarationBuilder.typeParameters != null) { + int count = declarationBuilder.typeParameters!.length; + _thisTypeParameters = new List.generate( + count, (int index) => function.typeParameters[index], + growable: false); + } + List typeArguments; + if (_thisTypeParameters != null) { + typeArguments = [ + for (TypeParameter parameter in _thisTypeParameters!) + new TypeParameterType.withDefaultNullability(parameter) + ]; + } else { + typeArguments = []; + } + + ExtensionTypeDeclaration extensionTypeDeclaration = + declarationBuilder.extensionTypeDeclaration; + _thisVariable = new VariableDeclarationImpl(syntheticThisName, + isFinal: true, + type: new ExtensionType( + extensionTypeDeclaration, Nullability.nonNullable, typeArguments)) + ..fileOffset = fileOffset + ..isLowered = true; + + List typeParameterTypes = []; + for (int i = 0; i < function.typeParameters.length; i++) { + TypeParameter typeParameter = function.typeParameters[i]; + typeParameterTypes + .add(new TypeParameterType.withDefaultNullability(typeParameter)); + } + ExtensionType type = new ExtensionType(extensionTypeDeclaration, + Nullability.nonNullable, typeParameterTypes); + returnType.registerInferredType(type); + _constructor.function.fileOffset = formalsOffset; + _constructor.function.fileEndOffset = _constructor.fileEndOffset; + _constructor.isConst = isConst; + _constructor.isExternal = _isExternal; + _constructor.isStatic = true; + _constructor.isExtensionTypeMember = true; + + if (_constructorTearOff != null) { + delayedDefaultValueCloners.add(buildConstructorTearOffProcedure( + tearOff: _constructorTearOff, + declarationConstructor: declarationConstructor, + implementationConstructor: _constructor, + libraryBuilder: libraryBuilder)); + } + + _hasBeenBuilt = true; + } + if (formals != null) { + bool needsInference = false; + for (FormalParameterBuilder formal in formals) { + if (formal.type is InferableTypeBuilder && + (formal.isInitializingFormal || formal.isSuperInitializingFormal)) { + formal.variable!.type = const UnknownType(); + needsInference = true; + } else if (!formal.hasDeclaredInitializer && + formal.isSuperInitializingFormal) { + needsInference = true; + } + } + if (needsInference) { + libraryBuilder.loader + .registerConstructorToBeInferred(_constructor, constructorBuilder); + } + } + } + + VariableDeclaration? get thisVariable { + assert(_thisVariable != null, + "ProcedureBuilder.thisVariable has not been set."); + return _thisVariable; + } + + List? get thisTypeParameters { + // Use [_thisVariable] as marker for whether this type parameters have + // been computed. + assert(_thisVariable != null, + "ProcedureBuilder.thisTypeParameters has not been set."); + return _thisTypeParameters; + } + + 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 + // parsing, so we simply clear parsed initializers and rebuild them + // again. + // For when doing an experimental incremental compilation they are also + // potentially done more than once (because it rebuilds the bodies of an old + // 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 = []; + //redirectingInitializer = null; + //superInitializer = null; + } + + void prependInitializer(Initializer initializer) { + initializers.insert(0, initializer); + } + + VariableDeclaration? getTearOffParameter(int index) { + Procedure? constructorTearOff = _constructorTearOff; + if (constructorTearOff != null) { + if (index < constructorTearOff.function.positionalParameters.length) { + return constructorTearOff.function.positionalParameters[index]; + } else { + index -= constructorTearOff.function.positionalParameters.length; + if (index < constructorTearOff.function.namedParameters.length) { + return constructorTearOff.function.namedParameters[index]; + } + } + } + return null; + } + + bool _hasBuiltBody = false; + + void buildBody() { + if (_hasBuiltBody) { + return; + } + if (!_isExternal) { + VariableDeclaration thisVariable = this.thisVariable!; + List statements = [thisVariable]; + ExtensionTypeInitializerToStatementConverter visitor = + new ExtensionTypeInitializerToStatementConverter( + statements, thisVariable); + for (Initializer initializer in initializers) { + initializer.accept(visitor); + } + if (function.body != null && function.body is! EmptyStatement) { + statements.add(function.body!); + } + statements.add(new ReturnStatement(new VariableGet(thisVariable))); + registerFunctionBody(new Block(statements)); + } + _hasBuiltBody = true; + } +} diff --git a/pkg/front_end/lib/src/fragment/getter.dart b/pkg/front_end/lib/src/fragment/getter.dart index 526b22d9e09..c1e5c6526fa 100644 --- a/pkg/front_end/lib/src/fragment/getter.dart +++ b/pkg/front_end/lib/src/fragment/getter.dart @@ -898,7 +898,7 @@ class _GetterFragmentBodyBuilderContext extends BodyBuilderContext { TypeBuilder get returnType => _fragment.returnType; @override - void setBody(Statement body) { + void registerFunctionBody(Statement body) { function.body = body..parent = function; } diff --git a/pkg/front_end/lib/src/fragment/method.dart b/pkg/front_end/lib/src/fragment/method.dart index dbe8e642ae3..18525a85442 100644 --- a/pkg/front_end/lib/src/fragment/method.dart +++ b/pkg/front_end/lib/src/fragment/method.dart @@ -1276,7 +1276,7 @@ class _MethodFragmentBodyBuilderContext extends BodyBuilderContext { TypeBuilder get returnType => _fragment.returnType; @override - void setBody(Statement body) { + void registerFunctionBody(Statement body) { function.body = body..parent = function; } diff --git a/pkg/front_end/lib/src/fragment/primary_constructor.dart b/pkg/front_end/lib/src/fragment/primary_constructor.dart index ed22ba3dd75..3f78c8ebc2e 100644 --- a/pkg/front_end/lib/src/fragment/primary_constructor.dart +++ b/pkg/front_end/lib/src/fragment/primary_constructor.dart @@ -18,7 +18,7 @@ class PrimaryConstructorFragment implements Fragment, FunctionFragment { final bool forAbstractClassOrMixin; Token? _beginInitializers; - AbstractSourceConstructorBuilder? _builder; + SourceConstructorBuilderImpl? _builder; PrimaryConstructorFragment( {required this.constructorName, @@ -47,12 +47,12 @@ class PrimaryConstructorFragment implements Fragment, FunctionFragment { } @override - AbstractSourceConstructorBuilder get builder { + SourceConstructorBuilderImpl get builder { assert(_builder != null, "Builder has not been computed for $this."); return _builder!; } - void set builder(AbstractSourceConstructorBuilder value) { + void set builder(SourceConstructorBuilderImpl value) { assert(_builder == null, "Builder has already been computed for $this."); _builder = value; } diff --git a/pkg/front_end/lib/src/fragment/setter.dart b/pkg/front_end/lib/src/fragment/setter.dart index 40e07337da9..38b8b88e403 100644 --- a/pkg/front_end/lib/src/fragment/setter.dart +++ b/pkg/front_end/lib/src/fragment/setter.dart @@ -919,7 +919,7 @@ class _SetterFragmentBodyBuilderContext extends BodyBuilderContext { TypeBuilder get returnType => _fragment.returnType; @override - void setBody(Statement body) { + void registerFunctionBody(Statement body) { function.body = body..parent = function; } diff --git a/pkg/front_end/lib/src/kernel/body_builder.dart b/pkg/front_end/lib/src/kernel/body_builder.dart index 9406f7be5f5..f8ff1259bed 100644 --- a/pkg/front_end/lib/src/kernel/body_builder.dart +++ b/pkg/front_end/lib/src/kernel/body_builder.dart @@ -1340,7 +1340,7 @@ class BodyBuilder extends StackListenerImpl ]) ..fileOffset = body.fileOffset; } - _context.setBody(body); + _context.registerFunctionBody(body); } performBacklogComputations(); @@ -2114,7 +2114,7 @@ class BodyBuilder extends StackListenerImpl /// >If a generative constructor c is not a redirecting constructor /// >and no body is provided, then c implicitly has an empty body {}. /// We use an empty statement instead. - function.body = new EmptyStatement()..parent = function; + _context.registerNoBodyConstructor(); } else if (body != null && _context.isMixinClass && !_context.isFactory) { // Report an error if a mixin class has a non-factory constructor with a // body. diff --git a/pkg/front_end/lib/src/kernel/body_builder_context.dart b/pkg/front_end/lib/src/kernel/body_builder_context.dart index 07216ff6cf9..42d09939b75 100644 --- a/pkg/front_end/lib/src/kernel/body_builder_context.dart +++ b/pkg/front_end/lib/src/kernel/body_builder_context.dart @@ -368,8 +368,13 @@ abstract class BodyBuilderContext { } /// Registers [body] as the result of the body building. - void setBody(Statement body) { - throw new UnsupportedError("${runtimeType}.setBody"); + void registerFunctionBody(Statement body) { + throw new UnsupportedError("${runtimeType}.registerFunctionBody"); + } + + /// Registers that the constructor has no body. + void registerNoBodyConstructor() { + throw new UnsupportedError("${runtimeType}.registerNoBodyConstructor"); } /// Returns the type of `this` in the body being built. @@ -793,8 +798,8 @@ mixin _FunctionBodyBuilderContextMixin } } -mixin _ConstructorBodyBuilderContextMixin - implements BodyBuilderContext { +mixin _ConstructorBodyBuilderContextMixin< + T extends ConstructorDeclarationBuilder> implements BodyBuilderContext { T get _member; TreeNode get _initializerParent; @@ -853,11 +858,11 @@ mixin _ConstructorBodyBuilderContextMixin class ConstructorBodyBuilderContext extends BodyBuilderContext with - _FunctionBodyBuilderContextMixin, - _ConstructorBodyBuilderContextMixin, - _MemberBodyBuilderContext { + _FunctionBodyBuilderContextMixin, + _ConstructorBodyBuilderContextMixin, + _MemberBodyBuilderContext { @override - final DeclaredSourceConstructorBuilder _member; + final SourceConstructorBuilderImpl _member; @override final Member _builtMember; @@ -872,8 +877,13 @@ class ConstructorBodyBuilderContext extends BodyBuilderContext } @override - void setBody(Statement body) { - _member.body = body; + void registerFunctionBody(Statement body) { + _member.registerFunctionBody(body); + } + + @override + void registerNoBodyConstructor() { + _member.registerNoBodyConstructor(); } @override @@ -883,7 +893,8 @@ class ConstructorBodyBuilderContext extends BodyBuilderContext @override bool needsImplicitSuperInitializer(CoreTypes coreTypes) { - return !_declarationContext.isObjectClass(coreTypes) && + return _member.isClassMember && + !_declarationContext.isObjectClass(coreTypes) && !isExternalConstructor; } @@ -891,40 +902,6 @@ class ConstructorBodyBuilderContext extends BodyBuilderContext TreeNode get _initializerParent => _member.invokeTarget; } -class ExtensionTypeConstructorBodyBuilderContext extends BodyBuilderContext - with - _FunctionBodyBuilderContextMixin, - _ConstructorBodyBuilderContextMixin< - SourceExtensionTypeConstructorBuilder>, - _MemberBodyBuilderContext { - @override - final SourceExtensionTypeConstructorBuilder _member; - @override - final Member _builtMember; - - ExtensionTypeConstructorBodyBuilderContext(this._member, this._builtMember) - : super(_member.libraryBuilder, _member.declarationBuilder, - isDeclarationInstanceMember: _member.isDeclarationInstanceMember); - - @override - LocalScope computeFormalParameterInitializerScope(LocalScope parent) { - return _member.computeFormalParameterInitializerScope(parent); - } - - @override - void setBody(Statement body) { - _member.body = body; - } - - @override - bool isConstructorCyclic(String name) { - return _declarationContext.isConstructorCyclic(_member.name, name); - } - - @override - TreeNode get _initializerParent => _member.invokeTarget; -} - class ParameterBodyBuilderContext extends BodyBuilderContext { factory ParameterBodyBuilderContext( LibraryBuilder libraryBuilder, diff --git a/pkg/front_end/lib/src/kernel/kernel_target.dart b/pkg/front_end/lib/src/kernel/kernel_target.dart index 29083829325..7df0adb2d86 100644 --- a/pkg/front_end/lib/src/kernel/kernel_target.dart +++ b/pkg/front_end/lib/src/kernel/kernel_target.dart @@ -102,6 +102,14 @@ class KernelTarget { const PredefinedTypeName("dynamic"), const NullabilityBuilder.inherent(), instanceTypeParameterAccess: InstanceTypeParameterAccessState.Unexpected); + final NamedTypeBuilder intType = new NamedTypeBuilderImpl( + const PredefinedTypeName("int"), const NullabilityBuilder.omitted(), + instanceTypeParameterAccess: InstanceTypeParameterAccessState.Unexpected); + + final NamedTypeBuilder stringType = new NamedTypeBuilderImpl( + const PredefinedTypeName("String"), const NullabilityBuilder.omitted(), + instanceTypeParameterAccess: InstanceTypeParameterAccessState.Unexpected); + final NamedTypeBuilder objectType = new NamedTypeBuilderImpl( const PredefinedTypeName("Object"), const NullabilityBuilder.omitted(), instanceTypeParameterAccess: InstanceTypeParameterAccessState.Unexpected); @@ -1232,30 +1240,25 @@ class KernelTarget { enclosingClass.enclosingLibrary.nonNullable, typeParameterTypes); } + void _bindCoreType(NamedTypeBuilder typeBuilder, {bool isNullClass = false}) { + TypeDeclarationBuilder typeDeclarationBuilder = loader.coreLibrary + .lookupLocalMember(typeBuilder.typeName.name, required: true) + as TypeDeclarationBuilder; + typeBuilder.bind(loader.coreLibrary, typeDeclarationBuilder); + if (isNullClass) { + (typeDeclarationBuilder as ClassBuilder).isNullClass = true; + } + } + void setupTopAndBottomTypes() { - objectType.bind( - loader.coreLibrary, - loader.coreLibrary.lookupLocalMember("Object", required: true) - as TypeDeclarationBuilder); - dynamicType.bind( - loader.coreLibrary, - loader.coreLibrary.lookupLocalMember("dynamic", required: true) - as TypeDeclarationBuilder); - ClassBuilder nullClassBuilder = loader.coreLibrary - .lookupLocalMember("Null", required: true) as ClassBuilder; - nullType.bind(loader.coreLibrary, nullClassBuilder..isNullClass = true); - bottomType.bind( - loader.coreLibrary, - loader.coreLibrary.lookupLocalMember("Never", required: true) - as TypeDeclarationBuilder); - enumType.bind( - loader.coreLibrary, - loader.coreLibrary.lookupLocalMember("Enum", required: true) - as TypeDeclarationBuilder); - underscoreEnumType.bind( - loader.coreLibrary, - loader.coreLibrary.lookupLocalMember("_Enum", required: true) - as TypeDeclarationBuilder); + _bindCoreType(objectType); + _bindCoreType(stringType); + _bindCoreType(intType); + _bindCoreType(dynamicType); + _bindCoreType(nullType, isNullClass: true); + _bindCoreType(bottomType); + _bindCoreType(enumType); + _bindCoreType(underscoreEnumType); } void computeCoreTypes() { @@ -1421,15 +1424,16 @@ class KernelTarget { } } - Map> + Map> constructorInitializedFields = new Map.identity(); Set? initializedFieldBuilders = null; Set? uninitializedInstanceFields; - Iterator constructorIterator = - classDeclaration.fullConstructorIterator(); + Iterator constructorIterator = + classDeclaration + .fullConstructorIterator(); while (constructorIterator.moveNext()) { - ConstructorDeclaration constructor = constructorIterator.current; + ConstructorDeclarationBuilder constructor = constructorIterator.current; if (constructor.isEffectivelyRedirecting) continue; if (constructor.isConst && nonFinalFields.isNotEmpty) { classDeclaration.addProblem(messageConstConstructorNonFinalField, @@ -1514,9 +1518,10 @@ class KernelTarget { // Run through all fields that are initialized by some constructor, and // make sure that all other constructors also initialize them. - for (MapEntry> entry + for (MapEntry> entry in constructorInitializedFields.entries) { - ConstructorDeclaration constructorBuilder = entry.key; + ConstructorDeclarationBuilder constructorBuilder = entry.key; Set fieldBuilders = entry.value; for (SourcePropertyBuilder fieldBuilder in initializedFieldBuilders!.difference(fieldBuilders)) { diff --git a/pkg/front_end/lib/src/source/constructor_declaration.dart b/pkg/front_end/lib/src/source/constructor_declaration.dart index c6793433f72..47f64e199a8 100644 --- a/pkg/front_end/lib/src/source/constructor_declaration.dart +++ b/pkg/front_end/lib/src/source/constructor_declaration.dart @@ -12,7 +12,7 @@ import 'source_property_builder.dart'; /// Common interface for builders for generative constructor declarations in /// source code, such as a generative constructor in a regular class or a /// generative constructor in an extension type declaration. -abstract class ConstructorDeclaration implements SourceFunctionBuilder { +abstract class ConstructorDeclarationBuilder implements SourceFunctionBuilder { /// Returns `true` if this constructor, including its augmentations, is /// external. /// diff --git a/pkg/front_end/lib/src/source/source_class_builder.dart b/pkg/front_end/lib/src/source/source_class_builder.dart index 5e50ac4a1f5..b356df5f5b1 100644 --- a/pkg/front_end/lib/src/source/source_class_builder.dart +++ b/pkg/front_end/lib/src/source/source_class_builder.dart @@ -940,7 +940,7 @@ class SourceClassBuilder extends ClassBuilderImpl SourceMemberBuilder constructor = constructorIterator.current; // Assumes the constructor isn't synthetic since // [installSyntheticConstructors] hasn't been called yet. - if (constructor is DeclaredSourceConstructorBuilder) { + if (constructor is SourceConstructorBuilderImpl) { // Report an error if a mixin class has a constructor with parameters, // is external, or is a redirecting constructor. if (constructor.isRedirecting || diff --git a/pkg/front_end/lib/src/source/source_constructor_builder.dart b/pkg/front_end/lib/src/source/source_constructor_builder.dart index c7356eb8951..20fd2bcfdbd 100644 --- a/pkg/front_end/lib/src/source/source_constructor_builder.dart +++ b/pkg/front_end/lib/src/source/source_constructor_builder.dart @@ -8,7 +8,6 @@ import 'package:kernel/class_hierarchy.dart'; import 'package:kernel/type_algebra.dart'; import 'package:kernel/type_environment.dart'; -import '../api_prototype/lowering_predicates.dart'; import '../base/constant_context.dart' show ConstantContext; import '../base/identifiers.dart'; import '../base/local_scope.dart'; @@ -33,27 +32,20 @@ import '../builder/member_builder.dart'; import '../builder/metadata_builder.dart'; import '../builder/omitted_type_builder.dart'; import '../builder/type_builder.dart'; +import '../fragment/constructor/declaration.dart'; import '../kernel/body_builder.dart' show BodyBuilder; import '../kernel/body_builder_context.dart'; -import '../kernel/constructor_tearoff_lowering.dart'; import '../kernel/expression_generator_helper.dart'; import '../kernel/hierarchy/class_member.dart' show ClassMember; import '../kernel/internal_ast.dart'; import '../kernel/kernel_helper.dart' - show - DelayedDefaultValueCloner, - TypeDependency, - finishConstructorAugmentation, - finishProcedureAugmentation; + show DelayedDefaultValueCloner, TypeDependency; import '../kernel/type_algorithms.dart'; import '../type_inference/inference_results.dart'; -import '../type_inference/type_schema.dart'; import 'constructor_declaration.dart'; import 'name_scheme.dart'; -import 'source_builder_mixins.dart'; import 'source_class_builder.dart'; import 'source_enum_builder.dart'; -import 'source_extension_type_declaration_builder.dart'; import 'source_function_builder.dart'; import 'source_library_builder.dart' show SourceLibraryBuilder; import 'source_loader.dart' @@ -85,56 +77,66 @@ abstract class SourceConstructorBuilder implements ConstructorBuilder { Uri get fileUri; } -abstract class AbstractSourceConstructorBuilder extends SourceMemberBuilderImpl +class SourceConstructorBuilderImpl extends SourceMemberBuilderImpl implements SourceConstructorBuilder, SourceFunctionBuilder, Inferable, - ConstructorDeclaration, + ConstructorDeclarationBuilder, InferredTypeListener { - @override - final List? metadata; - final Modifiers modifiers; @override final String name; @override - final List? typeParameters; + final SourceLibraryBuilder libraryBuilder; @override - final List? formals; - - /// If this procedure is an extension instance member or extension type - /// instance member, [_thisVariable] holds the synthetically added `this` - /// parameter. - VariableDeclaration? _thisVariable; - - /// If this procedure is an extension instance member or extension type - /// instance member, [_thisTypeParameters] holds the type parameters copied - /// from the extension/extension type declaration. - List? _thisTypeParameters; + final DeclarationBuilder declarationBuilder; @override - final OmittedTypeBuilder returnType; + final int fileOffset; - final int charOpenParenOffset; - - bool _hasFormalsInferred = false; + @override + final Uri fileUri; Token? beginInitializers; - AbstractSourceConstructorBuilder( - this.metadata, - this.modifiers, - this.returnType, - this.name, - this.typeParameters, - this.formals, - this.charOpenParenOffset, - this.nativeMethodName, - this.beginInitializers) { + final ConstructorDeclaration _introductory; + + final MemberName _memberName; + + final List _delayedDefaultValueCloners = []; + + Set? _initializedFields; + + SourceConstructorBuilderImpl? actualOrigin; + + List? _augmentations; + + SourceConstructorBuilderImpl({ + required this.modifiers, + required this.name, + required this.libraryBuilder, + required this.declarationBuilder, + required this.fileOffset, + required this.fileUri, + this.nativeMethodName, + required Reference? constructorReference, + required Reference? tearOffReference, + required NameScheme nameScheme, + required this.beginInitializers, + required ConstructorDeclaration constructorDeclaration, + }) : _introductory = constructorDeclaration, + _memberName = nameScheme.getDeclaredName(name) { + _introductory.createNode( + name: name, + libraryBuilder: libraryBuilder, + nameScheme: nameScheme, + constructorReference: constructorReference, + tearOffReference: tearOffReference); + returnType.registerInferredTypeListener(this); if (formals != null) { for (FormalParameterBuilder formal in formals!) { @@ -145,6 +147,22 @@ abstract class AbstractSourceConstructorBuilder extends SourceMemberBuilderImpl } } + @override + Builder get parent => declarationBuilder; + + @override + List? get metadata => _introductory.metadata; + + @override + OmittedTypeBuilder get returnType => _introductory.returnType; + + @override + List? get typeParameters => + _introductory.typeParameters; + + @override + List? get formals => _introductory.formals; + @override // Coverage-ignore(suite): Not run. Iterable? get metadataForTesting => metadata; @@ -171,9 +189,119 @@ abstract class AbstractSourceConstructorBuilder extends SourceMemberBuilderImpl // Coverage-ignore(suite): Not run. bool get isAssignable => false; + @override + // Coverage-ignore(suite): Not run. + Name get memberName => _memberName.name; + /// Returns `true` if this member is augmented, either by being the origin /// of a augmented member or by not being the last among augmentations. - bool get isAugmented; + bool get isAugmented { + if (isAugmenting) { + return origin._augmentations!.last != this; + } else { + return _augmentations != null; + } + } + + @override + SourceConstructorBuilderImpl get origin => actualOrigin ?? this; + + // Coverage-ignore(suite): Not run. + List? get augmentationsForTesting => _augmentations; + + @override + void applyAugmentation(Builder augmentation) { + if (augmentation is SourceConstructorBuilderImpl) { + if (checkAugmentation( + augmentationLibraryBuilder: augmentation.libraryBuilder, + origin: this, + augmentation: augmentation)) { + augmentation.actualOrigin = this; + (_augmentations ??= []).add(augmentation); + } + } else { + // Coverage-ignore-block(suite): Not run. + reportAugmentationMismatch( + originLibraryBuilder: libraryBuilder, + origin: this, + augmentation: augmentation); + } + } + + @override + bool get isRedirecting => _introductory.isRedirecting; + + @override + VariableDeclaration? get thisVariable => _introductory.thisVariable; + + @override + List? get thisTypeParameters => + _introductory.thisTypeParameters; + + @override + Member get readTarget => _introductory.readTarget; + + @override + // Coverage-ignore(suite): Not run. + Reference get readTargetReference => _introductory.readTargetReference; + + @override + Member get invokeTarget => + isAugmenting ? origin.invokeTarget : _introductory.invokeTarget; + + @override + // Coverage-ignore(suite): Not run. + Reference get invokeTargetReference => isAugmenting + ? origin.invokeTargetReference + : _introductory.invokeTargetReference; + + @override + // Coverage-ignore(suite): Not run. + Member? get writeTarget => null; + + @override + // Coverage-ignore(suite): Not run. + Reference? get writeTargetReference => null; + + @override + // Coverage-ignore(suite): Not run. + Iterable get exportedMemberReferences => [invokeTargetReference]; + + // TODO(johnniwinther): Add annotations to tear-offs. + @override + Iterable get annotatables => [invokeTarget]; + + @override + FunctionNode get function => _introductory.function; + + @override + void becomeNative(SourceLoader loader) { + _introductory.becomeNative(); + for (Annotatable annotatable in annotatables) { + loader.addNativeAnnotation(annotatable, nativeMethodName!); + } + } + + late final Substitution _fieldTypeSubstitution = + _introductory.computeFieldTypeSubstitution(declarationBuilder); + + @override + DartType substituteFieldType(DartType fieldType) { + return _fieldTypeSubstitution.substituteType(fieldType); + } + + void registerFunctionBody(Statement value) { + _introductory.registerFunctionBody(value); + } + + void registerNoBodyConstructor() { + _introductory.registerNoBodyConstructor(); + } + + @override + VariableDeclaration? getTearOffParameter(int index) { + return _introductory.getTearOffParameter(index); + } LocalScope computeFormalParameterScope(LookupScope parent) { if (formals == null) return new FormalParameterScope(parent: parent); @@ -255,275 +383,38 @@ abstract class AbstractSourceConstructorBuilder extends SourceMemberBuilderImpl final String? nativeMethodName; - Statement? bodyInternal; - - void set body(Statement? newBody) { -// if (newBody != null) { -// if (isAbstract) { -// // TODO(danrubel): Is this check needed? -// return internalProblem(messageInternalProblemBodyOnAbstractMethod, -// newBody.fileOffset, fileUri); -// } -// } - bodyInternal = newBody; - // A forwarding semi-stub is a method that is abstract in the source code, - // but which needs to have a forwarding stub body in order to ensure that - // covariance checks occur. We don't want to replace the forwarding stub - // body with null. - TreeNode? parent = function.parent; - if (!(newBody == null && - // Coverage-ignore(suite): Not run. - parent is Procedure && - // Coverage-ignore(suite): Not run. - parent.isForwardingSemiStub)) { - function.body = newBody; - newBody?.parent = function; - } - } - @override // Coverage-ignore(suite): Not run. bool get isNative => nativeMethodName != null; - bool get supportsTypeParameters => true; - - void buildFunction() { - function.asyncMarker = AsyncMarker.Sync; - function.body = body; - body?.parent = function; - buildTypeParametersAndFormals( - libraryBuilder, function, typeParameters, formals, - classTypeParameters: null, - supportsTypeParameters: supportsTypeParameters); - if (!(isExtensionInstanceMember || isExtensionTypeInstanceMember) && - isSetter && - // Coverage-ignore(suite): Not run. - (formals?.length != 1 || formals![0].isOptionalPositional)) { - // Coverage-ignore-block(suite): Not run. - // Replace illegal parameters by single dummy parameter. - // Do this after building the parameters, since the diet listener - // assumes that parameters are built, even if illegal in number. - VariableDeclaration parameter = new VariableDeclarationImpl("#synthetic"); - function.positionalParameters.clear(); - function.positionalParameters.add(parameter); - parameter.parent = function; - function.namedParameters.clear(); - function.requiredParameterCount = 1; - } else if ((isExtensionInstanceMember || isExtensionTypeInstanceMember) && - isSetter && - // Coverage-ignore(suite): Not run. - (formals?.length != 2 || formals![1].isOptionalPositional)) { - // Coverage-ignore-block(suite): Not run. - // Replace illegal parameters by single dummy parameter (after #this). - // Do this after building the parameters, since the diet listener - // assumes that parameters are built, even if illegal in number. - VariableDeclaration thisParameter = function.positionalParameters[0]; - VariableDeclaration parameter = new VariableDeclarationImpl("#synthetic"); - function.positionalParameters.clear(); - function.positionalParameters.add(thisParameter); - function.positionalParameters.add(parameter); - parameter.parent = function; - function.namedParameters.clear(); - function.requiredParameterCount = 2; - } - if (returnType is! InferableTypeBuilder) { - // Coverage-ignore-block(suite): Not run. - function.returnType = - returnType.build(libraryBuilder, TypeUse.returnType); - } - if (isExtensionInstanceMember || isExtensionTypeInstanceMember) { - SourceDeclarationBuilderMixin declarationBuilder = - parent as SourceDeclarationBuilderMixin; - if (declarationBuilder.typeParameters != null) { - int count = declarationBuilder.typeParameters!.length; - _thisTypeParameters = new List.generate( - count, (int index) => function.typeParameters[index], - growable: false); - } - if (isExtensionTypeInstanceMember && isConstructor) { - SourceExtensionTypeDeclarationBuilder extensionTypeDeclarationBuilder = - parent as SourceExtensionTypeDeclarationBuilder; - List typeArguments; - if (_thisTypeParameters != null) { - typeArguments = [ - for (TypeParameter parameter in _thisTypeParameters!) - new TypeParameterType.withDefaultNullability(parameter) - ]; - } else { - typeArguments = []; - } - _thisVariable = new VariableDeclarationImpl(syntheticThisName, - isFinal: true, - type: new ExtensionType( - extensionTypeDeclarationBuilder.extensionTypeDeclaration, - Nullability.nonNullable, - typeArguments)) - ..fileOffset = fileOffset - ..isLowered = true; - } else { - // Coverage-ignore-block(suite): Not run. - _thisVariable = function.positionalParameters.first; - } - } - } - - @override - VariableDeclaration getFormalParameter(int index) { - return formals![index].variable!; - } - - @override - VariableDeclaration? get thisVariable { - assert( - _thisVariable != null || - !(isExtensionInstanceMember || isExtensionTypeInstanceMember), - "ProcedureBuilder.thisVariable has not been set."); - return _thisVariable; - } - - @override - List? get thisTypeParameters { - // Use [_thisVariable] as marker for whether this type parameters have - // been computed. - assert( - _thisVariable != null || - !(isExtensionInstanceMember || isExtensionTypeInstanceMember), - "ProcedureBuilder.thisTypeParameters has not been set."); - return _thisTypeParameters; - } - @override void onInferredType(DartType type) { function.returnType = type; } - bool hasBuiltOutlineExpressions = false; - - @override - void buildOutlineExpressions(ClassHierarchy classHierarchy, - List delayedDefaultValueCloners) { - if (!hasBuiltOutlineExpressions) { - formals?.infer(classHierarchy); - - DeclarationBuilder? classOrExtensionBuilder = - isClassMember || isExtensionMember || isExtensionTypeMember - ? parent as DeclarationBuilder - : null; - LookupScope parentScope = - classOrExtensionBuilder?.scope ?? // Coverage-ignore(suite): Not run. - libraryBuilder.scope; - for (Annotatable annotatable in annotatables) { - MetadataBuilder.buildAnnotations(annotatable, metadata, - createBodyBuilderContext(), libraryBuilder, fileUri, parentScope, - createFileUriExpression: isAugmented); - } - if (typeParameters != null) { - for (int i = 0; i < typeParameters!.length; i++) { - typeParameters![i].buildOutlineExpressions( - libraryBuilder, - createBodyBuilderContext(), - classHierarchy, - computeTypeParameterScope(parentScope)); - } - } - - 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, - buildDefaultValue: FormalParameterBuilder - .needsDefaultValuesBuiltAsOutlineExpressions(this)); - } - } - hasBuiltOutlineExpressions = true; - } - } - - @override - void becomeNative(SourceLoader loader) { - for (Annotatable annotatable in annotatables) { - loader.addNativeAnnotation(annotatable, nativeMethodName!); - } - } - - BodyBuilderContext createBodyBuilderContext(); - @override bool get isConstructor => true; - Statement? get body { - if (bodyInternal == null && !isExternal) { - bodyInternal = new EmptyStatement(); - } - return bodyInternal; - } + List get _initializers => _introductory.initializers; - @override - void inferTypes(ClassHierarchyBase hierarchy) { - inferFormalTypes(hierarchy); - } - - @override - void inferFormalTypes(ClassHierarchyBase hierarchy) { - if (_hasFormalsInferred) return; - if (formals != null) { - libraryBuilder.loader.withUriForCrashReporting(fileUri, fileOffset, () { - for (FormalParameterBuilder formal in formals!) { - if (formal.type is InferableTypeBuilder) { - if (formal.isInitializingFormal) { - formal.finalizeInitializingFormal( - declarationBuilder, this, hierarchy); - } - } - } - _inferSuperInitializingFormals(hierarchy); - }); - } - _hasFormalsInferred = true; - } - - // Coverage-ignore(suite): Not run. - void _inferSuperInitializingFormals(ClassHierarchyBase hierarchy) {} - - void _buildFormals(Member member) { - if (formals != null) { - bool needsInference = false; - for (FormalParameterBuilder formal in formals!) { - if (formal.type is InferableTypeBuilder && - (formal.isInitializingFormal || formal.isSuperInitializingFormal)) { - formal.variable!.type = const UnknownType(); - needsInference = true; - } else if (!formal.hasDeclaredInitializer && - formal.isSuperInitializingFormal) { - needsInference = true; - } - } - if (needsInference) { - libraryBuilder.loader.registerConstructorToBeInferred(member, this); - } - } - } - - List get initializers; - - void _injectInvalidInitializer(Message message, int charOffset, int length, - ExpressionGeneratorHelper helper, TreeNode parent) { - Initializer lastInitializer = initializers.removeLast(); - assert(lastInitializer == superInitializer || - lastInitializer == redirectingInitializer); - Initializer error = helper.buildInvalidInitializer( - helper.buildProblem(message, charOffset, length)); - initializers.add(error..parent = parent); - initializers.add(lastInitializer); - } + List get initializers => + isAugmenting ? origin.initializers : _initializers; SuperInitializer? superInitializer; RedirectingInitializer? redirectingInitializer; + void _injectInvalidInitializer(Message message, int charOffset, int length, + ExpressionGeneratorHelper helper, TreeNode parent) { + Initializer lastInitializer = _introductory.initializers.removeLast(); + assert(lastInitializer == superInitializer || + lastInitializer == redirectingInitializer); + Initializer error = helper.buildInvalidInitializer( + helper.buildProblem(message, charOffset, length)); + _initializers.add(error..parent = parent); + _initializers.add(lastInitializer); + } + @override void addInitializer(Initializer initializer, ExpressionGeneratorHelper helper, {required InitializerInferenceResult? inferenceResult, @@ -540,7 +431,7 @@ abstract class AbstractSourceConstructorBuilder extends SourceMemberBuilderImpl helper, parent); } else { - inferenceResult?.applyResult(initializers, parent); + inferenceResult?.applyResult(_initializers, parent); superInitializer = initializer; LocatedMessage? message = helper.checkArgumentsForFunction( @@ -548,7 +439,7 @@ abstract class AbstractSourceConstructorBuilder extends SourceMemberBuilderImpl initializer.arguments, initializer.arguments.fileOffset, []); if (message != null) { - initializers.add(helper.buildInvalidInitializer( + _initializers.add(helper.buildInvalidInitializer( helper.buildUnresolvedError( helper.constructorNameForDiagnostics( initializer.target.name.text), @@ -559,7 +450,7 @@ abstract class AbstractSourceConstructorBuilder extends SourceMemberBuilderImpl kind: UnresolvedKind.Constructor)) ..parent = parent); } else { - initializers.add(initializer..parent = parent); + _initializers.add(initializer..parent = parent); } } } else if (initializer is RedirectingInitializer) { @@ -578,10 +469,10 @@ abstract class AbstractSourceConstructorBuilder extends SourceMemberBuilderImpl noLength, helper, parent); - } else if (initializers.isNotEmpty) { + } else if (_initializers.isNotEmpty) { // Error on all previous ones. - for (int i = 0; i < initializers.length; i++) { - Initializer initializer = initializers[i]; + for (int i = 0; i < _initializers.length; i++) { + Initializer initializer = _initializers[i]; int length = noLength; if (initializer is AssertInitializer) length = "assert".length; Initializer error = helper.buildInvalidInitializer( @@ -590,13 +481,13 @@ abstract class AbstractSourceConstructorBuilder extends SourceMemberBuilderImpl initializer.fileOffset, length)); error.parent = parent; - initializers[i] = error; + _initializers[i] = error; } - inferenceResult?.applyResult(initializers, parent); - initializers.add(initializer..parent = parent); + inferenceResult?.applyResult(_initializers, parent); + _initializers.add(initializer..parent = parent); redirectingInitializer = initializer; } else { - inferenceResult?.applyResult(initializers, parent); + inferenceResult?.applyResult(_initializers, parent); redirectingInitializer = initializer; LocatedMessage? message = helper.checkArgumentsForFunction( @@ -604,7 +495,7 @@ abstract class AbstractSourceConstructorBuilder extends SourceMemberBuilderImpl initializer.arguments, initializer.arguments.fileOffset, const []); if (message != null) { - initializers.add(helper.buildInvalidInitializer( + _initializers.add(helper.buildInvalidInitializer( helper.buildUnresolvedError( helper.constructorNameForDiagnostics( initializer.target.name.text), @@ -615,7 +506,7 @@ abstract class AbstractSourceConstructorBuilder extends SourceMemberBuilderImpl kind: UnresolvedKind.Constructor)) ..parent = parent); } else { - initializers.add(initializer..parent = parent); + _initializers.add(initializer..parent = parent); } } } else if (redirectingInitializer != null) { @@ -631,8 +522,8 @@ abstract class AbstractSourceConstructorBuilder extends SourceMemberBuilderImpl _injectInvalidInitializer(messageSuperInitializerNotLast, initializer.fileOffset, noLength, helper, parent); } else { - inferenceResult?.applyResult(initializers, parent); - initializers.add(initializer..parent = parent); + inferenceResult?.applyResult(_initializers, parent); + _initializers.add(initializer..parent = parent); } } @@ -662,24 +553,6 @@ abstract class AbstractSourceConstructorBuilder extends SourceMemberBuilderImpl } } - Procedure? get _constructorTearOff; - - @override - VariableDeclaration? getTearOffParameter(int index) { - Procedure? constructorTearOff = _constructorTearOff; - if (constructorTearOff != null) { - if (index < constructorTearOff.function.positionalParameters.length) { - return constructorTearOff.function.positionalParameters[index]; - } else { - index -= constructorTearOff.function.positionalParameters.length; - if (index < constructorTearOff.function.namedParameters.length) { - return constructorTearOff.function.namedParameters[index]; - } - } - } - return null; - } - @override int computeDefaultTypes(ComputeDefaultTypeContext context, {required bool inErrorRecovery}) { @@ -701,6 +574,12 @@ abstract class AbstractSourceConstructorBuilder extends SourceMemberBuilderImpl TypeEnvironment typeEnvironment) { library.checkInitializersInFormals(formals, typeEnvironment, isAbstract: isAbstract, isExternal: isExternal); + List? augmentations = _augmentations; + if (augmentations != null) { + for (SourceConstructorBuilderImpl augmentation in augmentations) { + augmentation.checkTypes(library, nameSpace, typeEnvironment); + } + } } @override @@ -745,27 +624,121 @@ abstract class AbstractSourceConstructorBuilder extends SourceMemberBuilderImpl @override // Coverage-ignore(suite): Not run. bool get isEnumElement => false; -} - -class DeclaredSourceConstructorBuilder - extends AbstractSourceConstructorBuilder { - late final Constructor _constructor; @override - late final Procedure? _constructorTearOff; - - Set? _initializedFields; - - DeclaredSourceConstructorBuilder? actualOrigin; - - List? _augmentations; - - bool _hasDefaultValueCloner = false; + void buildOutlineNodes(BuildNodesCallback f) { + _introductory.buildOutlineNodes(f, + constructorBuilder: this, + libraryBuilder: libraryBuilder, + declarationConstructor: invokeTarget, + delayedDefaultValueCloners: _delayedDefaultValueCloners); + } @override - List? formals; + int buildBodyNodes(BuildNodesCallback f) { + _introductory.buildBody(); + if (!isAugmenting) return 0; + _introductory.finishAugmentation(origin); + return 1; + } - final MemberName _memberName; + @override + void registerInitializedField(SourcePropertyBuilder fieldBuilder) { + if (isAugmenting) { + origin.registerInitializedField(fieldBuilder); + } else { + (_initializedFields ??= {}).add(fieldBuilder); + } + } + + @override + Set? takeInitializedFields() { + Set? result = _initializedFields; + _initializedFields = null; + return result; + } + + @override + void prepareInitializers() { + _introductory.prepareInitializers(); + redirectingInitializer = null; + superInitializer = null; + } + + @override + void prependInitializer(Initializer initializer) { + if (isAugmentation) { + // Coverage-ignore-block(suite): Not run. + origin.prependInitializer(initializer); + } else { + _introductory.prependInitializer(initializer); + } + } + + bool _hasBuiltOutlines = false; + bool hasBuiltOutlineExpressions = false; + + @override + void buildOutlineExpressions(ClassHierarchy classHierarchy, + List delayedDefaultValueCloners) { + if (_hasBuiltOutlines) return; + + if (isConst && isAugmenting) { + origin.buildOutlineExpressions( + classHierarchy, delayedDefaultValueCloners); + } + if (!hasBuiltOutlineExpressions) { + formals?.infer(classHierarchy); + + LookupScope parentScope = declarationBuilder.scope; + for (Annotatable annotatable in annotatables) { + MetadataBuilder.buildAnnotations(annotatable, metadata, + createBodyBuilderContext(), libraryBuilder, fileUri, parentScope, + createFileUriExpression: isAugmented); + } + if (typeParameters != null) { + for (int i = 0; i < typeParameters!.length; i++) { + typeParameters![i].buildOutlineExpressions( + libraryBuilder, + createBodyBuilderContext(), + classHierarchy, + computeTypeParameterScope(parentScope)); + } + } + + 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, + buildDefaultValue: FormalParameterBuilder + .needsDefaultValuesBuiltAsOutlineExpressions(this)); + } + } + hasBuiltOutlineExpressions = true; + } + if (isConst || _introductory.hasSuperInitializingFormals) { + // For modular compilation purposes we need to include initializers + // for const constructors into the outline. + LookupScope typeParameterScope = + computeTypeParameterScope(declarationBuilder.scope); + _buildConstructorForOutline(beginInitializers, typeParameterScope); + _introductory.buildBody(); + } + + addSuperParameterDefaultValueCloners(delayedDefaultValueCloners); + delayedDefaultValueCloners.addAll(_delayedDefaultValueCloners); + _delayedDefaultValueCloners.clear(); + + if (isConst && isAugmenting) { + _introductory.finishAugmentation(origin); + } + + beginInitializers = null; + _hasBuiltOutlines = true; + } @override String get fullNameForErrors { @@ -773,121 +746,6 @@ class DeclaredSourceConstructorBuilder "${name.isEmpty ? '' : '.$name'}"; } - @override - final int fileOffset; - - @override - final Uri fileUri; - - @override - final SourceLibraryBuilder libraryBuilder; - - @override - final DeclarationBuilder declarationBuilder; - - DeclaredSourceConstructorBuilder( - {required List? metadata, - required Modifiers modifiers, - required OmittedTypeBuilder returnType, - required String name, - required List? typeParameters, - required this.formals, - required this.libraryBuilder, - required this.declarationBuilder, - required this.fileUri, - required int startOffset, - required this.fileOffset, - required int formalsOffset, - required int endOffset, - required Reference? constructorReference, - required Reference? tearOffReference, - required NameScheme nameScheme, - String? nativeMethodName, - required bool forAbstractClassOrEnumOrMixin, - required Token? beginInitializers, - bool isSynthetic = false}) - : _hasSuperInitializingFormals = - formals?.any((formal) => formal.isSuperInitializingFormal) ?? false, - _memberName = nameScheme.getDeclaredName(name), - super(metadata, modifiers, returnType, name, typeParameters, formals, - formalsOffset, nativeMethodName, beginInitializers) { - _constructor = new Constructor(new FunctionNode(null), - name: dummyName, - fileUri: fileUri, - reference: constructorReference, - isSynthetic: isSynthetic) - ..startFileOffset = startOffset - ..fileOffset = fileOffset - ..fileEndOffset = endOffset; - nameScheme - .getConstructorMemberName(name, isTearOff: false) - .attachMember(_constructor); - _constructorTearOff = createConstructorTearOffProcedure( - nameScheme.getConstructorMemberName(name, isTearOff: true), - libraryBuilder, - fileUri, - fileOffset, - tearOffReference, - forAbstractClassOrEnumOrMixin: forAbstractClassOrEnumOrMixin); - } - - @override - Builder get parent => declarationBuilder; - - @override - bool get supportsTypeParameters => false; - - @override - // Coverage-ignore(suite): Not run. - Name get memberName => _memberName.name; - - @override - SourceClassBuilder get classBuilder => - super.classBuilder as SourceClassBuilder; - - @override - Member get readTarget => - _constructorTearOff ?? - // The case is need to ensure that the upper bound is [Member] and not - // [GenericFunction]. - _constructor as Member; - - @override - // Coverage-ignore(suite): Not run. - Reference get readTargetReference => - (_constructorTearOff ?? _constructor).reference; - - @override - // Coverage-ignore(suite): Not run. - Member? get writeTarget => null; - - @override - // Coverage-ignore(suite): Not run. - Reference? get writeTargetReference => null; - - @override - Member get invokeTarget => constructor; - - @override - // Coverage-ignore(suite): Not run. - Reference get invokeTargetReference => constructor.reference; - - @override - FunctionNode get function => _constructor.function; - - @override - // Coverage-ignore(suite): Not run. - Iterable get exportedMemberReferences => [constructor.reference]; - - @override - List get initializers => _constructor.initializers; - - @override - DeclaredSourceConstructorBuilder get origin => actualOrigin ?? this; - - // Coverage-ignore(suite): Not run. - List? get augmentationsForTesting => _augmentations; - @override bool get isDeclarationInstanceMember => false; @@ -909,16 +767,6 @@ class DeclaredSourceConstructorBuilder return isExternal; } - @override - bool get isRedirecting { - for (Initializer initializer in initializers) { - if (initializer is RedirectingInitializer) { - return true; - } - } - return false; - } - @override bool get isEffectivelyRedirecting { bool isRedirecting = this.isRedirecting; @@ -933,54 +781,22 @@ class DeclaredSourceConstructorBuilder return isRedirecting; } - @override - void buildOutlineNodes(BuildNodesCallback f) { - _build(); - f( - member: _constructor, - tearOff: _constructorTearOff, - kind: BuiltMemberKind.Constructor); - } - - bool _hasBeenBuilt = false; - - void _build() { - if (!_hasBeenBuilt) { - buildFunction(); - _constructor.function.fileOffset = charOpenParenOffset; - _constructor.function.fileEndOffset = _constructor.fileEndOffset; - _constructor.function.typeParameters = const []; - _constructor.isConst = isConst; - _constructor.isExternal = isExternal; - - if (_constructorTearOff != null) { - DelayedDefaultValueCloner delayedDefaultValueCloners = - buildConstructorTearOffProcedure( - tearOff: _constructorTearOff, - declarationConstructor: constructor, - implementationConstructor: _constructor, - enclosingDeclarationTypeParameters: - classBuilder.cls.typeParameters, - libraryBuilder: libraryBuilder); - _delayedDefaultValueCloners.add(delayedDefaultValueCloners); - } - - _hasBeenBuilt = true; - } - _buildFormals(_constructor); - } - @override VariableDeclaration getFormalParameter(int index) { - if (parent is SourceEnumBuilder) { + if (declarationBuilder is SourceEnumBuilder) { return formals![index + 2].variable!; } else { - return super.getFormalParameter(index); + return formals![index].variable!; } } ConstructorBuilder? _computeSuperTargetBuilder( List? initializers) { + if (declarationBuilder is! SourceClassBuilder) { + return null; + } + SourceClassBuilder classBuilder = declarationBuilder as SourceClassBuilder; + Member superTarget; ClassBuilder superclassBuilder; @@ -1031,14 +847,34 @@ class DeclaredSourceConstructorBuilder } } - final bool _hasSuperInitializingFormals; + @override + void inferTypes(ClassHierarchyBase hierarchy) { + inferFormalTypes(hierarchy); + } - final List _delayedDefaultValueCloners = - []; + bool _hasFormalsInferred = false; @override + void inferFormalTypes(ClassHierarchyBase hierarchy) { + if (_hasFormalsInferred) return; + if (formals != null) { + libraryBuilder.loader.withUriForCrashReporting(fileUri, fileOffset, () { + for (FormalParameterBuilder formal in formals!) { + if (formal.type is InferableTypeBuilder) { + if (formal.isInitializingFormal) { + formal.finalizeInitializingFormal( + declarationBuilder, this, hierarchy); + } + } + } + _inferSuperInitializingFormals(hierarchy); + }); + } + _hasFormalsInferred = true; + } + void _inferSuperInitializingFormals(ClassHierarchyBase hierarchy) { - if (_hasSuperInitializingFormals) { + if (_introductory.hasSuperInitializingFormals) { List? initializers; if (beginInitializers != null) { BodyBuilder bodyBuilder = libraryBuilder.loader @@ -1050,17 +886,17 @@ class DeclaredSourceConstructorBuilder initializers = bodyBuilder.parseInitializers(beginInitializers!, doFinishConstructor: false); } - finalizeSuperInitializingFormals( + _finalizeSuperInitializingFormals( hierarchy, _delayedDefaultValueCloners, initializers); } } - void finalizeSuperInitializingFormals( + void _finalizeSuperInitializingFormals( ClassHierarchyBase hierarchy, List delayedDefaultValueCloners, List? initializers) { if (formals == null) return; - if (!_hasSuperInitializingFormals) return; + if (!_introductory.hasSuperInitializingFormals) return; void performRecoveryForErroneousCase() { for (FormalParameterBuilder formal in formals!) { @@ -1116,7 +952,7 @@ class DeclaredSourceConstructorBuilder List? namedSuperParameters; Supertype? supertype = hierarchy.getClassAsInstanceOf( - classBuilder.cls, superTarget.enclosingClass!); + classBuilder!.cls, superTarget.enclosingClass!); assert(supertype != null); Map substitution = new Map.fromIterables( @@ -1186,68 +1022,24 @@ class DeclaredSourceConstructorBuilder } if (positionalSuperParameters != null || namedSuperParameters != null) { - if (!_hasDefaultValueCloner) { - // If this constructor formals are part of a cyclic dependency this - // might be called more than once. - delayedDefaultValueCloners.add(new DelayedDefaultValueCloner( - superTarget, constructor, - positionalSuperParameters: - positionalSuperParameters ?? const [], - namedSuperParameters: namedSuperParameters ?? const [], - isOutlineNode: true, - libraryBuilder: libraryBuilder)); - if (_constructorTearOff != null) { - delayedDefaultValueCloners.add(new DelayedDefaultValueCloner( - superTarget, _constructorTearOff, - positionalSuperParameters: - positionalSuperParameters ?? const [], - namedSuperParameters: namedSuperParameters ?? const [], - isOutlineNode: true, - libraryBuilder: libraryBuilder)); - } - _hasDefaultValueCloner = true; - } + _introductory.addSuperParameterDefaultValueCloners( + libraryBuilder: libraryBuilder, + delayedDefaultValueCloners: delayedDefaultValueCloners, + superTarget: superTarget, + positionalSuperParameters: positionalSuperParameters, + namedSuperParameters: namedSuperParameters); } } - bool _hasBuiltOutlines = false; - - @override - void buildOutlineExpressions(ClassHierarchy classHierarchy, - List delayedDefaultValueCloners) { - if (_hasBuiltOutlines) return; - - formals?.infer(classHierarchy); - - if (isConst && isAugmenting) { - origin.buildOutlineExpressions( - classHierarchy, delayedDefaultValueCloners); - } - super.buildOutlineExpressions(classHierarchy, delayedDefaultValueCloners); - - // For modular compilation purposes we need to include initializers - // for const constructors into the outline. We also need to parse - // initializers to infer types of the super-initializing parameters. - if (isConst || _hasSuperInitializingFormals) { - _buildConstructorForOutline(beginInitializers, classBuilder.scope); - } - addSuperParameterDefaultValueCloners(delayedDefaultValueCloners); - if (isConst && isAugmenting) { - _finishAugmentation(); - } - beginInitializers = null; - _hasBuiltOutlines = true; - } - @override void addSuperParameterDefaultValueCloners( List delayedDefaultValueCloners) { - if (beginInitializers != null && constructor.initializers.isNotEmpty) { + if (beginInitializers != null && initializers.isNotEmpty) { // If the initializers aren't built yet, we can't compute the super // target. The synthetic initializers should be excluded, since they can // be built separately from formal field initializers. bool allInitializersAreSynthetic = true; - for (Initializer initializer in constructor.initializers) { + for (Initializer initializer in initializers) { if (!initializer.isSynthetic) { allInitializersAreSynthetic = false; break; @@ -1255,160 +1047,17 @@ class DeclaredSourceConstructorBuilder } if (!allInitializersAreSynthetic) { ConstructorBuilder? superTargetBuilder = - _computeSuperTargetBuilder(constructor.initializers); + _computeSuperTargetBuilder(initializers); if (superTargetBuilder is SourceConstructorBuilder) { superTargetBuilder .addSuperParameterDefaultValueCloners(delayedDefaultValueCloners); } } } - - delayedDefaultValueCloners.addAll(_delayedDefaultValueCloners); - _delayedDefaultValueCloners.clear(); } - @override - void buildFunction() { - // According to the specification §9.3 the return type of a constructor - // function is its enclosing class. - super.buildFunction(); - Class enclosingClass = classBuilder.cls; - List typeParameterTypes = []; - for (int i = 0; i < enclosingClass.typeParameters.length; i++) { - TypeParameter typeParameter = enclosingClass.typeParameters[i]; - typeParameterTypes - .add(new TypeParameterType.withDefaultNullability(typeParameter)); - } - InterfaceType type = new InterfaceType( - enclosingClass, Nullability.nonNullable, typeParameterTypes); - returnType.registerInferredType(type); - } - - Constructor get constructor => - isAugmenting ? origin.constructor : _constructor; - - void _finishAugmentation() { - finishConstructorAugmentation(origin.constructor, _constructor); - - if (_constructorTearOff != null) { - finishProcedureAugmentation( - origin._constructorTearOff!, _constructorTearOff); - } - } - - @override - int buildBodyNodes(BuildNodesCallback f) { - if (!isAugmenting) return 0; - _finishAugmentation(); - return 1; - } - - @override - void becomeNative(SourceLoader loader) { - _constructor.isExternal = true; - super.becomeNative(loader); - } - - @override - void applyAugmentation(Builder augmentation) { - if (augmentation is DeclaredSourceConstructorBuilder) { - if (checkAugmentation( - augmentationLibraryBuilder: augmentation.libraryBuilder, - origin: this, - augmentation: augmentation)) { - augmentation.actualOrigin = this; - (_augmentations ??= []).add(augmentation); - } - } else { - // Coverage-ignore-block(suite): Not run. - reportAugmentationMismatch( - originLibraryBuilder: libraryBuilder, - origin: this, - augmentation: augmentation); - } - } - - @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 - // parsing, so we simply clear parsed initializers and rebuild them - // again. - // For when doing an experimental incremental compilation they are also - // potentially done more than once (because it rebuilds the bodies of an old - // 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. - _constructor.initializers = []; - redirectingInitializer = null; - superInitializer = null; - } - - @override - void prependInitializer(Initializer initializer) { - initializer.parent = constructor; - constructor.initializers.insert(0, initializer); - } - - @override - void registerInitializedField(SourcePropertyBuilder fieldBuilder) { - if (isAugmenting) { - origin.registerInitializedField(fieldBuilder); - } else { - (_initializedFields ??= {}).add(fieldBuilder); - } - } - - @override - Set? takeInitializedFields() { - Set? result = _initializedFields; - _initializedFields = null; - return result; - } - - void ensureGrowableFormals() { - if (formals != null) { - formals = new List.of(formals!, growable: true); - } else { - formals = []; - } - } - - @override - void checkTypes(SourceLibraryBuilder library, NameSpace nameSpace, - TypeEnvironment typeEnvironment) { - super.checkTypes(library, nameSpace, typeEnvironment); - List? augmentations = _augmentations; - if (augmentations != null) { - for (DeclaredSourceConstructorBuilder augmentation in augmentations) { - augmentation.checkTypes(library, nameSpace, typeEnvironment); - } - } - } - - @override - DartType substituteFieldType(DartType fieldType) { - // Nothing to do. Regular generative constructors don't have their own - // type parameters. - return fieldType; - } - - @override BodyBuilderContext createBodyBuilderContext() { - return new ConstructorBodyBuilderContext(this, constructor); - } - - // TODO(johnniwinther): Add annotations to tear-offs. - @override - Iterable get annotatables => [constructor]; - - @override - bool get isAugmented { - if (isAugmenting) { - return origin._augmentations!.last != this; - } else { - return _augmentations != null; - } + return new ConstructorBodyBuilderContext(this, invokeTarget); } } @@ -1652,322 +1301,6 @@ class SyntheticSourceConstructorBuilder extends MemberBuilderImpl TypeEnvironment typeEnvironment) {} } -class SourceExtensionTypeConstructorBuilder - extends AbstractSourceConstructorBuilder { - @override - final SourceLibraryBuilder libraryBuilder; - - @override - final SourceExtensionTypeDeclarationBuilder declarationBuilder; - - late final Procedure _constructor; - - @override - late final Procedure? _constructorTearOff; - - Set? _initializedFields; - - @override - List initializers = []; - - final MemberName _memberName; - - DelayedDefaultValueCloner? _delayedDefaultValueCloner; - - @override - final int fileOffset; - - @override - final Uri fileUri; - - SourceExtensionTypeConstructorBuilder( - {required List? metadata, - required Modifiers modifiers, - required OmittedTypeBuilder returnType, - required String name, - required List? typeParameters, - required List? formals, - required this.libraryBuilder, - required this.declarationBuilder, - required this.fileUri, - required int startOffset, - required this.fileOffset, - required int formalsOffset, - required int endOffset, - required Reference? constructorReference, - required Reference? tearOffReference, - required NameScheme nameScheme, - String? nativeMethodName, - required bool forAbstractClassOrEnumOrMixin, - required Token? beginInitializers}) - : _memberName = nameScheme.getDeclaredName(name), - super(metadata, modifiers, returnType, name, typeParameters, formals, - formalsOffset, nativeMethodName, beginInitializers) { - _constructor = new Procedure( - dummyName, ProcedureKind.Method, new FunctionNode(null), - fileUri: fileUri, reference: constructorReference) - ..fileOffset = fileOffset - ..fileEndOffset = endOffset; - nameScheme - .getConstructorMemberName(name, isTearOff: false) - .attachMember(_constructor); - _constructorTearOff = createConstructorTearOffProcedure( - nameScheme.getConstructorMemberName(name, isTearOff: true), - libraryBuilder, - fileUri, - fileOffset, - tearOffReference, - forAbstractClassOrEnumOrMixin: forAbstractClassOrEnumOrMixin, - forceCreateLowering: true) - ?..isExtensionTypeMember = true; - } - - @override - Builder get parent => declarationBuilder; - - @override - // Coverage-ignore(suite): Not run. - Name get memberName => _memberName.name; - - @override - Member get readTarget => - _constructorTearOff ?? // Coverage-ignore(suite): Not run. - _constructor; - - @override - // Coverage-ignore(suite): Not run. - Reference get readTargetReference => - (_constructorTearOff ?? _constructor).reference; - - @override - // Coverage-ignore(suite): Not run. - Member? get writeTarget => null; - - @override - // Coverage-ignore(suite): Not run. - Reference? get writeTargetReference => null; - - @override - Member get invokeTarget => _constructor; - - @override - // Coverage-ignore(suite): Not run. - Reference get invokeTargetReference => _constructor.reference; - - @override - FunctionNode get function => _constructor.function; - - @override - // Coverage-ignore(suite): Not run. - Iterable get exportedMemberReferences => [_constructor.reference]; - - @override - // Coverage-ignore(suite): Not run. - void addSuperParameterDefaultValueCloners( - List delayedDefaultValueCloners) {} - - @override - void _inferSuperInitializingFormals(ClassHierarchyBase hierarchy) { - if (formals != null) { - for (FormalParameterBuilder formal in formals!) { - if (formal.isSuperInitializingFormal) { - TypeBuilder formalTypeBuilder = formal.type; - if (formalTypeBuilder is InferableTypeBuilder) { - formalTypeBuilder.registerType(const InvalidType()); - } - } - } - } - } - - @override - void buildOutlineExpressions(ClassHierarchy classHierarchy, - List delayedDefaultValueCloners) { - super.buildOutlineExpressions(classHierarchy, delayedDefaultValueCloners); - - if (isConst) { - // For modular compilation purposes we need to include initializers - // for const constructors into the outline. - LookupScope typeParameterScope = - computeTypeParameterScope(declarationBuilder.scope); - _buildConstructorForOutline(beginInitializers, typeParameterScope); - _buildBody(); - } - beginInitializers = null; - - if (_delayedDefaultValueCloner != null) { - delayedDefaultValueCloners.add(_delayedDefaultValueCloner!); - } - } - - bool _hasBuiltBody = false; - - void _buildBody() { - if (_hasBuiltBody) { - return; - } - if (!isExternal) { - VariableDeclaration thisVariable = this.thisVariable!; - List statements = [thisVariable]; - ExtensionTypeInitializerToStatementConverter visitor = - new ExtensionTypeInitializerToStatementConverter( - statements, thisVariable); - for (Initializer initializer in initializers) { - initializer.accept(visitor); - } - if (body != null && body is! EmptyStatement) { - statements.add(body!); - } - statements.add(new ReturnStatement(new VariableGet(thisVariable))); - body = new Block(statements); - } - _hasBuiltBody = true; - } - - @override - int buildBodyNodes(BuildNodesCallback f) { - _buildBody(); - // TODO(johnniwinther): Support augmentation. - return 0; - } - - @override - void buildOutlineNodes(BuildNodesCallback f) { - _build(); - f( - member: _constructor, - tearOff: _constructorTearOff, - kind: BuiltMemberKind.ExtensionTypeConstructor); - } - - bool _hasBeenBuilt = false; - - @override - void buildFunction() { - // According to the specification §9.3 the return type of a constructor - // function is its enclosing class. - super.buildFunction(); - ExtensionTypeDeclaration extensionTypeDeclaration = - declarationBuilder.extensionTypeDeclaration; - List typeParameterTypes = []; - for (int i = 0; i < function.typeParameters.length; i++) { - TypeParameter typeParameter = function.typeParameters[i]; - typeParameterTypes - .add(new TypeParameterType.withDefaultNullability(typeParameter)); - } - ExtensionType type = new ExtensionType( - extensionTypeDeclaration, Nullability.nonNullable, typeParameterTypes); - returnType.registerInferredType(type); - } - - void _build() { - if (!_hasBeenBuilt) { - buildFunction(); - _constructor.function.fileOffset = charOpenParenOffset; - _constructor.function.fileEndOffset = _constructor.fileEndOffset; - _constructor.isConst = isConst; - _constructor.isExternal = isExternal; - _constructor.isStatic = true; - _constructor.isExtensionTypeMember = true; - - if (_constructorTearOff != null) { - _delayedDefaultValueCloner = buildConstructorTearOffProcedure( - tearOff: _constructorTearOff, - declarationConstructor: _constructor, - implementationConstructor: _constructor, - libraryBuilder: libraryBuilder); - } - - _hasBeenBuilt = true; - } - _buildFormals(_constructor); - } - - @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 - // parsing, so we simply clear parsed initializers and rebuild them - // again. - // For when doing an experimental incremental compilation they are also - // potentially done more than once (because it rebuilds the bodies of an old - // 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 = []; - redirectingInitializer = null; - superInitializer = null; - } - - @override - void prependInitializer(Initializer initializer) { - initializers.insert(0, initializer); - } - - @override - void registerInitializedField(SourcePropertyBuilder fieldBuilder) { - (_initializedFields ??= {}).add(fieldBuilder); - } - - @override - Set? takeInitializedFields() { - Set? result = _initializedFields; - _initializedFields = null; - return result; - } - - @override - bool get isEffectivelyExternal => isExternal; - - @override - bool get isRedirecting { - for (Initializer initializer in initializers) { - if (initializer is ExtensionTypeRedirectingInitializer) { - return true; - } - } - return false; - } - - @override - bool get isEffectivelyRedirecting => isRedirecting; - - Substitution? _substitutionCache; - - Substitution get _substitution { - if (typeParameters != null) { - assert( - declarationBuilder.typeParameters!.length == typeParameters?.length); - _substitutionCache = Substitution.fromPairs( - declarationBuilder.extensionTypeDeclaration.typeParameters, - new List.generate( - declarationBuilder.typeParameters!.length, - (int index) => new TypeParameterType.withDefaultNullability( - function.typeParameters[index]))); - } else { - _substitutionCache = Substitution.empty; - } - return _substitutionCache!; - } - - @override - DartType substituteFieldType(DartType fieldType) { - return _substitution.substituteType(fieldType); - } - - @override - BodyBuilderContext createBodyBuilderContext() { - return new ExtensionTypeConstructorBodyBuilderContext(this, _constructor); - } - - // TODO(johnniwinther): Add annotations to tear-offs. - @override - Iterable get annotatables => [_constructor]; - - @override - bool get isAugmented => false; -} - class ExtensionTypeInitializerToStatementConverter implements InitializerVisitor { VariableDeclaration thisVariable; diff --git a/pkg/front_end/lib/src/source/source_enum_builder.dart b/pkg/front_end/lib/src/source/source_enum_builder.dart index daf4e304b29..ed2fe0e29d7 100644 --- a/pkg/front_end/lib/src/source/source_enum_builder.dart +++ b/pkg/front_end/lib/src/source/source_enum_builder.dart @@ -33,6 +33,7 @@ import '../codes/cfe_codes.dart' messageNoUnnamedConstructorInObject, noLength, templateEnumContainsRestrictedInstanceDeclaration; +import '../fragment/constructor/declaration.dart'; import '../fragment/fragment.dart'; import '../kernel/body_builder_context.dart'; import '../kernel/constructor_tearoff_lowering.dart'; @@ -58,17 +59,13 @@ class SourceEnumBuilder extends SourceClassBuilder { final TypeBuilder _underscoreEnumTypeBuilder; - late final NamedTypeBuilder intType; - - late final NamedTypeBuilder stringType; - late final NamedTypeBuilder objectType; late final NamedTypeBuilder listType; late final NamedTypeBuilder selfType; - DeclaredSourceConstructorBuilder? synthesizedDefaultConstructorBuilder; + SourceConstructorBuilderImpl? synthesizedDefaultConstructorBuilder; late final _EnumValuesFieldDeclaration _enumValuesFieldDeclaration; @@ -141,30 +138,6 @@ class SourceEnumBuilder extends SourceClassBuilder { super.buildScopes(coreLibrary); _createSynthesizedMembers(coreLibrary); - // Include duplicates to install the formals on all constructors to avoid a - // crash later. - Iterator iterator = - nameSpace.filteredConstructorNameIterator( - includeDuplicates: true, includeAugmentations: true); - while (iterator.moveNext()) { - MemberBuilder member = iterator.current; - if (member is DeclaredSourceConstructorBuilder) { - member.ensureGrowableFormals(); - - FormalParameterBuilder nameFormalParameterBuilder = - new FormalParameterBuilder(FormalParameterKind.requiredPositional, - Modifiers.empty, stringType, "#name", fileOffset, - fileUri: fileUri, hasImmediatelyDeclaredInitializer: false); - member.formals!.insert(0, nameFormalParameterBuilder); - - FormalParameterBuilder indexFormalParameterBuilder = - new FormalParameterBuilder(FormalParameterKind.requiredPositional, - Modifiers.empty, intType, "#index", fileOffset, - fileUri: fileUri, hasImmediatelyDeclaredInitializer: false); - member.formals!.insert(0, indexFormalParameterBuilder); - } - } - Iterator constructorIterator = nameSpace.filteredConstructorIterator( includeDuplicates: false, includeAugmentations: true); @@ -180,23 +153,6 @@ class SourceEnumBuilder extends SourceClassBuilder { void _createSynthesizedMembers(LibraryBuilder coreLibrary) { // TODO(ahe): These types shouldn't be looked up in scope, they come // directly from dart:core. - intType = new NamedTypeBuilderImpl( - const PredefinedTypeName("int"), const NullabilityBuilder.omitted(), - instanceTypeParameterAccess: - // If "int" resolves to an instance type parameter then that we - // would allowed (the types that we are adding are in instance - // context after all) but it would be unexpected and we would like - // an assertion failure, since "int" was meant to be `int` from - // `dart:core`. - // TODO(johnniwinther): Add a more robust way of creating named - // typed builders for dart:core types. This might be needed for the - // enhanced enums feature where enums can actually declare type - // variables. - InstanceTypeParameterAccessState.Unexpected); - stringType = new NamedTypeBuilderImpl( - const PredefinedTypeName("String"), const NullabilityBuilder.omitted(), - instanceTypeParameterAccess: - InstanceTypeParameterAccessState.Unexpected); objectType = new NamedTypeBuilderImpl( const PredefinedTypeName("Object"), const NullabilityBuilder.omitted(), instanceTypeParameterAccess: @@ -326,35 +282,55 @@ class SourceEnumBuilder extends SourceClassBuilder { } } if (needsSynthesizedDefaultConstructor) { - synthesizedDefaultConstructorBuilder = - new DeclaredSourceConstructorBuilder( - metadata: null, - modifiers: Modifiers.Const, + FormalParameterBuilder nameFormalParameterBuilder = + new FormalParameterBuilder( + FormalParameterKind.requiredPositional, + Modifiers.empty, + libraryBuilder.loader.target.stringType, + "#name", + fileOffset, + fileUri: fileUri, + hasImmediatelyDeclaredInitializer: false); + + FormalParameterBuilder indexFormalParameterBuilder = + new FormalParameterBuilder( + FormalParameterKind.requiredPositional, + Modifiers.empty, + libraryBuilder.loader.target.intType, + "#index", + fileOffset, + fileUri: fileUri, + hasImmediatelyDeclaredInitializer: false); + + ConstructorDeclaration constructorDeclaration = + new DefaultEnumConstructorDeclaration( returnType: libraryBuilder.loader.inferableTypes.addInferableType(), - name: "", - typeParameters: null, - formals: [], - libraryBuilder: libraryBuilder, - declarationBuilder: this, + formals: [ + indexFormalParameterBuilder, + nameFormalParameterBuilder + ], fileUri: fileUri, - startOffset: fileOffset, - fileOffset: fileOffset, - formalsOffset: fileOffset, - endOffset: endOffset, - constructorReference: constructorReference, - tearOffReference: tearOffReference, - nameScheme: new NameScheme( - isInstanceMember: false, - containerName: new ClassName(name), - containerType: ContainerType.Class, - libraryName: libraryName), - forAbstractClassOrEnumOrMixin: true, - isSynthetic: true, - // Trick the constructor to be built during the outline phase. - // TODO(johnniwinther): Avoid relying on [beginInitializers] to - // ensure building constructors creation during the outline phase. - beginInitializers: new Token.eof(-1)); + fileOffset: fileOffset); + synthesizedDefaultConstructorBuilder = new SourceConstructorBuilderImpl( + modifiers: Modifiers.Const, + name: "", + libraryBuilder: libraryBuilder, + declarationBuilder: this, + fileUri: fileUri, + fileOffset: fileOffset, + constructorReference: constructorReference, + tearOffReference: tearOffReference, + nameScheme: new NameScheme( + isInstanceMember: false, + containerName: new ClassName(name), + containerType: ContainerType.Class, + libraryName: libraryName), + // Trick the constructor to be built during the outline phase. + // TODO(johnniwinther): Avoid relying on [beginInitializers] to + // ensure building constructors creation during the outline phase. + beginInitializers: new Token.eof(-1), + constructorDeclaration: constructorDeclaration); synthesizedDefaultConstructorBuilder! .registerInitializedField(valuesBuilder); nameSpace.addConstructor("", synthesizedDefaultConstructorBuilder!); @@ -379,7 +355,9 @@ class SourceEnumBuilder extends SourceClassBuilder { isAbstract: false, reference: toStringReference, creator: new _EnumToStringCreator( - this, stringType, _underscoreEnumTypeBuilder)); + this, + libraryBuilder.loader.target.stringType, + _underscoreEnumTypeBuilder)); nameSpace.addLocalMember(toStringBuilder.name, toStringBuilder, setter: false); nameSpaceBuilder.checkTypeParameterConflict(libraryBuilder, @@ -410,9 +388,6 @@ class SourceEnumBuilder extends SourceClassBuilder { } } - intType.resolveIn(coreLibrary.scope, fileOffset, fileUri, libraryBuilder); - stringType.resolveIn( - coreLibrary.scope, fileOffset, fileUri, libraryBuilder); objectType.resolveIn( coreLibrary.scope, fileOffset, fileUri, libraryBuilder); listType.resolveIn(coreLibrary.scope, fileOffset, fileUri, libraryBuilder); @@ -429,7 +404,7 @@ class SourceEnumBuilder extends SourceClassBuilder { if (identical(this.supertypeBuilder, _underscoreEnumTypeBuilder)) { if (synthesizedDefaultConstructorBuilder != null) { Constructor constructor = - synthesizedDefaultConstructorBuilder!.constructor; + synthesizedDefaultConstructorBuilder!.invokeTarget as Constructor; ClassBuilder objectClass = objectType.declaration as ClassBuilder; ClassBuilder enumClass = _underscoreEnumTypeBuilder.declaration as ClassBuilder; diff --git a/pkg/front_end/lib/src/source/source_extension_type_declaration_builder.dart b/pkg/front_end/lib/src/source/source_extension_type_declaration_builder.dart index fedd3036e0e..830bc841a70 100644 --- a/pkg/front_end/lib/src/source/source_extension_type_declaration_builder.dart +++ b/pkg/front_end/lib/src/source/source_extension_type_declaration_builder.dart @@ -860,14 +860,14 @@ class SourceExtensionTypeDeclarationBuilder /// Looks up the constructor by [name] on the class built by this class /// builder. - SourceExtensionTypeConstructorBuilder? lookupConstructor(Name name) { + SourceConstructorBuilderImpl? lookupConstructor(Name name) { if (name.text == "new") { // Coverage-ignore-block(suite): Not run. name = new Name("", name.library); } Builder? builder = nameSpace.lookupConstructor(name.text); - if (builder is SourceExtensionTypeConstructorBuilder) { + if (builder is SourceConstructorBuilderImpl) { return builder; } return null; diff --git a/pkg/front_end/lib/src/source/source_factory_builder.dart b/pkg/front_end/lib/src/source/source_factory_builder.dart index b516aac52bf..cd560ecdf66 100644 --- a/pkg/front_end/lib/src/source/source_factory_builder.dart +++ b/pkg/front_end/lib/src/source/source_factory_builder.dart @@ -515,7 +515,7 @@ class FactoryBodyBuilderContext extends BodyBuilderContext { } @override - void setBody(Statement body) { + void registerFunctionBody(Statement body) { _member.setBody(body); } 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 ff69493e43f..941edfc0a40 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 @@ -2,6 +2,7 @@ // 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. +import 'package:_fe_analyzer_shared/src/parser/formal_parameter_kind.dart'; import 'package:kernel/ast.dart'; import 'package:kernel/reference_from_index.dart'; @@ -12,12 +13,14 @@ import '../base/problems.dart'; import '../base/scope.dart'; import '../builder/builder.dart'; import '../builder/declaration_builders.dart'; +import '../builder/formal_parameter_builder.dart'; import '../builder/function_builder.dart'; import '../builder/member_builder.dart'; import '../builder/named_type_builder.dart'; import '../builder/nullability_builder.dart'; import '../builder/prefix_builder.dart'; import '../builder/type_builder.dart'; +import '../fragment/constructor/declaration.dart'; import '../fragment/fragment.dart'; import 'builder_factory.dart'; import 'name_scheme.dart'; @@ -1583,11 +1586,32 @@ void _computeBuildersFromFragments(String name, List fragments, methodBuilder; } case ConstructorFragment(): - List? typeParameters = - fragment.typeParameters?.builders; + String name = fragment.name; + NameScheme nameScheme = new NameScheme( + isInstanceMember: false, + containerName: containerName, + containerType: containerType, + libraryName: indexedLibrary != null + ? new LibraryName(indexedLibrary.library.reference) + : enclosingLibraryBuilder.libraryName); + + Reference? constructorReference; + Reference? tearOffReference; + + if (indexedContainer != null) { + constructorReference = indexedContainer!.lookupConstructorReference( + nameScheme.getConstructorMemberName(name, isTearOff: false).name); + tearOffReference = indexedContainer!.lookupGetterReference( + nameScheme.getConstructorMemberName(name, isTearOff: true).name); + } + + SourceConstructorBuilderImpl constructorBuilder; switch (declarationBuilder!) { - case ExtensionBuilder(): case ExtensionTypeDeclarationBuilder(): + List? typeParameters = fragment + .typeParameters + // Coverage-ignore(suite): Not run. + ?.builders; NominalParameterCopy? nominalVariableCopy = NominalParameterCopy.copyTypeParameters( unboundNominalParameters, declarationBuilder.typeParameters, @@ -1603,74 +1627,109 @@ void _computeBuildersFromFragments(String name, List fragments, typeParameters = nominalVariableCopy.newParameterBuilders; } } + fragment.typeParameterNameSpace.addTypeParameters( + problemReporting, typeParameters, + ownerName: fragment.name, allowNameConflict: true); + ConstructorDeclaration constructorDeclaration = + new ExtensionTypeConstructorDeclaration(fragment, + typeParameters: typeParameters); + constructorBuilder = new SourceConstructorBuilderImpl( + modifiers: fragment.modifiers, + name: name, + libraryBuilder: enclosingLibraryBuilder, + declarationBuilder: + declarationBuilder as SourceExtensionTypeDeclarationBuilder, + fileUri: fragment.fileUri, + fileOffset: fragment.fullNameOffset, + constructorReference: constructorReference, + tearOffReference: tearOffReference, + nameScheme: nameScheme, + nativeMethodName: fragment.nativeMethodName, + beginInitializers: fragment.beginInitializers, + constructorDeclaration: constructorDeclaration); case ClassBuilder(): - } - fragment.typeParameterNameSpace.addTypeParameters( - problemReporting, typeParameters, - ownerName: fragment.name, allowNameConflict: true); - - String name = fragment.name; - NameScheme nameScheme = new NameScheme( - isInstanceMember: false, - containerName: containerName, - containerType: containerType, - libraryName: indexedLibrary != null - ? new LibraryName(indexedLibrary.library.reference) - : enclosingLibraryBuilder.libraryName); - - Reference? constructorReference; - Reference? tearOffReference; - - if (indexedContainer != null) { - constructorReference = indexedContainer!.lookupConstructorReference( - nameScheme.getConstructorMemberName(name, isTearOff: false).name); - tearOffReference = indexedContainer!.lookupGetterReference( - nameScheme.getConstructorMemberName(name, isTearOff: true).name); - } - - AbstractSourceConstructorBuilder constructorBuilder; - if (declarationBuilder is SourceExtensionTypeDeclarationBuilder) { - constructorBuilder = new SourceExtensionTypeConstructorBuilder( - metadata: fragment.metadata, - modifiers: fragment.modifiers, - returnType: fragment.returnType, - name: name, - typeParameters: typeParameters, - formals: fragment.formals, - libraryBuilder: enclosingLibraryBuilder, - declarationBuilder: declarationBuilder, - fileUri: fragment.fileUri, - startOffset: fragment.startOffset, - fileOffset: fragment.fullNameOffset, - formalsOffset: fragment.formalsOffset, - endOffset: fragment.endOffset, - constructorReference: constructorReference, - tearOffReference: tearOffReference, - nameScheme: nameScheme, - nativeMethodName: fragment.nativeMethodName, - forAbstractClassOrEnumOrMixin: fragment.forAbstractClassOrMixin, - beginInitializers: fragment.beginInitializers); - } else { - constructorBuilder = new DeclaredSourceConstructorBuilder( - metadata: fragment.metadata, - modifiers: fragment.modifiers, - returnType: fragment.returnType, - name: fragment.name, - typeParameters: typeParameters, - formals: fragment.formals, - libraryBuilder: enclosingLibraryBuilder, - declarationBuilder: declarationBuilder, - fileUri: fragment.fileUri, - startOffset: fragment.startOffset, - fileOffset: fragment.fullNameOffset, - formalsOffset: fragment.formalsOffset, - endOffset: fragment.endOffset, - constructorReference: constructorReference, - tearOffReference: tearOffReference, - nameScheme: nameScheme, - nativeMethodName: fragment.nativeMethodName, - forAbstractClassOrEnumOrMixin: fragment.forAbstractClassOrMixin, - beginInitializers: fragment.beginInitializers); + List? syntheticFormals; + if (declarationBuilder.isEnum) { + syntheticFormals = [ + new FormalParameterBuilder( + FormalParameterKind.requiredPositional, + Modifiers.empty, + loader.target.intType, + "#index", + fragment.fullNameOffset, + fileUri: fragment.fileUri, + hasImmediatelyDeclaredInitializer: false), + new FormalParameterBuilder( + FormalParameterKind.requiredPositional, + Modifiers.empty, + loader.target.stringType, + "#name", + fragment.fullNameOffset, + fileUri: fragment.fileUri, + hasImmediatelyDeclaredInitializer: false), + ]; + } + List? typeParameters = + fragment.typeParameters?.builders; + fragment.typeParameterNameSpace.addTypeParameters( + problemReporting, typeParameters, + ownerName: fragment.name, allowNameConflict: true); + ConstructorDeclaration constructorDeclaration = + new RegularConstructorDeclaration(fragment, + typeParameters: typeParameters, + syntheticFormals: syntheticFormals); + constructorBuilder = new SourceConstructorBuilderImpl( + modifiers: fragment.modifiers, + name: fragment.name, + libraryBuilder: enclosingLibraryBuilder, + declarationBuilder: declarationBuilder, + fileUri: fragment.fileUri, + fileOffset: fragment.fullNameOffset, + constructorReference: constructorReference, + tearOffReference: tearOffReference, + nameScheme: nameScheme, + nativeMethodName: fragment.nativeMethodName, + beginInitializers: fragment.beginInitializers, + constructorDeclaration: constructorDeclaration); + case ExtensionBuilder(): + List? typeParameters = fragment + .typeParameters + // Coverage-ignore(suite): Not run. + ?.builders; + NominalParameterCopy? nominalVariableCopy = + NominalParameterCopy.copyTypeParameters( + unboundNominalParameters, declarationBuilder.typeParameters, + kind: TypeParameterKind.extensionSynthesized, + instanceTypeParameterAccess: + InstanceTypeParameterAccessState.Allowed); + if (nominalVariableCopy != null) { + if (typeParameters != null) { + // Coverage-ignore-block(suite): Not run. + typeParameters = nominalVariableCopy.newParameterBuilders + ..addAll(typeParameters); + } else { + typeParameters = nominalVariableCopy.newParameterBuilders; + } + } + fragment.typeParameterNameSpace.addTypeParameters( + problemReporting, typeParameters, + ownerName: fragment.name, allowNameConflict: true); + ConstructorDeclaration constructorDeclaration = + new RegularConstructorDeclaration(fragment, + typeParameters: typeParameters, syntheticFormals: null); + constructorBuilder = new SourceConstructorBuilderImpl( + modifiers: fragment.modifiers, + name: fragment.name, + libraryBuilder: enclosingLibraryBuilder, + declarationBuilder: declarationBuilder, + fileUri: fragment.fileUri, + fileOffset: fragment.fullNameOffset, + constructorReference: constructorReference, + tearOffReference: tearOffReference, + nameScheme: nameScheme, + nativeMethodName: fragment.nativeMethodName, + beginInitializers: fragment.beginInitializers, + constructorDeclaration: constructorDeclaration); } fragment.builder = constructorBuilder; builders.add(new _AddBuilder(fragment.name, constructorBuilder, @@ -1685,19 +1744,6 @@ void _computeBuildersFromFragments(String name, List fragments, case PrimaryConstructorFragment(): String name = fragment.name; - NominalParameterCopy? nominalVariableCopy = - NominalParameterCopy.copyTypeParameters( - unboundNominalParameters, declarationBuilder!.typeParameters, - kind: TypeParameterKind.extensionSynthesized, - instanceTypeParameterAccess: - InstanceTypeParameterAccessState.Allowed); - - List? typeParameters = - nominalVariableCopy?.newParameterBuilders; - fragment.typeParameterNameSpace.addTypeParameters( - problemReporting, typeParameters, - ownerName: fragment.name, allowNameConflict: true); - NameScheme nameScheme = new NameScheme( isInstanceMember: false, containerName: containerName, @@ -1716,50 +1762,57 @@ void _computeBuildersFromFragments(String name, List fragments, nameScheme.getConstructorMemberName(name, isTearOff: true).name); } - AbstractSourceConstructorBuilder constructorBuilder; - if (declarationBuilder is SourceExtensionTypeDeclarationBuilder) { - constructorBuilder = new SourceExtensionTypeConstructorBuilder( - metadata: null, - modifiers: fragment.modifiers, - returnType: fragment.returnType, - name: name, - typeParameters: typeParameters, - formals: fragment.formals, - libraryBuilder: enclosingLibraryBuilder, - declarationBuilder: declarationBuilder, - fileUri: fragment.fileUri, - startOffset: fragment.startOffset, - fileOffset: fragment.fileOffset, - formalsOffset: fragment.formalsOffset, - // TODO(johnniwinther): Provide `endOffset`. - endOffset: fragment.formalsOffset, - constructorReference: constructorReference, - tearOffReference: tearOffReference, - nameScheme: nameScheme, - forAbstractClassOrEnumOrMixin: fragment.forAbstractClassOrMixin, - beginInitializers: fragment.beginInitializers); - } else { - // Coverage-ignore-block(suite): Not run. - constructorBuilder = new DeclaredSourceConstructorBuilder( - metadata: null, - modifiers: fragment.modifiers, - returnType: fragment.returnType, - name: fragment.name, - typeParameters: typeParameters, - formals: fragment.formals, - libraryBuilder: enclosingLibraryBuilder, - declarationBuilder: declarationBuilder, - fileUri: fragment.fileUri, - startOffset: fragment.startOffset, - fileOffset: fragment.fileOffset, - formalsOffset: fragment.formalsOffset, - // TODO(johnniwinther): Provide `endOffset`. - endOffset: fragment.formalsOffset, - constructorReference: constructorReference, - tearOffReference: tearOffReference, - nameScheme: nameScheme, - forAbstractClassOrEnumOrMixin: fragment.forAbstractClassOrMixin, - beginInitializers: fragment.beginInitializers); + SourceConstructorBuilderImpl constructorBuilder; + switch (declarationBuilder!) { + case ExtensionTypeDeclarationBuilder(): + NominalParameterCopy? nominalVariableCopy = + NominalParameterCopy.copyTypeParameters( + unboundNominalParameters, declarationBuilder.typeParameters, + kind: TypeParameterKind.extensionSynthesized, + instanceTypeParameterAccess: + InstanceTypeParameterAccessState.Allowed); + + List? typeParameters = + nominalVariableCopy?.newParameterBuilders; + fragment.typeParameterNameSpace.addTypeParameters( + problemReporting, typeParameters, + ownerName: fragment.name, allowNameConflict: true); + ConstructorDeclaration constructorDeclaration = + new ExtensionTypePrimaryConstructorDeclaration(fragment, + typeParameters: typeParameters); + constructorBuilder = new SourceConstructorBuilderImpl( + modifiers: fragment.modifiers, + name: name, + libraryBuilder: enclosingLibraryBuilder, + declarationBuilder: + declarationBuilder as SourceExtensionTypeDeclarationBuilder, + fileUri: fragment.fileUri, + fileOffset: fragment.fileOffset, + constructorReference: constructorReference, + tearOffReference: tearOffReference, + nameScheme: nameScheme, + beginInitializers: fragment.beginInitializers, + constructorDeclaration: constructorDeclaration); + // Coverage-ignore(suite): Not run. + case ClassBuilder(): + ConstructorDeclaration constructorDeclaration = + new PrimaryConstructorDeclaration(fragment); + constructorBuilder = new SourceConstructorBuilderImpl( + modifiers: fragment.modifiers, + name: fragment.name, + libraryBuilder: enclosingLibraryBuilder, + declarationBuilder: declarationBuilder, + fileUri: fragment.fileUri, + fileOffset: fragment.fileOffset, + constructorReference: constructorReference, + tearOffReference: tearOffReference, + nameScheme: nameScheme, + beginInitializers: fragment.beginInitializers, + constructorDeclaration: constructorDeclaration); + // Coverage-ignore(suite): Not run. + case ExtensionBuilder(): + throw new UnsupportedError( + 'Unexpected extension primary constructor $fragment'); } fragment.builder = constructorBuilder; builders.add(new _AddBuilder(fragment.name, constructorBuilder, diff --git a/pkg/front_end/lib/src/type_inference/inference_visitor.dart b/pkg/front_end/lib/src/type_inference/inference_visitor.dart index 8dfb41ecbf1..cd32bfa3ad5 100644 --- a/pkg/front_end/lib/src/type_inference/inference_visitor.dart +++ b/pkg/front_end/lib/src/type_inference/inference_visitor.dart @@ -151,7 +151,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase @override final TypeAnalyzerOptions options; - final ConstructorDeclaration? constructorDeclaration; + final ConstructorDeclarationBuilder? constructorDeclaration; @override late final SharedTypeAnalyzerErrors errors = new SharedTypeAnalyzerErrors( diff --git a/pkg/front_end/lib/src/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/type_inference/type_inferrer.dart index 426df7b8266..8730c11036d 100644 --- a/pkg/front_end/lib/src/type_inference/type_inferrer.dart +++ b/pkg/front_end/lib/src/type_inference/type_inferrer.dart @@ -52,8 +52,10 @@ abstract class TypeInferrer { DartType returnType, AsyncMarker asyncMarker, Statement body); /// Performs type inference on the given constructor initializer. - InitializerInferenceResult inferInitializer(InferenceHelper helper, - ConstructorDeclaration constructorDeclaration, Initializer initializer); + InitializerInferenceResult inferInitializer( + InferenceHelper helper, + ConstructorDeclarationBuilder constructorDeclaration, + Initializer initializer); /// Performs type inference on the given metadata annotations. void inferMetadata( @@ -141,7 +143,7 @@ class TypeInferrerImpl implements TypeInferrer { typeCacheLegacy: engine.typeCacheLegacy); InferenceVisitorBase _createInferenceVisitor(InferenceHelper helper, - [ConstructorDeclaration? constructorDeclaration]) { + [ConstructorDeclarationBuilder? constructorDeclaration]) { // For full (non-top level) inference, we need access to the // InferenceHelper so that we can perform error reporting. return new InferenceVisitorImpl( @@ -246,8 +248,10 @@ class TypeInferrerImpl implements TypeInferrer { } @override - InitializerInferenceResult inferInitializer(InferenceHelper helper, - ConstructorDeclaration constructorDeclaration, Initializer initializer) { + InitializerInferenceResult inferInitializer( + InferenceHelper helper, + ConstructorDeclarationBuilder constructorDeclaration, + Initializer initializer) { // Use polymorphic dispatch on [KernelInitializer] to perform whatever // kind of type inference is correct for this kind of initializer. // TODO(paulberry): experiment to see if dynamic dispatch would be better, @@ -349,8 +353,10 @@ class TypeInferrerImplBenchmarked implements TypeInferrer { } @override - InitializerInferenceResult inferInitializer(InferenceHelper helper, - ConstructorDeclaration constructorDeclaration, Initializer initializer) { + InitializerInferenceResult inferInitializer( + InferenceHelper helper, + ConstructorDeclarationBuilder constructorDeclaration, + Initializer initializer) { benchmarker.beginSubdivide(BenchmarkSubdivides.inferInitializer); InitializerInferenceResult result = impl.inferInitializer(helper, constructorDeclaration, initializer); diff --git a/pkg/front_end/test/coverage_suite_expected.dart b/pkg/front_end/test/coverage_suite_expected.dart index 438e04ed4a5..89d9b71ced7 100644 --- a/pkg/front_end/test/coverage_suite_expected.dart +++ b/pkg/front_end/test/coverage_suite_expected.dart @@ -479,6 +479,16 @@ const Map _expect = { missCount: 0, ), // 100.0%. + "package:front_end/src/fragment/constructor/declaration.dart": ( + hitCount: 248, + missCount: 0, + ), + // 100.0%. + "package:front_end/src/fragment/constructor/encoding.dart": ( + hitCount: 318, + missCount: 0, + ), + // 100.0%. "package:front_end/src/fragment/enum.dart": ( hitCount: 13, missCount: 0, @@ -580,12 +590,12 @@ const Map _expect = { ), // 100.0%. "package:front_end/src/kernel/body_builder.dart": ( - hitCount: 7181, + hitCount: 7180, missCount: 0, ), // 100.0%. "package:front_end/src/kernel/body_builder_context.dart": ( - hitCount: 303, + hitCount: 289, missCount: 0, ), // 100.0%. @@ -730,7 +740,7 @@ const Map _expect = { ), // 100.0%. "package:front_end/src/kernel/kernel_target.dart": ( - hitCount: 1068, + hitCount: 1051, missCount: 0, ), // 100.0%. @@ -860,12 +870,12 @@ const Map _expect = { ), // 100.0%. "package:front_end/src/source/source_constructor_builder.dart": ( - hitCount: 1084, + hitCount: 722, missCount: 0, ), // 100.0%. "package:front_end/src/source/source_enum_builder.dart": ( - hitCount: 420, + hitCount: 403, missCount: 0, ), // 100.0%. @@ -931,7 +941,7 @@ const Map _expect = { ), // 100.0%. "package:front_end/src/source/type_parameter_scope_builder.dart": ( - hitCount: 1395, + hitCount: 1408, missCount: 0, ), // 100.0%. diff --git a/pkg/front_end/test/patching/patching_test.dart b/pkg/front_end/test/patching/patching_test.dart index 4409fb24d2f..0271767e203 100644 --- a/pkg/front_end/test/patching/patching_test.dart +++ b/pkg/front_end/test/patching/patching_test.dart @@ -169,7 +169,7 @@ class PatchingDataExtractor extends CfeDataExtractor { if (memberBuilder is SourcePropertyBuilder) { patchMembers = memberBuilder.augmentationsForTesting; } - if (memberBuilder is DeclaredSourceConstructorBuilder) { + if (memberBuilder is SourceConstructorBuilderImpl) { patchMembers = memberBuilder.augmentationsForTesting; } if (memberBuilder is SourceFactoryBuilder) { diff --git a/pkg/front_end/testcases/extension_types/issue53212.dart.strong.outline.expect b/pkg/front_end/testcases/extension_types/issue53212.dart.strong.outline.expect index 75dd9c657f7..85d641853de 100644 --- a/pkg/front_end/testcases/extension_types/issue53212.dart.strong.outline.expect +++ b/pkg/front_end/testcases/extension_types/issue53212.dart.strong.outline.expect @@ -55,27 +55,35 @@ static extension-type-member method E1|constructor#(core::int foo) → self::E1% ; static extension-type-member method E1|constructor#_#new#tearOff(core::int foo) → self::E1% /* erasure=core::int, declared=! */ return self::E1|constructor#(foo); -static extension-type-member method E1|constructor#named(core::int foo, invalid-type bar) → self::E1% /* erasure=core::int, declared=! */ - ; +static extension-type-member method E1|constructor#named(core::int foo, invalid-type bar) → self::E1% /* erasure=core::int, declared=! */ { + lowered final self::E1% /* erasure=core::int, declared=! */ #this = foo; + return #this; +} static extension-type-member method E1|constructor#_#named#tearOff(core::int foo, invalid-type bar) → self::E1% /* erasure=core::int, declared=! */ return self::E1|constructor#named(foo, bar); static extension-type-member method E2|constructor#(core::int foo) → self::E2% /* erasure=core::int, declared=! */ ; static extension-type-member method E2|constructor#_#new#tearOff(core::int foo) → self::E2% /* erasure=core::int, declared=! */ return self::E2|constructor#(foo); -static extension-type-member method E2|constructor#named(core::int foo, {required invalid-type bar}) → self::E2% /* erasure=core::int, declared=! */ - ; +static extension-type-member method E2|constructor#named(core::int foo, {required invalid-type bar}) → self::E2% /* erasure=core::int, declared=! */ { + lowered final self::E2% /* erasure=core::int, declared=! */ #this = foo; + return #this; +} static extension-type-member method E2|constructor#_#named#tearOff(core::int foo, {required invalid-type bar}) → self::E2% /* erasure=core::int, declared=! */ return self::E2|constructor#named(foo, bar: bar); static extension-type-member method E3|constructor#(core::int foo) → self::E3% /* erasure=core::int, declared=! */ ; static extension-type-member method E3|constructor#_#new#tearOff(core::int foo) → self::E3% /* erasure=core::int, declared=! */ return self::E3|constructor#(foo); -static extension-type-member method E3|constructor#named(core::int foo, [has-declared-initializer invalid-type bar = null]) → self::E3% /* erasure=core::int, declared=! */ - ; +static extension-type-member method E3|constructor#named(core::int foo, [has-declared-initializer invalid-type bar = null]) → self::E3% /* erasure=core::int, declared=! */ { + lowered final self::E3% /* erasure=core::int, declared=! */ #this = foo; + return #this; +} static extension-type-member method E3|constructor#_#named#tearOff(core::int foo, [has-declared-initializer invalid-type bar]) → self::E3% /* erasure=core::int, declared=! */ return self::E3|constructor#named(foo, bar); -static extension-type-member method E4|constructor#(invalid-type foo) → self::E4% /* erasure=invalid-type, declared=! */ - ; +static extension-type-member method E4|constructor#(invalid-type foo) → self::E4% /* erasure=invalid-type, declared=! */ { + lowered final self::E4% /* erasure=invalid-type, declared=! */ #this = foo; + return #this; +} static extension-type-member method E4|constructor#_#new#tearOff(invalid-type foo) → self::E4% /* erasure=invalid-type, declared=! */ return self::E4|constructor#(foo); diff --git a/pkg/front_end/testcases/extension_types/issue53625.dart.strong.outline.expect b/pkg/front_end/testcases/extension_types/issue53625.dart.strong.outline.expect index f44f65ede25..6e001c1ae76 100644 --- a/pkg/front_end/testcases/extension_types/issue53625.dart.strong.outline.expect +++ b/pkg/front_end/testcases/extension_types/issue53625.dart.strong.outline.expect @@ -38,8 +38,10 @@ static extension-type-member method E07|constructor#(core::int x) → self::E07% ; static extension-type-member method E07|constructor#_#new#tearOff(core::int x) → self::E07% /* erasure=core::int, declared=! */ return self::E07|constructor#(x); -static extension-type-member method E08|constructor#(core::int x) → self::E08% /* erasure=core::int, declared=! */ - ; +static extension-type-member method E08|constructor#(core::int x) → self::E08% /* erasure=core::int, declared=! */ { + lowered final self::E08% /* erasure=core::int, declared=! */ #this = x; + return #this; +} static extension-type-member method E08|constructor#_#new#tearOff(core::int x) → self::E08% /* erasure=core::int, declared=! */ return self::E08|constructor#(x); static extension-type-member method E11|constructor#(() → core::int x) → self::E11% /* erasure=() → core::int, declared=! */