| // Copyright (c) 2019, 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:_fe_analyzer_shared/src/scanner/token.dart' show Token; |
| import 'package:kernel/ast.dart'; |
| import 'package:kernel/class_hierarchy.dart'; |
| import 'package:kernel/type_algebra.dart'; |
| |
| import '../builder/builder.dart'; |
| import '../builder/class_builder.dart'; |
| import '../builder/constructor_builder.dart'; |
| import '../builder/field_builder.dart'; |
| import '../builder/formal_parameter_builder.dart'; |
| import '../builder/library_builder.dart'; |
| import '../builder/member_builder.dart'; |
| import '../builder/metadata_builder.dart'; |
| import '../builder/named_type_builder.dart'; |
| import '../builder/type_alias_builder.dart'; |
| import '../builder/type_builder.dart'; |
| import '../builder/type_declaration_builder.dart'; |
| import '../builder/type_variable_builder.dart'; |
| import '../constant_context.dart' show ConstantContext; |
| import '../dill/dill_member_builder.dart'; |
| import '../kernel/body_builder.dart' show BodyBuilder; |
| import '../kernel/constructor_tearoff_lowering.dart'; |
| import '../kernel/expression_generator_helper.dart' |
| show ExpressionGeneratorHelper; |
| import '../kernel/hierarchy/class_member.dart' show ClassMember; |
| import '../kernel/kernel_helper.dart' show SynthesizedFunctionNode; |
| import '../kernel/utils.dart' |
| show isRedirectingGenerativeConstructorImplementation; |
| import '../messages.dart' |
| show |
| Message, |
| messageMoreThanOneSuperInitializer, |
| messageRedirectingConstructorWithAnotherInitializer, |
| messageRedirectingConstructorWithMultipleRedirectInitializers, |
| messageRedirectingConstructorWithSuperInitializer, |
| messageSuperInitializerNotLast, |
| noLength; |
| import '../source/source_class_builder.dart'; |
| import '../source/source_library_builder.dart' show SourceLibraryBuilder; |
| import '../source/source_loader.dart' show SourceLoader; |
| import '../source/source_member_builder.dart'; |
| import '../type_inference/type_inferrer.dart'; |
| import '../type_inference/type_schema.dart'; |
| import '../util/helpers.dart' show DelayedActionPerformer; |
| import 'source_function_builder.dart'; |
| |
| class SourceConstructorBuilder extends FunctionBuilderImpl |
| implements ConstructorBuilder { |
| final Constructor _constructor; |
| final Procedure? _constructorTearOff; |
| |
| Set<FieldBuilder>? _initializedFields; |
| |
| final int charOpenParenOffset; |
| |
| bool hasMovedSuperInitializer = false; |
| |
| SuperInitializer? superInitializer; |
| |
| RedirectingInitializer? redirectingInitializer; |
| |
| Token? beginInitializers; |
| |
| SourceConstructorBuilder? actualOrigin; |
| |
| Constructor get actualConstructor => _constructor; |
| |
| bool _hasFormalsInferred = false; |
| |
| final bool _hasSuperInitializingFormals; |
| |
| final List<SynthesizedFunctionNode> _superParameterDefaultValueCloners = |
| <SynthesizedFunctionNode>[]; |
| |
| SourceConstructorBuilder( |
| List<MetadataBuilder>? metadata, |
| int modifiers, |
| TypeBuilder? returnType, |
| String name, |
| List<TypeVariableBuilder>? typeVariables, |
| List<FormalParameterBuilder>? formals, |
| SourceLibraryBuilder compilationUnit, |
| int startCharOffset, |
| int charOffset, |
| this.charOpenParenOffset, |
| int charEndOffset, |
| Reference? constructorReference, |
| Reference? tearOffReference, |
| {String? nativeMethodName, |
| required bool forAbstractClassOrEnum}) |
| : _constructor = new Constructor(new FunctionNode(null), |
| name: new Name(name, compilationUnit.library), |
| fileUri: compilationUnit.fileUri, |
| reference: constructorReference) |
| ..startFileOffset = startCharOffset |
| ..fileOffset = charOffset |
| ..fileEndOffset = charEndOffset |
| ..isNonNullableByDefault = compilationUnit.isNonNullableByDefault, |
| _constructorTearOff = createConstructorTearOffProcedure( |
| name, |
| compilationUnit, |
| compilationUnit.fileUri, |
| charOffset, |
| tearOffReference, |
| forAbstractClassOrEnum: forAbstractClassOrEnum), |
| _hasSuperInitializingFormals = |
| formals?.any((formal) => formal.isSuperInitializingFormal) ?? false, |
| super(metadata, modifiers, returnType, name, typeVariables, formals, |
| compilationUnit, charOffset, nativeMethodName); |
| |
| @override |
| SourceLibraryBuilder get library => super.library as SourceLibraryBuilder; |
| |
| @override |
| SourceClassBuilder get classBuilder => |
| super.classBuilder as SourceClassBuilder; |
| |
| @override |
| Member? get readTarget => _constructorTearOff ?? _constructor; |
| |
| @override |
| Member? get writeTarget => null; |
| |
| @override |
| Member get invokeTarget => constructor; |
| |
| @override |
| FunctionNode get function => _constructor.function; |
| |
| @override |
| Iterable<Member> get exportedMembers => [constructor]; |
| |
| @override |
| SourceConstructorBuilder get origin => actualOrigin ?? this; |
| |
| ConstructorBuilder? get patchForTesting => |
| dataForTesting?.patchForTesting as ConstructorBuilder?; |
| |
| @override |
| bool get isDeclarationInstanceMember => false; |
| |
| @override |
| bool get isClassInstanceMember => false; |
| |
| @override |
| bool get isConstructor => true; |
| |
| @override |
| AsyncMarker get asyncModifier => AsyncMarker.Sync; |
| |
| @override |
| ProcedureKind? get kind => null; |
| |
| @override |
| bool get isRedirectingGenerativeConstructor { |
| return isRedirectingGenerativeConstructorImplementation(_constructor); |
| } |
| |
| @override |
| void buildMembers( |
| SourceLibraryBuilder library, void Function(Member, BuiltMemberKind) f) { |
| Member member = build(library); |
| f(member, BuiltMemberKind.Constructor); |
| if (_constructorTearOff != null) { |
| f(_constructorTearOff!, BuiltMemberKind.Method); |
| } |
| } |
| |
| bool _hasBeenBuilt = false; |
| |
| @override |
| Constructor build(SourceLibraryBuilder libraryBuilder) { |
| if (!_hasBeenBuilt) { |
| buildFunction(libraryBuilder); |
| _constructor.function.fileOffset = charOpenParenOffset; |
| _constructor.function.fileEndOffset = _constructor.fileEndOffset; |
| _constructor.function.typeParameters = const <TypeParameter>[]; |
| _constructor.isConst = isConst; |
| _constructor.isExternal = isExternal; |
| updatePrivateMemberName(_constructor, libraryBuilder); |
| |
| if (_constructorTearOff != null) { |
| buildConstructorTearOffProcedure(_constructorTearOff!, _constructor, |
| classBuilder.cls, libraryBuilder); |
| } |
| |
| _hasBeenBuilt = true; |
| } |
| if (formals != null) { |
| bool needsInference = false; |
| for (FormalParameterBuilder formal in formals!) { |
| if (formal.type == null && |
| (formal.isInitializingFormal || formal.isSuperInitializingFormal)) { |
| formal.variable!.type = const UnknownType(); |
| needsInference = true; |
| } |
| } |
| if (needsInference) { |
| assert( |
| library == libraryBuilder, |
| "Unexpected library builder ${libraryBuilder} for" |
| " constructor $this in ${library}."); |
| libraryBuilder.loader |
| .registerConstructorToBeInferred(_constructor, this); |
| } |
| } |
| return _constructor; |
| } |
| |
| /// Infers the types of any untyped initializing formals. |
| void inferFormalTypes(ClassHierarchy classHierarchy) { |
| if (_hasFormalsInferred) return; |
| if (formals != null) { |
| for (FormalParameterBuilder formal in formals!) { |
| if (formal.type == null) { |
| if (formal.isInitializingFormal) { |
| formal.finalizeInitializingFormal(classBuilder); |
| } |
| } |
| } |
| |
| if (_hasSuperInitializingFormals) { |
| if (beginInitializers != null) { |
| BodyBuilder bodyBuilder = library.loader |
| .createBodyBuilderForOutlineExpression( |
| library, classBuilder, this, classBuilder.scope, fileUri); |
| bodyBuilder.constantContext = ConstantContext.required; |
| bodyBuilder.parseInitializers(beginInitializers!, |
| doFinishConstructor: false); |
| } |
| finalizeSuperInitializingFormals( |
| classHierarchy, _superParameterDefaultValueCloners); |
| } |
| } |
| _hasFormalsInferred = true; |
| } |
| |
| /* ConstructorBuilder | DillConstructorBuilder */ |
| Object? _computeSuperTargetBuilder() { |
| Constructor superTarget; |
| ClassBuilder superclassBuilder; |
| |
| TypeBuilder? supertype = classBuilder.supertypeBuilder; |
| if (supertype is NamedTypeBuilder) { |
| TypeDeclarationBuilder? declaration = supertype.declaration; |
| if (declaration is ClassBuilder) { |
| superclassBuilder = declaration; |
| } else if (declaration is TypeAliasBuilder) { |
| declaration = declaration.unaliasDeclaration(supertype.arguments); |
| if (declaration is ClassBuilder) { |
| superclassBuilder = declaration; |
| } else { |
| // The error in this case should be reported elsewhere. |
| return null; |
| } |
| } else { |
| // The error in this case should be reported elsewhere. |
| return null; |
| } |
| } else { |
| // The error in this case should be reported elsewhere. |
| return null; |
| } |
| |
| if (constructor.initializers.isNotEmpty && |
| constructor.initializers.last is SuperInitializer) { |
| superTarget = (constructor.initializers.last as SuperInitializer).target; |
| } else { |
| MemberBuilder? memberBuilder = superclassBuilder.constructors |
| .lookup("", charOffset, library.fileUri); |
| if (memberBuilder is ConstructorBuilder) { |
| superTarget = memberBuilder.constructor; |
| } else if (memberBuilder is DillConstructorBuilder) { |
| superTarget = memberBuilder.constructor; |
| } else { |
| // The error in this case should be reported elsewhere. |
| return null; |
| } |
| } |
| |
| MemberBuilder? constructorBuilder = |
| superclassBuilder.findConstructorOrFactory( |
| superTarget.name.text, charOffset, library.fileUri, library); |
| return constructorBuilder is ConstructorBuilder || |
| constructorBuilder is DillConstructorBuilder |
| ? constructorBuilder |
| : null; |
| } |
| |
| void finalizeSuperInitializingFormals(ClassHierarchy classHierarchy, |
| List<SynthesizedFunctionNode> synthesizedFunctionNodes) { |
| if (formals == null) return; |
| if (!_hasSuperInitializingFormals) return; |
| |
| void performRecoveryForErroneousCase() { |
| for (FormalParameterBuilder formal in formals!) { |
| if (formal.isSuperInitializingFormal) { |
| formal.variable!.type = const DynamicType(); |
| } |
| } |
| } |
| |
| Object? superTargetBuilder = _computeSuperTargetBuilder(); |
| Constructor superTarget; |
| List<FormalParameterBuilder>? superFormals; |
| if (superTargetBuilder is SourceConstructorBuilder) { |
| superTarget = superTargetBuilder.constructor; |
| superFormals = superTargetBuilder.formals!; |
| } else if (superTargetBuilder is DillConstructorBuilder) { |
| superTarget = superTargetBuilder.constructor; |
| if (superTargetBuilder is SyntheticConstructorBuilder) { |
| superFormals = superTargetBuilder.formals; |
| } else { |
| // The error in this case should be reported elsewhere. Here we perform |
| // a simple recovery. |
| return performRecoveryForErroneousCase(); |
| } |
| } else { |
| // The error in this case should be reported elsewhere. Here we perform a |
| // simple recovery. |
| return performRecoveryForErroneousCase(); |
| } |
| |
| if (superFormals == null) { |
| // The error in this case should be reported elsewhere. Here we perform a |
| // simple recovery. |
| return performRecoveryForErroneousCase(); |
| } |
| |
| if (superTargetBuilder is SourceConstructorBuilder) { |
| superTargetBuilder.inferFormalTypes(classHierarchy); |
| } else if (superTargetBuilder is SyntheticConstructorBuilder) { |
| MemberBuilder? superTargetOriginBuilder = superTargetBuilder.actualOrigin; |
| if (superTargetOriginBuilder is SourceConstructorBuilder) { |
| superTargetOriginBuilder.inferFormalTypes(classHierarchy); |
| } |
| } |
| |
| int superInitializingFormalIndex = -1; |
| List<int>? positionalSuperParameters; |
| List<String>? namedSuperParameters; |
| |
| Supertype? supertype = classHierarchy.getClassAsInstanceOf( |
| classBuilder.cls, superTarget.enclosingClass); |
| assert(supertype != null); |
| Map<TypeParameter, DartType> substitution = |
| new Map<TypeParameter, DartType>.fromIterables( |
| supertype!.classNode.typeParameters, supertype.typeArguments); |
| |
| for (int formalIndex = 0; formalIndex < formals!.length; formalIndex++) { |
| FormalParameterBuilder formal = formals![formalIndex]; |
| if (formal.isSuperInitializingFormal) { |
| superInitializingFormalIndex++; |
| bool hasImmediatelyDeclaredInitializer = formal.hasDeclaredInitializer; |
| if (formal.type == null) { |
| DartType? type; |
| |
| if (formal.isPositional) { |
| if (superInitializingFormalIndex < superFormals.length) { |
| FormalParameterBuilder correspondingSuperFormal = |
| superFormals[superInitializingFormalIndex]; |
| formal.hasDeclaredInitializer = |
| hasImmediatelyDeclaredInitializer || |
| correspondingSuperFormal.hasDeclaredInitializer; |
| if (!hasImmediatelyDeclaredInitializer) { |
| (positionalSuperParameters ??= <int>[]).add(formalIndex); |
| } |
| type = correspondingSuperFormal.variable!.type; |
| } else { |
| // TODO(cstefantsova): Report an error. |
| } |
| } else { |
| FormalParameterBuilder? correspondingSuperFormal; |
| for (FormalParameterBuilder superFormal in superFormals) { |
| if (superFormal.isNamed && superFormal.name == formal.name) { |
| correspondingSuperFormal = superFormal; |
| break; |
| } |
| } |
| |
| if (correspondingSuperFormal != null) { |
| formal.hasDeclaredInitializer = |
| hasImmediatelyDeclaredInitializer || |
| correspondingSuperFormal.hasDeclaredInitializer; |
| if (!hasImmediatelyDeclaredInitializer) { |
| (namedSuperParameters ??= <String>[]).add(formal.name); |
| } |
| type = correspondingSuperFormal.variable!.type; |
| } else { |
| // TODO(cstefantsova): Report an error. |
| } |
| } |
| |
| if (substitution.isNotEmpty && type != null) { |
| type = substitute(type, substitution); |
| } |
| formal.variable!.type = type ?? const DynamicType(); |
| } else { |
| formal.variable!.type = const DynamicType(); |
| } |
| } |
| } |
| |
| if (positionalSuperParameters != null || namedSuperParameters != null) { |
| synthesizedFunctionNodes.add(new SynthesizedFunctionNode( |
| substitution, superTarget.function, constructor.function, |
| positionalSuperParameters: positionalSuperParameters ?? const <int>[], |
| namedSuperParameters: namedSuperParameters ?? const <String>[], |
| isOutlineNode: true)); |
| } |
| } |
| |
| bool _hasBuiltOutlines = false; |
| |
| @override |
| void buildOutlineExpressions( |
| SourceLibraryBuilder library, |
| ClassHierarchy classHierarchy, |
| List<DelayedActionPerformer> delayedActionPerformers, |
| List<SynthesizedFunctionNode> synthesizedFunctionNodes) { |
| if (_hasBuiltOutlines) return; |
| if (isConst && isPatch) { |
| origin.buildOutlineExpressions(library, classHierarchy, |
| delayedActionPerformers, synthesizedFunctionNodes); |
| } |
| super.buildOutlineExpressions(library, classHierarchy, |
| delayedActionPerformers, synthesizedFunctionNodes); |
| |
| // 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) && |
| beginInitializers != null) { |
| BodyBuilder bodyBuilder = library.loader |
| .createBodyBuilderForOutlineExpression( |
| library, classBuilder, this, classBuilder.scope, fileUri); |
| bodyBuilder.constantContext = ConstantContext.required; |
| bodyBuilder.parseInitializers(beginInitializers!, |
| doFinishConstructor: isConst); |
| bodyBuilder.performBacklogComputations(delayedActionPerformers); |
| } |
| beginInitializers = null; |
| addSuperParameterDefaultValueCloners(synthesizedFunctionNodes); |
| if (isConst && isPatch) { |
| _finishPatch(); |
| } |
| _hasBuiltOutlines = true; |
| } |
| |
| void addSuperParameterDefaultValueCloners( |
| List<SynthesizedFunctionNode> synthesizedFunctionNodes) { |
| Object? superTargetBuilder = _computeSuperTargetBuilder(); |
| if (superTargetBuilder is SourceConstructorBuilder) { |
| superTargetBuilder |
| .addSuperParameterDefaultValueCloners(synthesizedFunctionNodes); |
| } else if (superTargetBuilder is SyntheticConstructorBuilder) { |
| superTargetBuilder |
| .addSuperParameterDefaultValueCloners(synthesizedFunctionNodes); |
| } |
| synthesizedFunctionNodes.addAll(_superParameterDefaultValueCloners); |
| _superParameterDefaultValueCloners.clear(); |
| } |
| |
| @override |
| void buildFunction(SourceLibraryBuilder library) { |
| // According to the specification §9.3 the return type of a constructor |
| // function is its enclosing class. |
| super.buildFunction(library); |
| Class enclosingClass = classBuilder.cls; |
| List<DartType> typeParameterTypes = <DartType>[]; |
| for (int i = 0; i < enclosingClass.typeParameters.length; i++) { |
| TypeParameter typeParameter = enclosingClass.typeParameters[i]; |
| typeParameterTypes.add( |
| new TypeParameterType.withDefaultNullabilityForLibrary( |
| typeParameter, library.library)); |
| } |
| function.returnType = new InterfaceType( |
| enclosingClass, library.nonNullable, typeParameterTypes); |
| } |
| |
| @override |
| Constructor get constructor => isPatch ? origin.constructor : _constructor; |
| |
| @override |
| Member get member => constructor; |
| |
| void injectInvalidInitializer(Message message, int charOffset, int length, |
| ExpressionGeneratorHelper helper) { |
| List<Initializer> 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<Initializer> 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); |
| initializers.add(initializer..parent = _constructor); |
| superInitializer = initializer; |
| } |
| } 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); |
| initializers.add(initializer..parent = _constructor); |
| redirectingInitializer = initializer; |
| } |
| } 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) { |
| 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 _finishPatch() { |
| // TODO(ahe): restore file-offset once we track both origin and patch file |
| // URIs. See https://github.com/dart-lang/sdk/issues/31579 |
| origin.constructor.fileUri = fileUri; |
| origin.constructor.startFileOffset = _constructor.startFileOffset; |
| origin.constructor.fileOffset = _constructor.fileOffset; |
| origin.constructor.fileEndOffset = _constructor.fileEndOffset; |
| origin.constructor.annotations |
| .forEach((m) => m.fileOffset = _constructor.fileOffset); |
| |
| origin.constructor.isExternal = _constructor.isExternal; |
| origin.constructor.function = _constructor.function; |
| origin.constructor.function.parent = origin.constructor; |
| origin.constructor.initializers = _constructor.initializers; |
| setParents(origin.constructor.initializers, origin.constructor); |
| } |
| |
| @override |
| int finishPatch() { |
| if (!isPatch) return 0; |
| _finishPatch(); |
| return 1; |
| } |
| |
| @override |
| void becomeNative(SourceLoader loader) { |
| _constructor.isExternal = true; |
| super.becomeNative(loader); |
| } |
| |
| @override |
| void applyPatch(Builder patch) { |
| if (patch is SourceConstructorBuilder) { |
| if (checkPatch(patch)) { |
| patch.actualOrigin = this; |
| dataForTesting?.patchForTesting = patch; |
| } |
| } else { |
| reportPatchMismatch(patch); |
| } |
| } |
| |
| 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; |
| hasMovedSuperInitializer = false; |
| } |
| |
| @override |
| List<ClassMember> get localMembers => |
| throw new UnsupportedError('${runtimeType}.localMembers'); |
| |
| @override |
| List<ClassMember> 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 |
| /// entry in the constructor initializer list. |
| void registerInitializedField(FieldBuilder fieldBuilder) { |
| (_initializedFields ??= {}).add(fieldBuilder); |
| } |
| |
| /// Returns the fields registered as initialized by this constructor. |
| /// |
| /// Returns the set of fields previously registered via |
| /// [registerInitializedField] and passes on the ownership of the collection |
| /// to the caller. |
| Set<FieldBuilder>? takeInitializedFields() { |
| Set<FieldBuilder>? result = _initializedFields; |
| _initializedFields = null; |
| return result; |
| } |
| } |
| |
| class SyntheticConstructorBuilder extends DillConstructorBuilder |
| with SourceMemberBuilderMixin { |
| // TODO(johnniwinther,cstefantsova): Rename [_origin] to avoid the confusion |
| // with patches. |
| // TODO(johnniwinther): Change the type of [_origin] to SourceMemberBuilder |
| // when it's the supertype for both old SourceMemberBuilder and |
| // SyntheticConstructorBuilder. |
| MemberBuilder? _origin; |
| SynthesizedFunctionNode? _synthesizedFunctionNode; |
| |
| SyntheticConstructorBuilder(SourceClassBuilder parent, |
| Constructor constructor, Procedure? constructorTearOff, |
| {MemberBuilder? origin, SynthesizedFunctionNode? synthesizedFunctionNode}) |
| : _origin = origin, |
| _synthesizedFunctionNode = synthesizedFunctionNode, |
| super(constructor, constructorTearOff, parent); |
| |
| // TODO(johnniwinther,cstefantsova): Rename [actualOrigin] to avoid the |
| // confusion with patches. |
| MemberBuilder? get actualOrigin { |
| MemberBuilder? origin = _origin; |
| while (origin is SyntheticConstructorBuilder) { |
| origin = origin._origin; |
| } |
| return origin; |
| } |
| |
| List<FormalParameterBuilder>? get formals { |
| MemberBuilder? origin = actualOrigin; |
| return origin is SourceConstructorBuilder ? origin.formals : null; |
| } |
| |
| @override |
| void buildOutlineExpressions( |
| SourceLibraryBuilder libraryBuilder, |
| ClassHierarchy classHierarchy, |
| List<DelayedActionPerformer> delayedActionPerformers, |
| List<SynthesizedFunctionNode> synthesizedFunctionNodes) { |
| if (_origin != null) { |
| // Ensure that default value expressions have been created for [_origin]. |
| LibraryBuilder originLibraryBuilder = _origin!.library; |
| if (originLibraryBuilder is SourceLibraryBuilder) { |
| // If [_origin] is from a source library, we need to build the default |
| // values and initializers first. |
| MemberBuilder origin = _origin!; |
| if (origin is SourceConstructorBuilder) { |
| origin.buildOutlineExpressions(originLibraryBuilder, classHierarchy, |
| delayedActionPerformers, synthesizedFunctionNodes); |
| } else if (origin is SyntheticConstructorBuilder) { |
| origin.buildOutlineExpressions(originLibraryBuilder, classHierarchy, |
| delayedActionPerformers, synthesizedFunctionNodes); |
| } |
| } |
| addSuperParameterDefaultValueCloners(synthesizedFunctionNodes); |
| _origin = null; |
| } |
| } |
| |
| void addSuperParameterDefaultValueCloners( |
| List<SynthesizedFunctionNode> synthesizedFunctionNodes) { |
| MemberBuilder? origin = _origin; |
| if (origin is SourceConstructorBuilder) { |
| origin.addSuperParameterDefaultValueCloners(synthesizedFunctionNodes); |
| } else if (origin is SyntheticConstructorBuilder) { |
| origin.addSuperParameterDefaultValueCloners(synthesizedFunctionNodes); |
| } |
| if (_synthesizedFunctionNode != null) { |
| synthesizedFunctionNodes |
| .add(_synthesizedFunctionNode!..isOutlineNode = true); |
| _synthesizedFunctionNode = null; |
| } |
| } |
| } |