From 6b73869b96d88c32293c51b6e627a16abd94dc6e Mon Sep 17 00:00:00 2001 From: Johnni Winther Date: Fri, 9 Dec 2022 15:21:47 +0000 Subject: [PATCH] [cfe] Initial support for view constructors Change-Id: I646c8e00cb819b5759f5df2b602f49a570d7f959 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/274220 Reviewed-by: Jens Johansen Commit-Queue: Johnni Winther --- .../lib/src/fasta/builder/class_builder.dart | 10 +- .../fasta/builder/constructor_builder.dart | 9 +- .../fasta/builder/declaration_builder.dart | 15 +- .../src/fasta/builder/extension_builder.dart | 3 +- .../builder/formal_parameter_builder.dart | 5 +- .../lib/src/fasta/builder/view_builder.dart | 13 +- .../src/fasta/dill/dill_member_builder.dart | 3 +- .../lib/src/fasta/kernel/body_builder.dart | 45 +- .../kernel/constructor_tearoff_lowering.dart | 31 +- .../lib/src/fasta/kernel/kernel_target.dart | 11 +- .../lib/src/fasta/source/diet_listener.dart | 20 +- .../lib/src/fasta/source/name_scheme.dart | 54 +- .../fasta/source/source_builder_mixins.dart | 4 + .../fasta/source/source_class_builder.dart | 3 +- .../source/source_constructor_builder.dart | 765 +++++++++++------- .../src/fasta/source/source_enum_builder.dart | 9 +- .../source/source_extension_builder.dart | 1 + .../fasta/source/source_factory_builder.dart | 2 +- .../fasta/source/source_library_builder.dart | 230 +++--- .../lib/src/fasta/source/source_loader.dart | 4 +- .../fasta/source/source_member_builder.dart | 1 + .../src/fasta/source/source_view_builder.dart | 7 +- .../inference_visitor_base.dart | 16 +- .../type_inference/type_inference_engine.dart | 4 +- .../testcases/general/issue42435.dart | 1 + .../issue42435.dart.textual_outline.expect | 1 + ...42435.dart.textual_outline_modelled.expect | 1 + .../general/issue42435.dart.weak.expect | 10 + .../issue42435.dart.weak.modular.expect | 10 + .../issue42435.dart.weak.outline.expect | 10 + .../issue42435.dart.weak.transformed.expect | 10 + .../testcases/textual_outline.status | 1 + .../testcases/views/constructors.dart | 15 + .../views/constructors.dart.strong.expect | 14 + ...onstructors.dart.strong.transformed.expect | 14 + .../constructors.dart.textual_outline.expect | 10 + .../views/constructors.dart.weak.expect | 14 + .../constructors.dart.weak.modular.expect | 14 + .../constructors.dart.weak.outline.expect | 14 + .../constructors.dart.weak.transformed.expect | 14 + 40 files changed, 940 insertions(+), 478 deletions(-) create mode 100644 pkg/front_end/testcases/views/constructors.dart create mode 100644 pkg/front_end/testcases/views/constructors.dart.strong.expect create mode 100644 pkg/front_end/testcases/views/constructors.dart.strong.transformed.expect create mode 100644 pkg/front_end/testcases/views/constructors.dart.textual_outline.expect create mode 100644 pkg/front_end/testcases/views/constructors.dart.weak.expect create mode 100644 pkg/front_end/testcases/views/constructors.dart.weak.modular.expect create mode 100644 pkg/front_end/testcases/views/constructors.dart.weak.outline.expect create mode 100644 pkg/front_end/testcases/views/constructors.dart.weak.transformed.expect diff --git a/pkg/front_end/lib/src/fasta/builder/class_builder.dart b/pkg/front_end/lib/src/fasta/builder/class_builder.dart index 0727a215085..d5088862446 100644 --- a/pkg/front_end/lib/src/fasta/builder/class_builder.dart +++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart @@ -57,8 +57,6 @@ abstract class ClassBuilder implements DeclarationBuilder { /// The types in the `on` clause of an extension or mixin declaration. List? get onTypes; - ConstructorScope get constructorScope; - @override Uri get fileUri; @@ -170,9 +168,6 @@ abstract class ClassBuilderImpl extends DeclarationBuilderImpl @override List? onTypes; - @override - final ConstructorScope constructorScope; - @override bool isNullClass = false; @@ -190,10 +185,11 @@ abstract class ClassBuilderImpl extends DeclarationBuilderImpl this.interfaceBuilders, this.onTypes, Scope scope, - this.constructorScope, + ConstructorScope constructorScope, LibraryBuilder parent, int charOffset) - : super(metadata, modifiers, name, parent, charOffset, scope); + : super(metadata, modifiers, name, parent, charOffset, scope, + constructorScope); @override String get debugName => "ClassBuilder"; diff --git a/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart b/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart index 960410b10c7..97ee1e1380b 100644 --- a/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart +++ b/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart @@ -7,6 +7,11 @@ import 'package:kernel/ast.dart'; import 'function_builder.dart'; abstract class ConstructorBuilder implements FunctionBuilder { - /// The [Constructor] built by this builder. - Constructor get constructor; + /// The member target used for tearing of the constructor. + @override + Member get readTarget; + + /// The member target used for calling the constructor. + @override + Member get invokeTarget; } diff --git a/pkg/front_end/lib/src/fasta/builder/declaration_builder.dart b/pkg/front_end/lib/src/fasta/builder/declaration_builder.dart index a0d0db48381..8b46674e2f5 100644 --- a/pkg/front_end/lib/src/fasta/builder/declaration_builder.dart +++ b/pkg/front_end/lib/src/fasta/builder/declaration_builder.dart @@ -37,6 +37,8 @@ abstract class DeclarationBuilder implements TypeDeclarationBuilder { /// reported. Builder? lookupLocalMember(String name, {bool setter = false, bool required = false}); + + ConstructorScope get constructorScope; } abstract class DeclarationBuilderImpl extends TypeDeclarationBuilderImpl @@ -44,11 +46,20 @@ abstract class DeclarationBuilderImpl extends TypeDeclarationBuilderImpl @override final Scope scope; + @override + final ConstructorScope constructorScope; + @override final Uri fileUri; - DeclarationBuilderImpl(List? metadata, int modifiers, - String name, LibraryBuilder parent, int charOffset, this.scope) + DeclarationBuilderImpl( + List? metadata, + int modifiers, + String name, + LibraryBuilder parent, + int charOffset, + this.scope, + this.constructorScope) : fileUri = parent.fileUri, super(metadata, modifiers, name, parent, charOffset); diff --git a/pkg/front_end/lib/src/fasta/builder/extension_builder.dart b/pkg/front_end/lib/src/fasta/builder/extension_builder.dart index f45c31569d8..018090c6906 100644 --- a/pkg/front_end/lib/src/fasta/builder/extension_builder.dart +++ b/pkg/front_end/lib/src/fasta/builder/extension_builder.dart @@ -47,7 +47,8 @@ abstract class ExtensionBuilderImpl extends DeclarationBuilderImpl implements ExtensionBuilder { ExtensionBuilderImpl(List? metadata, int modifiers, String name, LibraryBuilder parent, int charOffset, Scope scope) - : super(metadata, modifiers, name, parent, charOffset, scope); + : super(metadata, modifiers, name, parent, charOffset, scope, + new ConstructorScope(name, const {})); @override DartType buildAliasedTypeWithBuiltArguments( diff --git a/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart b/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart index 0da39c0680d..1b8dba2f05c 100644 --- a/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart +++ b/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart @@ -23,6 +23,7 @@ import '../util/helpers.dart' show DelayedActionPerformer; import 'builder.dart'; import 'class_builder.dart'; import 'constructor_builder.dart'; +import 'declaration_builder.dart'; import 'library_builder.dart'; import 'metadata_builder.dart'; import 'modifier_builder.dart'; @@ -220,8 +221,8 @@ class FormalParameterBuilder extends ModifierBuilderImpl } void finalizeInitializingFormal( - ClassBuilder classBuilder, ClassHierarchyBase hierarchy) { - Builder? fieldBuilder = classBuilder.lookupLocalMember(name); + DeclarationBuilder declarationBuilder, ClassHierarchyBase hierarchy) { + Builder? fieldBuilder = declarationBuilder.lookupLocalMember(name); if (fieldBuilder is SourceFieldBuilder) { type.registerInferredType(fieldBuilder.inferType(hierarchy)); } else { diff --git a/pkg/front_end/lib/src/fasta/builder/view_builder.dart b/pkg/front_end/lib/src/fasta/builder/view_builder.dart index b20df5d440a..cca492e6caa 100644 --- a/pkg/front_end/lib/src/fasta/builder/view_builder.dart +++ b/pkg/front_end/lib/src/fasta/builder/view_builder.dart @@ -45,9 +45,16 @@ abstract class ViewBuilder implements DeclarationBuilder { abstract class ViewBuilderImpl extends DeclarationBuilderImpl with DeclarationBuilderMixin implements ViewBuilder { - ViewBuilderImpl(List? metadata, int modifiers, String name, - LibraryBuilder parent, int charOffset, Scope scope) - : super(metadata, modifiers, name, parent, charOffset, scope); + ViewBuilderImpl( + List? metadata, + int modifiers, + String name, + LibraryBuilder parent, + int charOffset, + Scope scope, + ConstructorScope constructorScope) + : super(metadata, modifiers, name, parent, charOffset, scope, + constructorScope); @override DartType buildAliasedTypeWithBuiltArguments( diff --git a/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart index a782700e51b..3bd517241ed 100644 --- a/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart +++ b/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart @@ -223,7 +223,6 @@ class DillFactoryBuilder extends DillProcedureBuilder { class DillConstructorBuilder extends DillMemberBuilder implements ConstructorBuilder { - @override final Constructor constructor; final Procedure? _constructorTearOff; @@ -238,7 +237,7 @@ class DillConstructorBuilder extends DillMemberBuilder Constructor get member => constructor; @override - Member? get readTarget => _constructorTearOff ?? constructor; + Member get readTarget => _constructorTearOff ?? constructor; @override Member? get writeTarget => null; diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart index c52be52c02b..0afad0ca586 100644 --- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart +++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart @@ -1290,7 +1290,7 @@ class BodyBuilder extends StackListenerImpl } } } - if (builder is DeclaredSourceConstructorBuilder) { + if (builder is AbstractSourceConstructorBuilder) { finishConstructor(builder, asyncModifier, body, superParametersAsArguments: superParametersAsArguments); } else if (builder is SourceProcedureBuilder) { @@ -1829,8 +1829,8 @@ class BodyBuilder extends StackListenerImpl handleNoInitializers(); } if (doFinishConstructor) { - DeclaredSourceConstructorBuilder constructorBuilder = - member as DeclaredSourceConstructorBuilder; + AbstractSourceConstructorBuilder constructorBuilder = + member as AbstractSourceConstructorBuilder; List? formals = constructorBuilder.formals; finishConstructor(constructorBuilder, AsyncMarker.Sync, null, superParametersAsArguments: formals != null @@ -1879,14 +1879,14 @@ class BodyBuilder extends StackListenerImpl return arguments; } - void finishConstructor(DeclaredSourceConstructorBuilder builder, + void finishConstructor(AbstractSourceConstructorBuilder builder, AsyncMarker asyncModifier, Statement? body, {required List? superParametersAsArguments}) { /// Quotes below are from [Dart Programming Language Specification, 4th /// Edition]( /// https://ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf). - assert(builder == member); + assert(builder == this.member); assert(() { if (superParametersAsArguments == null) { return true; @@ -1925,7 +1925,8 @@ class BodyBuilder extends StackListenerImpl "Expected 'superParametersAsArguments' " "to be sorted by occurrence in file."); - Constructor constructor = builder.actualConstructor; + Member member = builder.member; + FunctionNode function = builder.function; List? formals = builder.formals; if (formals != null) { for (int i = 0; i < formals.length; i++) { @@ -1983,11 +1984,11 @@ class BodyBuilder extends StackListenerImpl if (initializers.last is SuperInitializer) { SuperInitializer superInitializer = initializers.last as SuperInitializer; - if (builder.classBuilder.isEnum) { + if (builder.declarationBuilder.isEnum) { initializers[initializers.length - 1] = buildInvalidInitializer( buildProblem(fasta.messageEnumConstructorSuperInitializer, superInitializer.fileOffset, noLength)) - ..parent = constructor; + ..parent = member; } else if (libraryFeatures.superParameters.isEnabled) { ArgumentsImpl arguments = superInitializer.arguments as ArgumentsImpl; @@ -2029,10 +2030,10 @@ class BodyBuilder extends StackListenerImpl ArgumentsImpl arguments = redirectingInitializer.arguments as ArgumentsImpl; List enumSyntheticArguments = [ - new VariableGetImpl(constructor.function.positionalParameters[0], + new VariableGetImpl(function.positionalParameters[0], forNullGuardedAccess: false) ..parent = redirectingInitializer.arguments, - new VariableGetImpl(constructor.function.positionalParameters[1], + new VariableGetImpl(function.positionalParameters[1], forNullGuardedAccess: false) ..parent = redirectingInitializer.arguments ]; @@ -2057,8 +2058,9 @@ class BodyBuilder extends StackListenerImpl } } + List builtInitializers = builder.initializers; if (asyncModifier != AsyncMarker.Sync) { - constructor.initializers.add(buildInvalidInitializer(buildProblem( + builtInitializers.add(buildInvalidInitializer(buildProblem( fasta.messageConstructorNotSync, body!.fileOffset, noLength))); } if (needsImplicitSuperInitializer) { @@ -2075,13 +2077,13 @@ class BodyBuilder extends StackListenerImpl namedArguments = namedSuperParametersAsArguments; } if (sourceClassBuilder is SourceEnumBuilder) { - assert(constructor.function.positionalParameters.length >= 2 && - constructor.function.positionalParameters[0].name == "#index" && - constructor.function.positionalParameters[1].name == "#name"); + assert(function.positionalParameters.length >= 2 && + function.positionalParameters[0].name == "#index" && + function.positionalParameters[1].name == "#name"); (positionalArguments ??= []).insertAll(0, [ - new VariableGetImpl(constructor.function.positionalParameters[0], + new VariableGetImpl(function.positionalParameters[0], forNullGuardedAccess: false), - new VariableGetImpl(constructor.function.positionalParameters[1], + new VariableGetImpl(function.positionalParameters[1], forNullGuardedAccess: false) ]); } @@ -2104,9 +2106,9 @@ class BodyBuilder extends StackListenerImpl null) { String superclass = sourceClassBuilder!.supertypeBuilder!.fullNameForErrors; - int length = constructor.name.text.length; + int length = builder.name.length; if (length == 0) { - length = (constructor.parent as Class).name.length; + length = sourceClassBuilder!.cls.name.length; } initializer = buildInvalidInitializer( buildProblem( @@ -2125,16 +2127,15 @@ class BodyBuilder extends StackListenerImpl builder.addInitializer(initializer, this, inferenceResult: inferenceResult); } else { - constructor.initializers.add(initializer); + builtInitializers.add(initializer); } } - setParents(constructor.initializers, constructor); + setParents(builtInitializers, member); if (body == null) { /// >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. - constructor.function.body = new EmptyStatement() - ..parent = constructor.function; + function.body = new EmptyStatement()..parent = function; } } diff --git a/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart b/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart index 7bcff0f50bb..ce1ce423db2 100644 --- a/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart +++ b/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart @@ -101,10 +101,12 @@ Procedure? createConstructorTearOffProcedure( Uri fileUri, int fileOffset, Reference? reference, - {required bool forAbstractClassOrEnum}) { + {required bool forAbstractClassOrEnum, + bool forceCreateLowering = false}) { if (!forAbstractClassOrEnum && - compilationUnit - .loader.target.backendTarget.isConstructorTearOffLoweringEnabled) { + (forceCreateLowering || + compilationUnit.loader.target.backendTarget + .isConstructorTearOffLoweringEnabled)) { return _createTearOffProcedure(compilationUnit, constructorTearOffName(name), fileUri, fileOffset, reference); } @@ -144,7 +146,8 @@ Procedure createTypedefTearOffProcedure( } /// Creates the parameters and body for [tearOff] based on -/// [declarationConstructor] in [enclosingClass]. +/// [declarationConstructor]. +/// [enclosingDeclarationTypeParameters]. /// /// The [declarationConstructor] is the origin constructor and /// [implementationConstructor] is the patch constructor, if patched, otherwise @@ -153,7 +156,7 @@ void buildConstructorTearOffProcedure( {required Procedure tearOff, required Member declarationConstructor, required Member implementationConstructor, - required Class enclosingClass, + List? enclosingDeclarationTypeParameters, required SourceLibraryBuilder libraryBuilder}) { assert( declarationConstructor is Constructor || @@ -176,19 +179,15 @@ void buildConstructorTearOffProcedure( int fileOffset = tearOff.fileOffset; - List classTypeParameters; - if (declarationConstructor is Constructor) { - // Generative constructors implicitly have the type parameters of the - // enclosing class. - classTypeParameters = enclosingClass.typeParameters; - } else { - // Factory constructors explicitly copy over the type parameters of the - // enclosing class. - classTypeParameters = function.typeParameters; - } + // Generative constructors implicitly have the type parameters of the + // enclosing class. + // Factory constructors explicitly copy over the type parameters of the + // enclosing class. + List declarationTypeParameters = + enclosingDeclarationTypeParameters ?? function.typeParameters; FreshTypeParameters freshTypeParameters = - _createFreshTypeParameters(classTypeParameters, tearOff.function); + _createFreshTypeParameters(declarationTypeParameters, tearOff.function); List typeArguments = freshTypeParameters.freshTypeArguments; Substitution substitution = freshTypeParameters.substitution; diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart index 79f2a9504ac..d5f9d977189 100644 --- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart +++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart @@ -1087,7 +1087,7 @@ class KernelTarget extends TargetImplementation { tearOff: constructorTearOff, declarationConstructor: constructor, implementationConstructor: constructor, - enclosingClass: classBuilder.cls, + enclosingDeclarationTypeParameters: classBuilder.cls.typeParameters, libraryBuilder: classBuilder.libraryBuilder); } SyntheticSourceConstructorBuilder constructorBuilder = @@ -1166,7 +1166,7 @@ class KernelTarget extends TargetImplementation { tearOff: constructorTearOff, declarationConstructor: constructor, implementationConstructor: constructor, - enclosingClass: classBuilder.cls, + enclosingDeclarationTypeParameters: classBuilder.cls.typeParameters, libraryBuilder: classBuilder.libraryBuilder); } return new SyntheticSourceConstructorBuilder( @@ -1404,7 +1404,7 @@ class KernelTarget extends TargetImplementation { } } - Map> + Map> constructorInitializedFields = new Map.identity(); Set? initializedFields = null; @@ -1467,8 +1467,9 @@ class KernelTarget extends TargetImplementation { // Run through all fields that are initialized by some constructor, and // make sure that all other constructors also initialize them. - constructorInitializedFields.forEach((ConstructorBuilder constructorBuilder, - Set fieldBuilders) { + constructorInitializedFields.forEach( + (DeclaredSourceConstructorBuilder constructorBuilder, + Set fieldBuilders) { for (SourceFieldBuilder fieldBuilder in initializedFields!.difference(fieldBuilders)) { if (!fieldBuilder.hasInitializer && !fieldBuilder.isLate) { diff --git a/pkg/front_end/lib/src/fasta/source/diet_listener.dart b/pkg/front_end/lib/src/fasta/source/diet_listener.dart index 6d20f5e595d..451b133551d 100644 --- a/pkg/front_end/lib/src/fasta/source/diet_listener.dart +++ b/pkg/front_end/lib/src/fasta/source/diet_listener.dart @@ -51,11 +51,13 @@ import '../type_inference/type_inference_engine.dart' show InferenceDataForTesting, TypeInferenceEngine; import '../type_inference/type_inferrer.dart' show TypeInferrer; import 'diet_parser.dart'; +import 'source_class_builder.dart'; import 'source_constructor_builder.dart'; import 'source_enum_builder.dart'; import 'source_field_builder.dart'; import 'source_function_builder.dart'; import 'source_library_builder.dart' show SourceLibraryBuilder; +import 'source_view_builder.dart'; import 'stack_listener_impl.dart'; class DietListener extends StackListenerImpl { @@ -729,10 +731,9 @@ class DietListener extends StackListenerImpl { Token? metadata = pop() as Token?; checkEmpty(beginToken.charOffset); if (name is ParserRecovery || currentClassIsParserRecovery) return; - SourceFunctionBuilderImpl builder; + SourceFunctionBuilder builder; if (isConstructor) { - builder = - lookupConstructor(beginToken, name!) as SourceFunctionBuilderImpl; + builder = lookupConstructor(beginToken, name!) as SourceFunctionBuilder; } else { Builder? memberBuilder = lookupBuilder(beginToken, getOrSet, name as String); @@ -745,7 +746,7 @@ class DietListener extends StackListenerImpl { // this point we skip the member. return; } - builder = memberBuilder as SourceFunctionBuilderImpl; + builder = memberBuilder as SourceFunctionBuilder; } buildFunctionBody( createFunctionListener(builder), @@ -809,7 +810,7 @@ class DietListener extends StackListenerImpl { ..constantContext = constantContext; } - BodyBuilder createFunctionListener(SourceFunctionBuilderImpl builder) { + BodyBuilder createFunctionListener(SourceFunctionBuilder builder) { final Scope typeParameterScope = builder.computeTypeParameterScope(memberScope); final Scope formalParameterScope = @@ -1166,20 +1167,23 @@ class DietListener extends StackListenerImpl { } Builder? lookupConstructor(Token token, Object nameOrQualified) { - assert(currentClass != null); + assert(currentDeclaration != null); + assert(currentDeclaration is SourceClassBuilder || + currentDeclaration is SourceViewBuilder); Builder? declaration; String suffix; if (nameOrQualified is QualifiedName) { suffix = nameOrQualified.name; } else { - suffix = nameOrQualified == currentClass!.name + suffix = nameOrQualified == currentDeclaration!.name ? "" : nameOrQualified as String; } if (libraryFeatures.constructorTearoffs.isEnabled) { suffix = suffix == "new" ? "" : suffix; } - declaration = currentClass!.constructorScope.lookupLocalMember(suffix); + declaration = + currentDeclaration!.constructorScope.lookupLocalMember(suffix); declaration = handleDuplicatedName(declaration, token); checkBuilder(token, declaration, nameOrQualified); return declaration; diff --git a/pkg/front_end/lib/src/fasta/source/name_scheme.dart b/pkg/front_end/lib/src/fasta/source/name_scheme.dart index 2ef2d130957..73cafed1fbd 100644 --- a/pkg/front_end/lib/src/fasta/source/name_scheme.dart +++ b/pkg/front_end/lib/src/fasta/source/name_scheme.dart @@ -151,8 +151,20 @@ class NameScheme { } } - // TODO(johnniwinther): Use [NameScheme] for constructor and constructor - // tear-off names. + MemberName getConstructorMemberName(String name, {required bool isTearOff}) { + switch (containerType) { + case ContainerType.Library: + case ContainerType.Class: + return name.startsWith('_') + ? new PrivateMemberName(libraryName, name) + : new PublicMemberName(name); + case ContainerType.View: + case ContainerType.Extension: + // Extension is handled here for the error case only. + return new ViewConstructorName(libraryName, containerName!, name, + isTearOff: isTearOff); + } + } } /// The part of a member name defined by a library. @@ -395,8 +407,8 @@ class PrivateMemberName extends UpdatableMemberName { /// A name for an extension procedure. /// -/// This depends on a [LibraryName] and an [ExtensionName] and is updated the -/// reference of the [LibraryName] or the name of the [ExtensionName] is +/// This depends on a [LibraryName] and an [ContainerName] and is updated the +/// reference of the [LibraryName] or the name of the [ContainerName] is /// changed. class ExtensionProcedureName extends UpdatableMemberName { final LibraryName _libraryName; @@ -426,6 +438,40 @@ class ExtensionProcedureName extends UpdatableMemberName { } } +/// A name for a view constructor. +/// +/// This depends on a [LibraryName] and an [ContainerName] and is updated the +/// reference of the [LibraryName] or the name of the [ContainerName] is +/// changed. +class ViewConstructorName extends UpdatableMemberName { + final LibraryName _libraryName; + final ContainerName _containerName; + final bool isTearOff; + final String _text; + + ViewConstructorName(this._libraryName, this._containerName, this._text, + {required this.isTearOff}) { + _libraryName.attachMemberName(this); + _containerName.attachMemberName(this); + } + + @override + Name _createName() { + String viewName = _containerName.name; + String kindInfix; + // Constructors and tear-offs are converted to methods so we use an + // infix to make their names unique. + if (isTearOff) { + kindInfix = 'get#'; + } else { + kindInfix = ''; + } + + return new Name.byReference( + '${viewName}|${kindInfix}${_text}', _libraryName.reference); + } +} + /// A name of a synthesized field. /// /// This depends on a [LibraryName] and an [ExtensionName] and is updated the diff --git a/pkg/front_end/lib/src/fasta/source/source_builder_mixins.dart b/pkg/front_end/lib/src/fasta/source/source_builder_mixins.dart index 6563dd0c208..4a7e7bfb704 100644 --- a/pkg/front_end/lib/src/fasta/source/source_builder_mixins.dart +++ b/pkg/front_end/lib/src/fasta/source/source_builder_mixins.dart @@ -19,6 +19,7 @@ import '../kernel/kernel_helper.dart'; import '../problems.dart'; import '../scope.dart'; import '../util/helpers.dart'; +import 'source_constructor_builder.dart'; import 'source_field_builder.dart'; import 'source_library_builder.dart'; import 'source_member_builder.dart'; @@ -88,6 +89,7 @@ mixin SourceDeclarationBuilderMixin } scope.unfilteredNameIterator.forEach(buildBuilders); + constructorScope.unfilteredNameIterator.forEach(buildBuilders); } int buildBodyNodes({required bool addMembersToLibrary}) { @@ -122,6 +124,8 @@ mixin SourceDeclarationBuilderMixin setterDeclaration as ProcedureBuilder, typeEnvironment); } } + } else if (builder is SourceConstructorBuilder) { + builder.checkTypes(libraryBuilder, typeEnvironment); } else { assert(false, "Unexpected member: $builder."); } diff --git a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart index f4aab82c227..3bb2c54d745 100644 --- a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart +++ b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart @@ -1134,8 +1134,7 @@ class SourceClassBuilder extends ClassBuilderImpl // Synthetic constructors are created after the component has been built // so we need to add the constructor to the class. cls.addConstructor(constructorBuilder.invokeTarget); - if (constructorBuilder.readTarget != null && - constructorBuilder.readTarget != constructorBuilder.invokeTarget) { + if (constructorBuilder.readTarget != constructorBuilder.invokeTarget) { cls.addProcedure(constructorBuilder.readTarget as Procedure); } if (constructorBuilder.isConst) { diff --git a/pkg/front_end/lib/src/fasta/source/source_constructor_builder.dart b/pkg/front_end/lib/src/fasta/source/source_constructor_builder.dart index 3754f80659a..adb95185441 100644 --- a/pkg/front_end/lib/src/fasta/source/source_constructor_builder.dart +++ b/pkg/front_end/lib/src/fasta/source/source_constructor_builder.dart @@ -11,6 +11,7 @@ import 'package:kernel/type_environment.dart'; import '../builder/builder.dart'; import '../builder/class_builder.dart'; import '../builder/constructor_builder.dart'; +import '../builder/declaration_builder.dart'; import '../builder/formal_parameter_builder.dart'; import '../builder/member_builder.dart'; import '../builder/metadata_builder.dart'; @@ -55,9 +56,12 @@ import '../util/helpers.dart' show DelayedActionPerformer; import 'name_scheme.dart'; import 'source_field_builder.dart'; import 'source_function_builder.dart'; +import 'source_view_builder.dart'; abstract class SourceConstructorBuilder implements ConstructorBuilder, SourceMemberBuilder { + DeclarationBuilder get declarationBuilder; + /// Infers the types of any untyped initializing formals. void inferFormalTypes(ClassHierarchyBase hierarchy); @@ -72,87 +76,33 @@ abstract class SourceConstructorBuilder bool get isRedirecting; } -class DeclaredSourceConstructorBuilder extends SourceFunctionBuilderImpl +abstract class AbstractSourceConstructorBuilder + extends SourceFunctionBuilderImpl implements SourceConstructorBuilder, Inferable { @override final OmittedTypeBuilder returnType; - late final Constructor _constructor; - late final Procedure? _constructorTearOff; - - Set? _initializedFields; - final int charOpenParenOffset; - bool hasMovedSuperInitializer = false; - - SuperInitializer? superInitializer; - - RedirectingInitializer? redirectingInitializer; - - Token? beginInitializers; - - DeclaredSourceConstructorBuilder? actualOrigin; - - Constructor get actualConstructor => _constructor; - - List? _patches; - bool _hasFormalsInferred = false; - bool _hasDefaultValueCloner = false; + Token? beginInitializers; - final bool _hasSuperInitializingFormals; - - final List _superParameterDefaultValueCloners = - []; - - @override - List? formals; - - @override - String get fullNameForErrors { - return "${flattenName(classBuilder.name, charOffset, fileUri)}" - "${name.isEmpty ? '' : '.$name'}"; - } - - DeclaredSourceConstructorBuilder( + AbstractSourceConstructorBuilder( List? metadata, int modifiers, this.returnType, String name, List? typeVariables, - this.formals, + List? formals, SourceLibraryBuilder compilationUnit, - int startCharOffset, int charOffset, this.charOpenParenOffset, - int charEndOffset, - Reference? constructorReference, - Reference? tearOffReference, - {String? nativeMethodName, - required bool forAbstractClassOrEnum}) - : _hasSuperInitializingFormals = - formals?.any((formal) => formal.isSuperInitializingFormal) ?? false, - super(metadata, modifiers, name, typeVariables, formals, + String? nativeMethodName) + : super(metadata, modifiers, name, typeVariables, formals, compilationUnit, charOffset, nativeMethodName) { - _constructor = new Constructor(new FunctionNode(null), - name: dummyName, - fileUri: compilationUnit.fileUri, - reference: constructorReference) - ..startFileOffset = startCharOffset - ..fileOffset = charOffset - ..fileEndOffset = charEndOffset - ..isNonNullableByDefault = compilationUnit.isNonNullableByDefault; - MemberName constructorName = - new MemberName(compilationUnit.libraryName, name); - constructorName.attachMember(_constructor); - _constructorTearOff = createConstructorTearOffProcedure(name, - compilationUnit, compilationUnit.fileUri, charOffset, tearOffReference, - forAbstractClassOrEnum: forAbstractClassOrEnum); - if (formals != null) { - for (FormalParameterBuilder formal in formals!) { + for (FormalParameterBuilder formal in formals) { if (formal.isInitializingFormal || formal.isSuperInitializingFormal) { formal.type.registerInferable(this); } @@ -160,12 +110,292 @@ class DeclaredSourceConstructorBuilder extends SourceFunctionBuilderImpl } } + @override + DeclarationBuilder get declarationBuilder => super.declarationBuilder!; + + @override + bool get isConstructor => true; + + @override + ProcedureKind? get kind => null; + + @override + AsyncMarker get asyncModifier => AsyncMarker.Sync; + + @override + void inferTypes(ClassHierarchyBase hierarchy) { + inferFormalTypes(hierarchy); + } + + @override + void inferFormalTypes(ClassHierarchyBase hierarchy) { + if (_hasFormalsInferred) return; + if (formals != null) { + libraryBuilder.loader.withUriForCrashReporting(fileUri, charOffset, () { + for (FormalParameterBuilder formal in formals!) { + if (formal.type is InferableTypeBuilder) { + if (formal.isInitializingFormal) { + formal.finalizeInitializingFormal(declarationBuilder, hierarchy); + } + } + } + _inferSuperInitializingFormals(hierarchy); + }); + } + _hasFormalsInferred = true; + } + + 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; + + @override + bool get isRedirecting { + for (Initializer initializer in initializers) { + if (initializer is RedirectingInitializer) { + return true; + } + } + return false; + } + + void _injectInvalidInitializer(Message message, int charOffset, int length, + ExpressionGeneratorHelper helper) { + Initializer lastInitializer = initializers.removeLast(); + assert(lastInitializer == superInitializer || + lastInitializer == redirectingInitializer); + Initializer error = helper.buildInvalidInitializer( + helper.buildProblem(message, charOffset, length)); + initializers.add(error..parent = member); + initializers.add(lastInitializer); + } + + SuperInitializer? superInitializer; + + RedirectingInitializer? redirectingInitializer; + + void addInitializer(Initializer initializer, ExpressionGeneratorHelper helper, + {required InitializerInferenceResult? inferenceResult}) { + if (initializer is SuperInitializer) { + if (superInitializer != null) { + _injectInvalidInitializer(messageMoreThanOneSuperInitializer, + initializer.fileOffset, "super".length, helper); + } else if (redirectingInitializer != null) { + _injectInvalidInitializer( + messageRedirectingConstructorWithSuperInitializer, + initializer.fileOffset, + "super".length, + helper); + } else { + inferenceResult?.applyResult(initializers, member); + superInitializer = initializer; + + LocatedMessage? message = helper.checkArgumentsForFunction( + initializer.target.function, + initializer.arguments, + initializer.arguments.fileOffset, []); + if (message != null) { + initializers.add(helper.buildInvalidInitializer( + helper.buildUnresolvedError( + helper.constructorNameForDiagnostics( + initializer.target.name.text), + initializer.fileOffset, + arguments: initializer.arguments, + isSuper: true, + message: message, + kind: UnresolvedKind.Constructor)) + ..parent = member); + } else { + initializers.add(initializer..parent = member); + } + } + } else if (initializer is RedirectingInitializer) { + if (superInitializer != null) { + // Point to the existing super initializer. + _injectInvalidInitializer( + messageRedirectingConstructorWithSuperInitializer, + superInitializer!.fileOffset, + "super".length, + helper); + } else if (redirectingInitializer != null) { + _injectInvalidInitializer( + messageRedirectingConstructorWithMultipleRedirectInitializers, + initializer.fileOffset, + noLength, + helper); + } else if (initializers.isNotEmpty) { + // Error on all previous ones. + 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( + helper.buildProblem( + messageRedirectingConstructorWithAnotherInitializer, + initializer.fileOffset, + length)); + error.parent = member; + initializers[i] = error; + } + inferenceResult?.applyResult(initializers, member); + initializers.add(initializer..parent = member); + redirectingInitializer = initializer; + } else { + inferenceResult?.applyResult(initializers, member); + redirectingInitializer = initializer; + + LocatedMessage? message = helper.checkArgumentsForFunction( + initializer.target.function, + initializer.arguments, + initializer.arguments.fileOffset, const []); + if (message != null) { + initializers.add(helper.buildInvalidInitializer( + helper.buildUnresolvedError( + helper.constructorNameForDiagnostics( + initializer.target.name.text, + isSuper: false), + initializer.fileOffset, + arguments: initializer.arguments, + isSuper: false, + message: message, + kind: UnresolvedKind.Constructor)) + ..parent = member); + } else { + initializers.add(initializer..parent = member); + } + } + } else if (redirectingInitializer != null) { + int length = noLength; + if (initializer is AssertInitializer) length = "assert".length; + _injectInvalidInitializer( + messageRedirectingConstructorWithAnotherInitializer, + initializer.fileOffset, + length, + helper); + } else if (superInitializer != null) { + _injectInvalidInitializer(messageSuperInitializerNotLast, + initializer.fileOffset, noLength, helper); + } else { + inferenceResult?.applyResult(initializers, member); + initializers.add(initializer..parent = member); + } + } + + @override + void checkVariance( + SourceClassBuilder sourceClassBuilder, TypeEnvironment typeEnvironment) {} + + @override + void checkTypes( + SourceLibraryBuilder library, TypeEnvironment typeEnvironment) { + library.checkTypesInConstructorBuilder(this, formals, typeEnvironment); + } + + @override + List get localMembers => + throw new UnsupportedError('${runtimeType}.localMembers'); + + @override + List get localSetters => + throw new UnsupportedError('${runtimeType}.localSetters'); +} + +class DeclaredSourceConstructorBuilder + extends AbstractSourceConstructorBuilder { + late final Constructor _constructor; + late final Procedure? _constructorTearOff; + + Set? _initializedFields; + + DeclaredSourceConstructorBuilder? actualOrigin; + + Constructor get actualConstructor => _constructor; + + List? _patches; + + bool _hasDefaultValueCloner = false; + + @override + List? formals; + + @override + String get fullNameForErrors { + return "${flattenName(declarationBuilder.name, charOffset, fileUri)}" + "${name.isEmpty ? '' : '.$name'}"; + } + + DeclaredSourceConstructorBuilder( + List? metadata, + int modifiers, + OmittedTypeBuilder returnType, + String name, + List? typeVariables, + this.formals, + SourceLibraryBuilder compilationUnit, + int startCharOffset, + int charOffset, + int charOpenParenOffset, + int charEndOffset, + Reference? constructorReference, + Reference? tearOffReference, + NameScheme nameScheme, + {String? nativeMethodName, + required bool forAbstractClassOrEnum}) + : _hasSuperInitializingFormals = + formals?.any((formal) => formal.isSuperInitializingFormal) ?? false, + super( + metadata, + modifiers, + returnType, + name, + typeVariables, + formals, + compilationUnit, + charOffset, + charOpenParenOffset, + nativeMethodName) { + _constructor = new Constructor(new FunctionNode(null), + name: dummyName, + fileUri: compilationUnit.fileUri, + reference: constructorReference) + ..startFileOffset = startCharOffset + ..fileOffset = charOffset + ..fileEndOffset = charEndOffset + ..isNonNullableByDefault = compilationUnit.isNonNullableByDefault; + nameScheme + .getConstructorMemberName(name, isTearOff: false) + .attachMember(_constructor); + _constructorTearOff = createConstructorTearOffProcedure(name, + compilationUnit, compilationUnit.fileUri, charOffset, tearOffReference, + forAbstractClassOrEnum: forAbstractClassOrEnum); + // TODO(johnniwinther): Use [NameScheme] for constructor tear-off names. + } + @override SourceClassBuilder get classBuilder => super.classBuilder as SourceClassBuilder; @override - Member? get readTarget => _constructorTearOff ?? _constructor; + Member get readTarget => _constructorTearOff ?? _constructor; @override Member? get writeTarget => null; @@ -179,6 +409,9 @@ class DeclaredSourceConstructorBuilder extends SourceFunctionBuilderImpl @override Iterable get exportedMembers => [constructor]; + @override + List get initializers => _constructor.initializers; + @override DeclaredSourceConstructorBuilder get origin => actualOrigin ?? this; @@ -190,25 +423,6 @@ class DeclaredSourceConstructorBuilder extends SourceFunctionBuilderImpl @override bool get isClassInstanceMember => false; - @override - bool get isConstructor => true; - - @override - AsyncMarker get asyncModifier => AsyncMarker.Sync; - - @override - ProcedureKind? get kind => null; - - @override - bool get isRedirecting { - for (Initializer initializer in _constructor.initializers) { - if (initializer is RedirectingInitializer) { - return true; - } - } - return false; - } - /// Returns `true` if this constructor, including its augmentations, is /// external. /// @@ -272,29 +486,13 @@ class DeclaredSourceConstructorBuilder extends SourceFunctionBuilderImpl tearOff: _constructorTearOff!, declarationConstructor: constructor, implementationConstructor: _constructor, - enclosingClass: classBuilder.cls, + enclosingDeclarationTypeParameters: classBuilder.cls.typeParameters, 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, this); - } - } + _buildFormals(_constructor); } @override @@ -306,47 +504,9 @@ class DeclaredSourceConstructorBuilder extends SourceFunctionBuilderImpl } } - @override - void inferTypes(ClassHierarchyBase hierarchy) { - inferFormalTypes(hierarchy); - } - - @override - void inferFormalTypes(ClassHierarchyBase hierarchy) { - if (_hasFormalsInferred) return; - if (formals != null) { - libraryBuilder.loader.withUriForCrashReporting(fileUri, charOffset, () { - for (FormalParameterBuilder formal in formals!) { - if (formal.type is InferableTypeBuilder) { - if (formal.isInitializingFormal) { - formal.finalizeInitializingFormal(classBuilder, hierarchy); - } - } - } - - if (_hasSuperInitializingFormals) { - List? initializers; - if (beginInitializers != null) { - BodyBuilder bodyBuilder = libraryBuilder.loader - .createBodyBuilderForOutlineExpression(libraryBuilder, - classBuilder, this, classBuilder.scope, fileUri); - if (isConst) { - bodyBuilder.constantContext = ConstantContext.required; - } - initializers = bodyBuilder.parseInitializers(beginInitializers!, - doFinishConstructor: false); - } - finalizeSuperInitializingFormals( - hierarchy, _superParameterDefaultValueCloners, initializers); - } - }); - } - _hasFormalsInferred = true; - } - ConstructorBuilder? _computeSuperTargetBuilder( List? initializers) { - Constructor superTarget; + Member superTarget; ClassBuilder superclassBuilder; TypeBuilder? supertype = classBuilder.supertypeBuilder; @@ -379,7 +539,7 @@ class DeclaredSourceConstructorBuilder extends SourceFunctionBuilderImpl MemberBuilder? memberBuilder = superclassBuilder.constructorScope .lookup("", charOffset, libraryBuilder.fileUri); if (memberBuilder is ConstructorBuilder) { - superTarget = memberBuilder.constructor; + superTarget = memberBuilder.invokeTarget; } else { // The error in this case should be reported elsewhere. return null; @@ -392,6 +552,30 @@ class DeclaredSourceConstructorBuilder extends SourceFunctionBuilderImpl return constructorBuilder is ConstructorBuilder ? constructorBuilder : null; } + final bool _hasSuperInitializingFormals; + + final List _superParameterDefaultValueCloners = + []; + + @override + void _inferSuperInitializingFormals(ClassHierarchyBase hierarchy) { + if (_hasSuperInitializingFormals) { + List? initializers; + if (beginInitializers != null) { + BodyBuilder bodyBuilder = libraryBuilder.loader + .createBodyBuilderForOutlineExpression(libraryBuilder, + declarationBuilder, this, declarationBuilder.scope, fileUri); + if (isConst) { + bodyBuilder.constantContext = ConstantContext.required; + } + initializers = bodyBuilder.parseInitializers(beginInitializers!, + doFinishConstructor: false); + } + finalizeSuperInitializingFormals( + hierarchy, _superParameterDefaultValueCloners, initializers); + } + } + void finalizeSuperInitializingFormals( ClassHierarchyBase hierarchy, List delayedDefaultValueCloners, @@ -417,10 +601,10 @@ class DeclaredSourceConstructorBuilder extends SourceFunctionBuilderImpl superTargetBuilder.inferFormalTypes(hierarchy); } - Constructor superTarget; + Member superTarget; FunctionNode? superConstructorFunction; if (superTargetBuilder != null) { - superTarget = superTargetBuilder.constructor; + superTarget = superTargetBuilder.invokeTarget; superConstructorFunction = superTargetBuilder.function; } else { // The error in this case should be reported elsewhere. Here we perform a @@ -450,7 +634,7 @@ class DeclaredSourceConstructorBuilder extends SourceFunctionBuilderImpl List? namedSuperParameters; Supertype? supertype = hierarchy.getClassAsInstanceOf( - classBuilder.cls, superTarget.enclosingClass); + classBuilder.cls, superTarget.enclosingClass!); assert(supertype != null); Map substitution = new Map.fromIterables( @@ -553,7 +737,7 @@ class DeclaredSourceConstructorBuilder extends SourceFunctionBuilderImpl // We're going to fully build the constructor so we need scopes. formalParameterScope = computeFormalParameterInitializerScope( computeFormalParameterScope( - computeTypeParameterScope(declarationBuilder!.scope))); + computeTypeParameterScope(declarationBuilder.scope))); } else { formalParameterScope = null; } @@ -583,10 +767,7 @@ class DeclaredSourceConstructorBuilder extends SourceFunctionBuilderImpl List delayedDefaultValueCloners) { ConstructorBuilder? superTargetBuilder = _computeSuperTargetBuilder(constructor.initializers); - if (superTargetBuilder is DeclaredSourceConstructorBuilder) { - superTargetBuilder - .addSuperParameterDefaultValueCloners(delayedDefaultValueCloners); - } else if (superTargetBuilder is SyntheticSourceConstructorBuilder) { + if (superTargetBuilder is SourceConstructorBuilder) { superTargetBuilder .addSuperParameterDefaultValueCloners(delayedDefaultValueCloners); } @@ -608,137 +789,16 @@ class DeclaredSourceConstructorBuilder extends SourceFunctionBuilderImpl new TypeParameterType.withDefaultNullabilityForLibrary( typeParameter, libraryBuilder.library)); } - DartType type = new InterfaceType( + InterfaceType type = new InterfaceType( enclosingClass, libraryBuilder.nonNullable, typeParameterTypes); returnType.registerInferredType(type); } - @override Constructor get constructor => isPatch ? origin.constructor : _constructor; @override Member get member => constructor; - void injectInvalidInitializer(Message message, int charOffset, int length, - ExpressionGeneratorHelper helper) { - List initializers = _constructor.initializers; - Initializer lastInitializer = initializers.removeLast(); - assert(lastInitializer == superInitializer || - lastInitializer == redirectingInitializer); - Initializer error = helper.buildInvalidInitializer( - helper.buildProblem(message, charOffset, length)); - initializers.add(error..parent = _constructor); - initializers.add(lastInitializer); - } - - void addInitializer(Initializer initializer, ExpressionGeneratorHelper helper, - {required InitializerInferenceResult? inferenceResult}) { - List initializers = _constructor.initializers; - if (initializer is SuperInitializer) { - if (superInitializer != null) { - injectInvalidInitializer(messageMoreThanOneSuperInitializer, - initializer.fileOffset, "super".length, helper); - } else if (redirectingInitializer != null) { - injectInvalidInitializer( - messageRedirectingConstructorWithSuperInitializer, - initializer.fileOffset, - "super".length, - helper); - } else { - inferenceResult?.applyResult(initializers, _constructor); - superInitializer = initializer; - - LocatedMessage? message = helper.checkArgumentsForFunction( - initializer.target.function, - initializer.arguments, - initializer.arguments.fileOffset, []); - if (message != null) { - initializers.add(helper.buildInvalidInitializer( - helper.buildUnresolvedError( - helper.constructorNameForDiagnostics( - initializer.target.name.text), - initializer.fileOffset, - arguments: initializer.arguments, - isSuper: true, - message: message, - kind: UnresolvedKind.Constructor)) - ..parent = _constructor); - } else { - initializers.add(initializer..parent = _constructor); - } - } - } else if (initializer is RedirectingInitializer) { - if (superInitializer != null) { - // Point to the existing super initializer. - injectInvalidInitializer( - messageRedirectingConstructorWithSuperInitializer, - superInitializer!.fileOffset, - "super".length, - helper); - } else if (redirectingInitializer != null) { - injectInvalidInitializer( - messageRedirectingConstructorWithMultipleRedirectInitializers, - initializer.fileOffset, - noLength, - helper); - } else if (initializers.isNotEmpty) { - // Error on all previous ones. - 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( - helper.buildProblem( - messageRedirectingConstructorWithAnotherInitializer, - initializer.fileOffset, - length)); - error.parent = _constructor; - initializers[i] = error; - } - inferenceResult?.applyResult(initializers, _constructor); - initializers.add(initializer..parent = _constructor); - redirectingInitializer = initializer; - } else { - inferenceResult?.applyResult(initializers, _constructor); - redirectingInitializer = initializer; - - LocatedMessage? message = helper.checkArgumentsForFunction( - initializer.target.function, - initializer.arguments, - initializer.arguments.fileOffset, const []); - if (message != null) { - initializers.add(helper.buildInvalidInitializer( - helper.buildUnresolvedError( - helper.constructorNameForDiagnostics( - initializer.target.name.text, - isSuper: false), - initializer.fileOffset, - arguments: initializer.arguments, - isSuper: false, - message: message, - kind: UnresolvedKind.Constructor)) - ..parent = _constructor); - } else { - initializers.add(initializer..parent = _constructor); - } - } - } else if (redirectingInitializer != null) { - int length = noLength; - if (initializer is AssertInitializer) length = "assert".length; - injectInvalidInitializer( - messageRedirectingConstructorWithAnotherInitializer, - initializer.fileOffset, - length, - helper); - } else if (superInitializer != null) { - injectInvalidInitializer(messageSuperInitializerNotLast, - initializer.fileOffset, noLength, helper); - } else { - inferenceResult?.applyResult(initializers, _constructor); - initializers.add(initializer..parent = _constructor); - } - } - @override VariableDeclaration? getTearOffParameter(int index) { if (_constructorTearOff != null) { @@ -802,17 +862,8 @@ class DeclaredSourceConstructorBuilder extends SourceFunctionBuilderImpl _constructor.initializers = []; redirectingInitializer = null; superInitializer = null; - hasMovedSuperInitializer = false; } - @override - List get localMembers => - throw new UnsupportedError('${runtimeType}.localMembers'); - - @override - List get localSetters => - throw new UnsupportedError('${runtimeType}.localSetters'); - /// Registers field as being initialized by this constructor. /// /// The field can be initialized either via an initializing formal or via an @@ -844,14 +895,10 @@ class DeclaredSourceConstructorBuilder extends SourceFunctionBuilderImpl } } - @override - void checkVariance( - SourceClassBuilder sourceClassBuilder, TypeEnvironment typeEnvironment) {} - @override void checkTypes( SourceLibraryBuilder library, TypeEnvironment typeEnvironment) { - library.checkTypesInConstructorBuilder(this, typeEnvironment); + super.checkTypes(library, typeEnvironment); List? patches = _patches; if (patches != null) { for (DeclaredSourceConstructorBuilder patch in patches) { @@ -890,6 +937,9 @@ class SyntheticSourceConstructorBuilder extends DillConstructorBuilder SourceLibraryBuilder get libraryBuilder => super.libraryBuilder as SourceLibraryBuilder; + @override + DeclarationBuilder get declarationBuilder => classBuilder!; + @override bool get isRedirecting { for (Initializer initializer in constructor.initializers) { @@ -972,3 +1022,150 @@ class SyntheticSourceConstructorBuilder extends DillConstructorBuilder void checkTypes( SourceLibraryBuilder library, TypeEnvironment typeEnvironment) {} } + +class SourceViewConstructorBuilder extends AbstractSourceConstructorBuilder { + late final Procedure _constructor; + late final Procedure? _constructorTearOff; + + @override + final List initializers = []; + + SourceViewConstructorBuilder( + List? metadata, + int modifiers, + OmittedTypeBuilder returnType, + String name, + List? typeVariables, + List? formals, + SourceLibraryBuilder compilationUnit, + int startCharOffset, + int charOffset, + int charOpenParenOffset, + int charEndOffset, + Reference? constructorReference, + Reference? tearOffReference, + NameScheme nameScheme, + {String? nativeMethodName, + required bool forAbstractClassOrEnum}) + : super( + metadata, + modifiers, + returnType, + name, + typeVariables, + formals, + compilationUnit, + charOffset, + charOpenParenOffset, + nativeMethodName) { + _constructor = new Procedure( + dummyName, ProcedureKind.Method, new FunctionNode(null), + fileUri: compilationUnit.fileUri, reference: constructorReference) + ..fileOffset = charOffset + ..fileEndOffset = charEndOffset + ..isNonNullableByDefault = compilationUnit.isNonNullableByDefault; + nameScheme + .getConstructorMemberName(name, isTearOff: false) + .attachMember(_constructor); + _constructorTearOff = createConstructorTearOffProcedure( + name, + compilationUnit, compilationUnit.fileUri, charOffset, tearOffReference, + forAbstractClassOrEnum: forAbstractClassOrEnum, + // TODO(johnniwinther): Generate tear-off. + /*forceCreateLowering: true*/ + ); + if (_constructorTearOff != null) { + nameScheme + .getConstructorMemberName(name, isTearOff: true) + .attachMember(_constructorTearOff!); + } + } + + SourceViewBuilder get viewBuilder => parent as SourceViewBuilder; + + @override + Member get member => _constructor; + + @override + Member get readTarget => _constructorTearOff ?? _constructor; + + @override + Member? get writeTarget => null; + + @override + Member get invokeTarget => _constructor; + + @override + FunctionNode get function => _constructor.function; + + @override + Iterable get exportedMembers => [_constructor]; + + @override + void addSuperParameterDefaultValueCloners( + List delayedDefaultValueCloners) {} + + @override + void _inferSuperInitializingFormals(ClassHierarchyBase hierarchy) {} + + @override + int buildBodyNodes(void Function(Member, BuiltMemberKind) f) { + // TODO(johnniwinther): Support augmentation. + return 0; + } + + @override + void buildOutlineNodes(void Function(Member, BuiltMemberKind) f) { + _build(); + f(_constructor, BuiltMemberKind.ViewConstructor); + if (_constructorTearOff != null) { + f(_constructorTearOff!, BuiltMemberKind.Method); + } + } + + 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(); + + View view = viewBuilder.view; + List typeParameterTypes = []; + for (int i = 0; i < view.typeParameters.length; i++) { + TypeParameter typeParameter = view.typeParameters[i]; + typeParameterTypes.add( + new TypeParameterType.withDefaultNullabilityForLibrary( + typeParameter, libraryBuilder.library)); + } + ViewType type = + new ViewType(view, libraryBuilder.nonNullable, typeParameterTypes); + returnType.registerInferredType(type); + } + + 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) { + buildConstructorTearOffProcedure( + tearOff: _constructorTearOff!, + declarationConstructor: _constructor, + implementationConstructor: _constructor, + enclosingDeclarationTypeParameters: viewBuilder.view.typeParameters, + libraryBuilder: libraryBuilder); + } + + _hasBeenBuilt = true; + } + _buildFormals(_constructor); + } + + // TODO(johnniwinther): Generate initializers and return statement. +} diff --git a/pkg/front_end/lib/src/fasta/source/source_enum_builder.dart b/pkg/front_end/lib/src/fasta/source/source_enum_builder.dart index 1623bf53dfa..cb7c78ecc21 100644 --- a/pkg/front_end/lib/src/fasta/source/source_enum_builder.dart +++ b/pkg/front_end/lib/src/fasta/source/source_enum_builder.dart @@ -334,6 +334,11 @@ class SourceEnumBuilder extends SourceClassBuilder { charEndOffset, constructorReference, tearOffReference, + new NameScheme( + isInstanceMember: false, + containerName: new ClassName(name), + containerType: ContainerType.Class, + libraryName: libraryName), forAbstractClassOrEnum: true); synthesizedDefaultConstructorBuilder .registerInitializedField(valuesBuilder); @@ -762,7 +767,7 @@ class SourceEnumBuilder extends SourceClassBuilder { } } else { Expression initializer = bodyBuilder.buildStaticInvocation( - constructorBuilder.constructor, arguments, + constructorBuilder.invokeTarget, arguments, constness: Constness.explicitConst, charOffset: fieldBuilder.charOffset); ExpressionInferenceResult inferenceResult = bodyBuilder.typeInferrer @@ -796,7 +801,7 @@ class SourceEnumBuilder extends SourceClassBuilder { } } else { Expression initializer = new ConstructorInvocation( - constructorBuilder.constructor, arguments, + constructorBuilder.invokeTarget as Constructor, arguments, isConst: true) ..fileOffset = fieldBuilder.charOffset; if (!fieldBuilder.hasBodyBeenBuilt) { diff --git a/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart b/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart index 12bbf685eef..90014d8e242 100644 --- a/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart +++ b/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart @@ -122,6 +122,7 @@ class SourceExtensionBuilder extends ExtensionBuilderImpl case BuiltMemberKind.RedirectingFactory: case BuiltMemberKind.Field: case BuiltMemberKind.Method: + case BuiltMemberKind.ViewConstructor: case BuiltMemberKind.ViewMethod: case BuiltMemberKind.ViewGetter: case BuiltMemberKind.ViewSetter: diff --git a/pkg/front_end/lib/src/fasta/source/source_factory_builder.dart b/pkg/front_end/lib/src/fasta/source/source_factory_builder.dart index ee986514cc2..c64a9e5fd68 100644 --- a/pkg/front_end/lib/src/fasta/source/source_factory_builder.dart +++ b/pkg/front_end/lib/src/fasta/source/source_factory_builder.dart @@ -90,6 +90,7 @@ class SourceFactoryBuilder extends SourceFunctionBuilderImpl { .attachMember(_procedureInternal); _factoryTearOff = createFactoryTearOffProcedure(name, libraryBuilder, libraryBuilder.fileUri, charOffset, tearOffReference); + // TODO(johnniwinther): Use [NameScheme] for constructor tear-off names. this.asyncModifier = asyncModifier; } @@ -166,7 +167,6 @@ class SourceFactoryBuilder extends SourceFunctionBuilderImpl { tearOff: _factoryTearOff!, declarationConstructor: _procedure, implementationConstructor: _procedureInternal, - enclosingClass: classBuilder.cls, libraryBuilder: libraryBuilder); } } diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart index 1a73024af8c..aae2ecbd8f9 100644 --- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart +++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart @@ -2187,12 +2187,14 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { Map constructors = declaration.constructors!; Map setters = declaration.setters!; - Scope classScope = new Scope( + Scope memberScope = new Scope( local: members, setters: setters, parent: scope.withTypeVariables(typeVariables), - debugName: "extension $name", + debugName: "view $name", isModifiable: false); + ConstructorScope constructorScope = + new ConstructorScope(name, constructors); View? referenceFrom = referencesFromIndexed?.lookupView(name); @@ -2215,7 +2217,8 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { modifiers, declaration.name, typeVariables, - classScope, + memberScope, + constructorScope, this, startOffset, nameOffset, @@ -2732,23 +2735,57 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { constructorTearOffName(constructorName), _currentClassReferencesFromIndexed!.library)); } - DeclaredSourceConstructorBuilder constructorBuilder = - new DeclaredSourceConstructorBuilder( - metadata, - modifiers & ~abstractMask, - addInferableType(), - constructorName, - typeVariables, - formals, - this, - startCharOffset, - charOffset, - charOpenParenOffset, - charEndOffset, - constructorReference, - tearOffReference, - nativeMethodName: nativeMethodName, - forAbstractClassOrEnum: forAbstractClass); + AbstractSourceConstructorBuilder constructorBuilder; + + ContainerType containerType = + currentTypeParameterScopeBuilder.containerType; + ContainerName? containerName = + currentTypeParameterScopeBuilder.containerName; + NameScheme nameScheme = new NameScheme( + isInstanceMember: false, + containerName: containerName, + containerType: containerType, + libraryName: referencesFrom != null + ? new LibraryName(referencesFrom!.reference) + : libraryName); + if (currentTypeParameterScopeBuilder.kind == + TypeParameterScopeKind.viewDeclaration) { + constructorBuilder = new SourceViewConstructorBuilder( + metadata, + modifiers & ~abstractMask, + addInferableType(), + constructorName, + typeVariables, + formals, + this, + startCharOffset, + charOffset, + charOpenParenOffset, + charEndOffset, + constructorReference, + tearOffReference, + nameScheme, + nativeMethodName: nativeMethodName, + forAbstractClassOrEnum: forAbstractClass); + } else { + constructorBuilder = new DeclaredSourceConstructorBuilder( + metadata, + modifiers & ~abstractMask, + addInferableType(), + constructorName, + typeVariables, + formals, + this, + startCharOffset, + charOffset, + charOpenParenOffset, + charEndOffset, + constructorReference, + tearOffReference, + nameScheme, + nativeMethodName: nativeMethodName, + forAbstractClassOrEnum: forAbstractClass); + } checkTypeVariables(typeVariables, constructorBuilder); // TODO(johnniwinther): There is no way to pass the tear off reference here. addBuilder(constructorName, constructorBuilder, charOffset, @@ -3920,6 +3957,54 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { inErrorRecovery: issues.isNotEmpty); } + void processSourceFieldBuilder(SourceFieldBuilder member) { + TypeBuilder? fieldType = member.type; + if (fieldType is! OmittedTypeBuilder) { + List issues = + getInboundReferenceIssuesInType(fieldType); + reportIssues(issues); + _recursivelyReportGenericFunctionTypesAsBoundsForType(fieldType); + } + } + + void processSourceConstructorBuilder(SourceMemberBuilder member, + {required bool inErrorRecovery}) { + List? formals; + if (member is SourceFactoryBuilder) { + assert(member.isFactory, + "Unexpected constructor member (${member.runtimeType})."); + count += computeDefaultTypesForVariables(member.typeVariables, + // Type variables are inherited from the class so if the class + // has issues, so does the factory constructors. + inErrorRecovery: inErrorRecovery); + formals = member.formals; + } else { + assert(member is AbstractSourceConstructorBuilder, + "Unexpected constructor member (${member.runtimeType})."); + formals = (member as AbstractSourceConstructorBuilder).formals; + } + if (formals != null && formals.isNotEmpty) { + for (FormalParameterBuilder formal in formals) { + List issues = + getInboundReferenceIssuesInType(formal.type); + reportIssues(issues); + _recursivelyReportGenericFunctionTypesAsBoundsForType(formal.type); + } + } + } + + void processSourceMemberBuilder(SourceMemberBuilder member, + {required bool inErrorRecovery}) { + if (member is SourceProcedureBuilder) { + processSourceProcedureBuilder(member); + } else if (member is SourceFieldBuilder) { + processSourceFieldBuilder(member); + } else { + processSourceConstructorBuilder(member, + inErrorRecovery: inErrorRecovery); + } + } + void computeDefaultValuesForDeclaration(Builder declaration) { if (declaration is SourceClassBuilder) { List issues = getNonSimplicityIssuesForDeclaration( @@ -3929,51 +4014,23 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { count += computeDefaultTypesForVariables(declaration.typeVariables, inErrorRecovery: issues.isNotEmpty); - Iterator iterator = declaration.constructorScope - .filteredIterator( + Iterator iterator = declaration.constructorScope + .filteredIterator( includeDuplicates: false, includeAugmentations: true); while (iterator.moveNext()) { - MemberBuilder member = iterator.current; - List? formals; - if (member is SourceFactoryBuilder) { - assert(member.isFactory, - "Unexpected constructor member (${member.runtimeType})."); - count += computeDefaultTypesForVariables(member.typeVariables, - // Type variables are inherited from the class so if the class - // has issues, so does the factory constructors. - inErrorRecovery: issues.isNotEmpty); - formals = member.formals; - } else { - assert(member is DeclaredSourceConstructorBuilder, - "Unexpected constructor member (${member.runtimeType})."); - formals = (member as DeclaredSourceConstructorBuilder).formals; - } - if (formals != null && formals.isNotEmpty) { - for (FormalParameterBuilder formal in formals) { - List issues = - getInboundReferenceIssuesInType(formal.type); - reportIssues(issues); - _recursivelyReportGenericFunctionTypesAsBoundsForType( - formal.type); - } - } + processSourceMemberBuilder(iterator.current, + inErrorRecovery: issues.isNotEmpty); } Iterator memberIterator = declaration.fullMemberIterator; while (memberIterator.moveNext()) { Builder member = memberIterator.current; - if (member is SourceProcedureBuilder) { - processSourceProcedureBuilder(member); + if (member is SourceMemberBuilder) { + processSourceMemberBuilder(member, + inErrorRecovery: issues.isNotEmpty); } else { - assert(member is SourceFieldBuilder, + assert(false, "Unexpected class member $member (${member.runtimeType})."); - TypeBuilder? fieldType = (member as SourceFieldBuilder).type; - if (fieldType is! OmittedTypeBuilder) { - List issues = - getInboundReferenceIssuesInType(fieldType); - reportIssues(issues); - _recursivelyReportGenericFunctionTypesAsBoundsForType(fieldType); - } } } } else if (declaration is SourceTypeAliasBuilder) { @@ -3985,24 +4042,8 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { count += computeDefaultTypesForVariables(declaration.typeVariables, inErrorRecovery: issues.isNotEmpty); _recursivelyReportGenericFunctionTypesAsBoundsForType(declaration.type); - } else if (declaration is SourceFunctionBuilder) { - List issues = - getNonSimplicityIssuesForTypeVariables(declaration.typeVariables); - if (declaration.formals != null && declaration.formals!.isNotEmpty) { - for (FormalParameterBuilder formal in declaration.formals!) { - issues.addAll(getInboundReferenceIssuesInType(formal.type)); - _recursivelyReportGenericFunctionTypesAsBoundsForType(formal.type); - } - } - if (declaration.returnType is! OmittedTypeBuilder) { - issues - .addAll(getInboundReferenceIssuesInType(declaration.returnType)); - _recursivelyReportGenericFunctionTypesAsBoundsForType( - declaration.returnType); - } - reportIssues(issues); - count += computeDefaultTypesForVariables(declaration.typeVariables, - inErrorRecovery: issues.isNotEmpty); + } else if (declaration is SourceMemberBuilder) { + processSourceMemberBuilder(declaration, inErrorRecovery: false); } else if (declaration is SourceExtensionBuilder) { List issues = getNonSimplicityIssuesForDeclaration( declaration, @@ -4012,15 +4053,11 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { inErrorRecovery: issues.isNotEmpty); declaration.forEach((String name, Builder member) { - if (member is SourceProcedureBuilder) { - processSourceProcedureBuilder(member); - } else if (member is SourceFieldBuilder) { - if (member.type is! OmittedTypeBuilder) { - _recursivelyReportGenericFunctionTypesAsBoundsForType( - member.type); - } + if (member is SourceMemberBuilder) { + processSourceMemberBuilder(member, + inErrorRecovery: issues.isNotEmpty); } else { - throw new StateError( + assert(false, "Unexpected extension member $member (${member.runtimeType})."); } }); @@ -4033,26 +4070,14 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { inErrorRecovery: issues.isNotEmpty); declaration.forEach((String name, Builder member) { - if (member is SourceProcedureBuilder) { - processSourceProcedureBuilder(member); - } else if (member is SourceFieldBuilder) { - if (member.type is! OmittedTypeBuilder) { - _recursivelyReportGenericFunctionTypesAsBoundsForType( - member.type); - } + if (member is SourceMemberBuilder) { + processSourceMemberBuilder(member, + inErrorRecovery: issues.isNotEmpty); } else { - throw new StateError( - "Unexpected extension member $member (${member.runtimeType})."); + assert(false, + "Unexpected view member $member (${member.runtimeType})."); } }); - } else if (declaration is SourceFieldBuilder) { - if (declaration.type is! OmittedTypeBuilder) { - List issues = - getInboundReferenceIssuesInType(declaration.type); - reportIssues(issues); - _recursivelyReportGenericFunctionTypesAsBoundsForType( - declaration.type); - } } else { assert( declaration is PrefixBuilder || @@ -4339,10 +4364,11 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { } void checkTypesInConstructorBuilder( - DeclaredSourceConstructorBuilder constructorBuilder, + SourceConstructorBuilder constructorBuilder, + List? formals, TypeEnvironment typeEnvironment) { - if (!constructorBuilder.isExternal && constructorBuilder.formals != null) { - checkInitializersInFormals(constructorBuilder.formals!, typeEnvironment); + if (!constructorBuilder.isExternal && formals != null) { + checkInitializersInFormals(formals, typeEnvironment); } } diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart index 726ded7aad8..c393ef77a1a 100644 --- a/pkg/front_end/lib/src/fasta/source/source_loader.dart +++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart @@ -1005,8 +1005,8 @@ severity: $severity } void registerConstructorToBeInferred( - Constructor constructor, SourceConstructorBuilder builder) { - _typeInferenceEngine!.toBeInferred[constructor] = builder; + Member member, SourceConstructorBuilder builder) { + _typeInferenceEngine!.toBeInferred[member] = builder; } void registerTypeDependency(Member member, TypeDependency typeDependency) { diff --git a/pkg/front_end/lib/src/fasta/source/source_member_builder.dart b/pkg/front_end/lib/src/fasta/source/source_member_builder.dart index c87df4d88f9..f431bf0d4be 100644 --- a/pkg/front_end/lib/src/fasta/source/source_member_builder.dart +++ b/pkg/front_end/lib/src/fasta/source/source_member_builder.dart @@ -178,6 +178,7 @@ enum BuiltMemberKind { ExtensionSetter, ExtensionOperator, ExtensionTearOff, + ViewConstructor, ViewMethod, ViewGetter, ViewSetter, diff --git a/pkg/front_end/lib/src/fasta/source/source_view_builder.dart b/pkg/front_end/lib/src/fasta/source/source_view_builder.dart index 68b8bf197bd..f06861fb960 100644 --- a/pkg/front_end/lib/src/fasta/source/source_view_builder.dart +++ b/pkg/front_end/lib/src/fasta/source/source_view_builder.dart @@ -43,6 +43,7 @@ class SourceViewBuilder extends ViewBuilderImpl String name, this.typeParameters, Scope scope, + ConstructorScope constructorScope, SourceLibraryBuilder parent, int startOffset, int nameOffset, @@ -56,7 +57,8 @@ class SourceViewBuilder extends ViewBuilderImpl TypeVariableBuilder.typeParametersFromBuilders(typeParameters), reference: referenceFrom?.reference) ..fileOffset = nameOffset, - super(metadata, modifiers, name, parent, nameOffset, scope); + super(metadata, modifiers, name, parent, nameOffset, scope, + constructorScope); @override SourceLibraryBuilder get libraryBuilder => @@ -125,6 +127,9 @@ class SourceViewBuilder extends ViewBuilderImpl case BuiltMemberKind.LateIsSetField: kind = ViewMemberKind.Field; break; + case BuiltMemberKind.ViewConstructor: + kind = ViewMemberKind.Constructor; + break; case BuiltMemberKind.ViewMethod: kind = ViewMemberKind.Method; break; diff --git a/pkg/front_end/lib/src/fasta/type_inference/inference_visitor_base.dart b/pkg/front_end/lib/src/fasta/type_inference/inference_visitor_base.dart index 8e2d3474795..4724f39aee7 100644 --- a/pkg/front_end/lib/src/fasta/type_inference/inference_visitor_base.dart +++ b/pkg/front_end/lib/src/fasta/type_inference/inference_visitor_base.dart @@ -338,20 +338,20 @@ abstract class InferenceVisitorBase implements InferenceVisitor { } /// Ensures that all parameter types of [constructor] have been inferred. - void _inferConstructorParameterTypes(Constructor target) { - SourceConstructorBuilder? constructor = engine.beingInferred[target]; - if (constructor != null) { + void _inferConstructorParameterTypes(Member target) { + SourceConstructorBuilder? constructorBuilder = engine.beingInferred[target]; + if (constructorBuilder != null) { // There is a cyclic dependency where inferring the types of the // initializing formals of a constructor required us to infer the // corresponding field type which required us to know the type of the // constructor. - String name = target.enclosingClass.name; + String name = constructorBuilder.declarationBuilder.name; if (target.name.text.isNotEmpty) { // TODO(ahe): Use `inferrer.helper.constructorNameForDiagnostics` // instead. However, `inferrer.helper` may be null. name += ".${target.name.text}"; } - constructor.libraryBuilder.addProblem( + constructorBuilder.libraryBuilder.addProblem( templateCantInferTypeDueToCircularity.withArguments(name), target.fileOffset, name.length, @@ -365,10 +365,10 @@ abstract class InferenceVisitorBase implements InferenceVisitor { for (VariableDeclaration declaration in target.function.namedParameters) { declaration.type ??= const InvalidType(); }*/ - } else if ((constructor = engine.toBeInferred[target]) != null) { + } else if ((constructorBuilder = engine.toBeInferred[target]) != null) { engine.toBeInferred.remove(target); - engine.beingInferred[target] = constructor!; - constructor.inferFormalTypes(hierarchyBuilder); + engine.beingInferred[target] = constructorBuilder!; + constructorBuilder.inferFormalTypes(hierarchyBuilder); engine.beingInferred.remove(target); } } diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart index 101552cde20..9e99a3b1f56 100644 --- a/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart +++ b/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart @@ -155,14 +155,14 @@ abstract class TypeInferenceEngine { /// This is represented as a map from a constructor to its library /// builder because the builder is used to report errors due to cyclic /// inference dependencies. - final Map toBeInferred = {}; + final Map toBeInferred = {}; /// A map containing constructors in the process of being inferred. /// /// This is used to detect cyclic inference dependencies. It is represented /// as a map from a constructor to its library builder because the builder /// is used to report errors. - final Map beingInferred = {}; + final Map beingInferred = {}; final Map typeDependencies = {}; diff --git a/pkg/front_end/testcases/general/issue42435.dart b/pkg/front_end/testcases/general/issue42435.dart index f49f06882e1..a4ba1049fff 100644 --- a/pkg/front_end/testcases/general/issue42435.dart +++ b/pkg/front_end/testcases/general/issue42435.dart @@ -27,6 +27,7 @@ extension E on int { Function() baz3() => throw 42; Function() get baz4 => throw 42; void set baz5(Function() a) {} + static Function() baz6 = (() => throw 42)(); } main() {} diff --git a/pkg/front_end/testcases/general/issue42435.dart.textual_outline.expect b/pkg/front_end/testcases/general/issue42435.dart.textual_outline.expect index 2e817488e9f..c2e98fb063b 100644 --- a/pkg/front_end/testcases/general/issue42435.dart.textual_outline.expect +++ b/pkg/front_end/testcases/general/issue42435.dart.textual_outline.expect @@ -23,6 +23,7 @@ extension E on int { Function() baz3() => throw 42; Function() get baz4 => throw 42; void set baz5(Function() a) {} + static Function() baz6 = (() => throw 42)(); } main() {} diff --git a/pkg/front_end/testcases/general/issue42435.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/issue42435.dart.textual_outline_modelled.expect index c61aa8e4530..00fa9d80c8f 100644 --- a/pkg/front_end/testcases/general/issue42435.dart.textual_outline_modelled.expect +++ b/pkg/front_end/testcases/general/issue42435.dart.textual_outline_modelled.expect @@ -19,6 +19,7 @@ extension E on int { Function() baz3() => throw 42; Function() get baz4 => throw 42; baz2(Function() a) {} + static Function() baz6 = (() => throw 42)(); void set baz5(Function() a) {} } diff --git a/pkg/front_end/testcases/general/issue42435.dart.weak.expect b/pkg/front_end/testcases/general/issue42435.dart.weak.expect index 3dd8dc5c156..32b859a4db3 100644 --- a/pkg/front_end/testcases/general/issue42435.dart.weak.expect +++ b/pkg/front_end/testcases/general/issue42435.dart.weak.expect @@ -122,6 +122,14 @@ library /*isNonNullableByDefault*/; // class A> {} // ^ // +// pkg/front_end/testcases/general/issue42435.dart:30:19: Error: Generic type 'A' can't be used without type arguments in a type variable bound. +// Try providing type arguments to 'A' here. +// static Function() baz6 = (() => throw 42)(); +// ^ +// pkg/front_end/testcases/general/issue42435.dart:5:9: Context: Bound of this variable references variable 'X' from the same declaration. +// class A> {} +// ^ +// // pkg/front_end/testcases/general/issue42435.dart:29:26: Error: Generic type 'A' can't be used without type arguments in a type variable bound. // Try providing type arguments to 'A' here. // void set baz5(Function() a) {} @@ -168,9 +176,11 @@ extension E on core::int { method baz3 = self::E|baz3; tearoff baz3 = self::E|get#baz3; get baz4 = self::E|get#baz4; + static field baz6 = self::E|baz6; set baz5 = self::E|set#baz5; } static field > = dynamic>() → dynamic bar6 = let final Never #t2 = (() → Never => throw 42)(){() → Never} in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`."); +static field > = dynamic>() → dynamic E|baz6 = let final Never #t3 = (() → Never => throw 42)(){() → Never} in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`."); static method bar2(> = dynamic>() → dynamic a) → dynamic {} static method bar3() → > = dynamic>() → dynamic return throw 42; diff --git a/pkg/front_end/testcases/general/issue42435.dart.weak.modular.expect b/pkg/front_end/testcases/general/issue42435.dart.weak.modular.expect index 3dd8dc5c156..32b859a4db3 100644 --- a/pkg/front_end/testcases/general/issue42435.dart.weak.modular.expect +++ b/pkg/front_end/testcases/general/issue42435.dart.weak.modular.expect @@ -122,6 +122,14 @@ library /*isNonNullableByDefault*/; // class A> {} // ^ // +// pkg/front_end/testcases/general/issue42435.dart:30:19: Error: Generic type 'A' can't be used without type arguments in a type variable bound. +// Try providing type arguments to 'A' here. +// static Function() baz6 = (() => throw 42)(); +// ^ +// pkg/front_end/testcases/general/issue42435.dart:5:9: Context: Bound of this variable references variable 'X' from the same declaration. +// class A> {} +// ^ +// // pkg/front_end/testcases/general/issue42435.dart:29:26: Error: Generic type 'A' can't be used without type arguments in a type variable bound. // Try providing type arguments to 'A' here. // void set baz5(Function() a) {} @@ -168,9 +176,11 @@ extension E on core::int { method baz3 = self::E|baz3; tearoff baz3 = self::E|get#baz3; get baz4 = self::E|get#baz4; + static field baz6 = self::E|baz6; set baz5 = self::E|set#baz5; } static field > = dynamic>() → dynamic bar6 = let final Never #t2 = (() → Never => throw 42)(){() → Never} in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`."); +static field > = dynamic>() → dynamic E|baz6 = let final Never #t3 = (() → Never => throw 42)(){() → Never} in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`."); static method bar2(> = dynamic>() → dynamic a) → dynamic {} static method bar3() → > = dynamic>() → dynamic return throw 42; diff --git a/pkg/front_end/testcases/general/issue42435.dart.weak.outline.expect b/pkg/front_end/testcases/general/issue42435.dart.weak.outline.expect index 90c287fef5d..9a15fd50b7d 100644 --- a/pkg/front_end/testcases/general/issue42435.dart.weak.outline.expect +++ b/pkg/front_end/testcases/general/issue42435.dart.weak.outline.expect @@ -122,6 +122,14 @@ library /*isNonNullableByDefault*/; // class A> {} // ^ // +// pkg/front_end/testcases/general/issue42435.dart:30:19: Error: Generic type 'A' can't be used without type arguments in a type variable bound. +// Try providing type arguments to 'A' here. +// static Function() baz6 = (() => throw 42)(); +// ^ +// pkg/front_end/testcases/general/issue42435.dart:5:9: Context: Bound of this variable references variable 'X' from the same declaration. +// class A> {} +// ^ +// // pkg/front_end/testcases/general/issue42435.dart:29:26: Error: Generic type 'A' can't be used without type arguments in a type variable bound. // Try providing type arguments to 'A' here. // void set baz5(Function() a) {} @@ -167,9 +175,11 @@ extension E on core::int { method baz3 = self::E|baz3; tearoff baz3 = self::E|get#baz3; get baz4 = self::E|get#baz4; + static field baz6 = self::E|baz6; set baz5 = self::E|set#baz5; } static field > = dynamic>() → dynamic bar6; +static field > = dynamic>() → dynamic E|baz6; static method bar2(> = dynamic>() → dynamic a) → dynamic ; static method bar3() → > = dynamic>() → dynamic diff --git a/pkg/front_end/testcases/general/issue42435.dart.weak.transformed.expect b/pkg/front_end/testcases/general/issue42435.dart.weak.transformed.expect index 3dd8dc5c156..32b859a4db3 100644 --- a/pkg/front_end/testcases/general/issue42435.dart.weak.transformed.expect +++ b/pkg/front_end/testcases/general/issue42435.dart.weak.transformed.expect @@ -122,6 +122,14 @@ library /*isNonNullableByDefault*/; // class A> {} // ^ // +// pkg/front_end/testcases/general/issue42435.dart:30:19: Error: Generic type 'A' can't be used without type arguments in a type variable bound. +// Try providing type arguments to 'A' here. +// static Function() baz6 = (() => throw 42)(); +// ^ +// pkg/front_end/testcases/general/issue42435.dart:5:9: Context: Bound of this variable references variable 'X' from the same declaration. +// class A> {} +// ^ +// // pkg/front_end/testcases/general/issue42435.dart:29:26: Error: Generic type 'A' can't be used without type arguments in a type variable bound. // Try providing type arguments to 'A' here. // void set baz5(Function() a) {} @@ -168,9 +176,11 @@ extension E on core::int { method baz3 = self::E|baz3; tearoff baz3 = self::E|get#baz3; get baz4 = self::E|get#baz4; + static field baz6 = self::E|baz6; set baz5 = self::E|set#baz5; } static field > = dynamic>() → dynamic bar6 = let final Never #t2 = (() → Never => throw 42)(){() → Never} in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`."); +static field > = dynamic>() → dynamic E|baz6 = let final Never #t3 = (() → Never => throw 42)(){() → Never} in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`."); static method bar2(> = dynamic>() → dynamic a) → dynamic {} static method bar3() → > = dynamic>() → dynamic return throw 42; diff --git a/pkg/front_end/testcases/textual_outline.status b/pkg/front_end/testcases/textual_outline.status index b7c936de37f..5c25f227389 100644 --- a/pkg/front_end/testcases/textual_outline.status +++ b/pkg/front_end/testcases/textual_outline.status @@ -215,6 +215,7 @@ variance/class_type_parameter_modifier: FormatterCrash variance/generic_covariance_sound_variance: FormatterCrash variance/mixin_type_parameter_modifier: FormatterCrash variance/unconstrained_inference: FormatterCrash +views/constructors: FormatterCrash views/procedures: FormatterCrash views/representation: FormatterCrash views/view_class_declaration: FormatterCrash diff --git a/pkg/front_end/testcases/views/constructors.dart b/pkg/front_end/testcases/views/constructors.dart new file mode 100644 index 00000000000..c7fd0a50c25 --- /dev/null +++ b/pkg/front_end/testcases/views/constructors.dart @@ -0,0 +1,15 @@ +// Copyright (c) 2022, 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. + +view class Class1 { + final int field; + + Class1(this.field); +} + +view class Class2 { + final int field; + + Class2(this.field); +} diff --git a/pkg/front_end/testcases/views/constructors.dart.strong.expect b/pkg/front_end/testcases/views/constructors.dart.strong.expect new file mode 100644 index 00000000000..2bf42e376d9 --- /dev/null +++ b/pkg/front_end/testcases/views/constructors.dart.strong.expect @@ -0,0 +1,14 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; + +view Class1 /* representationType = core::int */ { + constructor • = self::Class1|; +} +view Class2 /* representationType = core::int */ { + constructor • = self::Class2|; +} +method Class1|(core::int field) → self::Class1 + ; +method Class2|(core::int field) → self::Class2 + ; diff --git a/pkg/front_end/testcases/views/constructors.dart.strong.transformed.expect b/pkg/front_end/testcases/views/constructors.dart.strong.transformed.expect new file mode 100644 index 00000000000..2bf42e376d9 --- /dev/null +++ b/pkg/front_end/testcases/views/constructors.dart.strong.transformed.expect @@ -0,0 +1,14 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; + +view Class1 /* representationType = core::int */ { + constructor • = self::Class1|; +} +view Class2 /* representationType = core::int */ { + constructor • = self::Class2|; +} +method Class1|(core::int field) → self::Class1 + ; +method Class2|(core::int field) → self::Class2 + ; diff --git a/pkg/front_end/testcases/views/constructors.dart.textual_outline.expect b/pkg/front_end/testcases/views/constructors.dart.textual_outline.expect new file mode 100644 index 00000000000..372f90542f0 --- /dev/null +++ b/pkg/front_end/testcases/views/constructors.dart.textual_outline.expect @@ -0,0 +1,10 @@ +view +class Class1 { + final int field; + Class1(this.field); +} +view +class Class2 { + final int field; + Class2(this.field); +} diff --git a/pkg/front_end/testcases/views/constructors.dart.weak.expect b/pkg/front_end/testcases/views/constructors.dart.weak.expect new file mode 100644 index 00000000000..2bf42e376d9 --- /dev/null +++ b/pkg/front_end/testcases/views/constructors.dart.weak.expect @@ -0,0 +1,14 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; + +view Class1 /* representationType = core::int */ { + constructor • = self::Class1|; +} +view Class2 /* representationType = core::int */ { + constructor • = self::Class2|; +} +method Class1|(core::int field) → self::Class1 + ; +method Class2|(core::int field) → self::Class2 + ; diff --git a/pkg/front_end/testcases/views/constructors.dart.weak.modular.expect b/pkg/front_end/testcases/views/constructors.dart.weak.modular.expect new file mode 100644 index 00000000000..2bf42e376d9 --- /dev/null +++ b/pkg/front_end/testcases/views/constructors.dart.weak.modular.expect @@ -0,0 +1,14 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; + +view Class1 /* representationType = core::int */ { + constructor • = self::Class1|; +} +view Class2 /* representationType = core::int */ { + constructor • = self::Class2|; +} +method Class1|(core::int field) → self::Class1 + ; +method Class2|(core::int field) → self::Class2 + ; diff --git a/pkg/front_end/testcases/views/constructors.dart.weak.outline.expect b/pkg/front_end/testcases/views/constructors.dart.weak.outline.expect new file mode 100644 index 00000000000..2bf42e376d9 --- /dev/null +++ b/pkg/front_end/testcases/views/constructors.dart.weak.outline.expect @@ -0,0 +1,14 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; + +view Class1 /* representationType = core::int */ { + constructor • = self::Class1|; +} +view Class2 /* representationType = core::int */ { + constructor • = self::Class2|; +} +method Class1|(core::int field) → self::Class1 + ; +method Class2|(core::int field) → self::Class2 + ; diff --git a/pkg/front_end/testcases/views/constructors.dart.weak.transformed.expect b/pkg/front_end/testcases/views/constructors.dart.weak.transformed.expect new file mode 100644 index 00000000000..2bf42e376d9 --- /dev/null +++ b/pkg/front_end/testcases/views/constructors.dart.weak.transformed.expect @@ -0,0 +1,14 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; + +view Class1 /* representationType = core::int */ { + constructor • = self::Class1|; +} +view Class2 /* representationType = core::int */ { + constructor • = self::Class2|; +} +method Class1|(core::int field) → self::Class1 + ; +method Class2|(core::int field) → self::Class2 + ;