| // Copyright (c) 2016, 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. |
| |
| library fasta.field_builder; |
| |
| import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' show Token; |
| import 'package:kernel/ast.dart'; |
| import 'package:kernel/class_hierarchy.dart'; |
| import 'package:kernel/core_types.dart'; |
| import 'package:kernel/type_algebra.dart'; |
| import 'package:kernel/type_environment.dart'; |
| |
| import '../api_prototype/lowering_predicates.dart'; |
| import '../base/constant_context.dart' show ConstantContext; |
| import '../base/modifier.dart' show covariantMask, hasInitializerMask, lateMask; |
| import '../base/problems.dart' show internalProblem; |
| import '../base/scope.dart' show LookupScope; |
| import '../builder/declaration_builders.dart'; |
| import '../builder/field_builder.dart'; |
| import '../builder/member_builder.dart'; |
| import '../builder/metadata_builder.dart'; |
| import '../builder/omitted_type_builder.dart'; |
| import '../builder/type_builder.dart'; |
| import '../codes/cfe_codes.dart' show messageInternalProblemAlreadyInitialized; |
| import '../kernel/body_builder.dart' show BodyBuilder; |
| import '../kernel/body_builder_context.dart'; |
| import '../kernel/hierarchy/class_member.dart'; |
| import '../kernel/hierarchy/members_builder.dart'; |
| import '../kernel/implicit_field_type.dart'; |
| import '../kernel/internal_ast.dart'; |
| import '../kernel/kernel_helper.dart'; |
| import '../kernel/late_lowering.dart' as late_lowering; |
| import '../kernel/member_covariance.dart'; |
| import '../source/name_scheme.dart'; |
| import '../source/source_extension_builder.dart'; |
| import '../source/source_library_builder.dart' show SourceLibraryBuilder; |
| import '../type_inference/type_inference_engine.dart' |
| show IncludesTypeParametersNonCovariantly; |
| import 'source_class_builder.dart'; |
| import 'source_extension_type_declaration_builder.dart'; |
| import 'source_member_builder.dart'; |
| |
| class SourceFieldBuilder extends SourceMemberBuilderImpl |
| implements FieldBuilder, InferredTypeListener, Inferable { |
| @override |
| final String name; |
| |
| final MemberName _memberName; |
| |
| @override |
| final int modifiers; |
| |
| late FieldEncoding _fieldEncoding; |
| |
| final List<MetadataBuilder>? metadata; |
| |
| final TypeBuilder type; |
| |
| Token? _constInitializerToken; |
| |
| /// Whether the body of this field has been built. |
| /// |
| /// Constant fields have their initializer built in the outline so we avoid |
| /// building them twice as part of the non-outline build. |
| bool hasBodyBeenBuilt = false; |
| |
| // TODO(johnniwinther): [parent] is not trust-worthy for determining |
| // properties since it is changed after the creation of the builder. For now |
| // we require it has an argument here. A follow-up should clean up the |
| // misuse of parent. |
| @override |
| final bool isTopLevel; |
| |
| final bool isSynthesized; |
| |
| /// If `true`, this field builder is for the field corresponding to an enum |
| /// element. |
| final bool isEnumElement; |
| |
| SourceFieldBuilder( |
| this.metadata, |
| this.type, |
| this.name, |
| this.modifiers, |
| this.isTopLevel, |
| SourceLibraryBuilder libraryBuilder, |
| Uri fileUri, |
| int charOffset, |
| int charEndOffset, |
| NameScheme fieldNameScheme, |
| {Reference? fieldReference, |
| Reference? fieldGetterReference, |
| Reference? fieldSetterReference, |
| Reference? lateIsSetFieldReference, |
| Reference? lateIsSetGetterReference, |
| Reference? lateIsSetSetterReference, |
| Reference? lateGetterReference, |
| Reference? lateSetterReference, |
| Token? initializerToken, |
| Token? constInitializerToken, |
| this.isSynthesized = false, |
| this.isEnumElement = false}) |
| : _constInitializerToken = constInitializerToken, |
| _memberName = fieldNameScheme.getDeclaredName(name), |
| super(libraryBuilder, charOffset) { |
| type.registerInferredTypeListener(this); |
| |
| bool isInstanceMember = fieldNameScheme.isInstanceMember; |
| |
| // If in mixed mode, late lowerings cannot use `null` as a sentinel on |
| // non-nullable fields since they can be assigned from legacy code. |
| late_lowering.IsSetStrategy isSetStrategy = |
| late_lowering.computeIsSetStrategy(libraryBuilder); |
| if (isAbstract || isExternal) { |
| assert(fieldReference == null); |
| assert(lateIsSetFieldReference == null); |
| assert(lateIsSetGetterReference == null); |
| assert(lateIsSetSetterReference == null); |
| assert(lateGetterReference == null); |
| assert(lateSetterReference == null); |
| assert(!isEnumElement, "Unexpected abstract/external enum element"); |
| _fieldEncoding = new AbstractOrExternalFieldEncoding( |
| this, |
| name, |
| fieldNameScheme, |
| fileUri, |
| charOffset, |
| charEndOffset, |
| fieldGetterReference, |
| fieldSetterReference, |
| isAbstract: isAbstract, |
| isExternal: isExternal, |
| isFinal: isFinal, |
| isCovariantByDeclaration: isCovariantByDeclaration); |
| } else if (fieldNameScheme.isExtensionTypeMember && |
| fieldNameScheme.isInstanceMember) { |
| assert(fieldReference == null); |
| assert(fieldSetterReference == null); |
| assert(lateIsSetFieldReference == null); |
| assert(lateIsSetGetterReference == null); |
| assert(lateIsSetSetterReference == null); |
| assert(lateGetterReference == null); |
| assert(lateSetterReference == null); |
| _fieldEncoding = new RepresentationFieldEncoding( |
| this, |
| name, |
| fieldNameScheme, |
| fileUri, |
| charOffset, |
| charEndOffset, |
| fieldGetterReference); |
| } else if (isLate && |
| libraryBuilder.loader.target.backendTarget.isLateFieldLoweringEnabled( |
| hasInitializer: hasInitializer, |
| isFinal: isFinal, |
| isStatic: !isInstanceMember)) { |
| assert(!isEnumElement, "Unexpected late enum element"); |
| if (hasInitializer) { |
| if (isFinal) { |
| _fieldEncoding = new LateFinalFieldWithInitializerEncoding( |
| name, |
| fieldNameScheme, |
| fileUri, |
| charOffset, |
| charEndOffset, |
| fieldReference, |
| fieldGetterReference, |
| fieldSetterReference, |
| lateIsSetFieldReference, |
| lateIsSetGetterReference, |
| lateIsSetSetterReference, |
| lateGetterReference, |
| lateSetterReference, |
| isCovariantByDeclaration, |
| isSetStrategy); |
| } else { |
| _fieldEncoding = new LateFieldWithInitializerEncoding( |
| name, |
| fieldNameScheme, |
| fileUri, |
| charOffset, |
| charEndOffset, |
| fieldReference, |
| fieldGetterReference, |
| fieldSetterReference, |
| lateIsSetFieldReference, |
| lateIsSetGetterReference, |
| lateIsSetSetterReference, |
| lateGetterReference, |
| lateSetterReference, |
| isCovariantByDeclaration, |
| isSetStrategy); |
| } |
| } else { |
| if (isFinal) { |
| _fieldEncoding = new LateFinalFieldWithoutInitializerEncoding( |
| name, |
| fieldNameScheme, |
| fileUri, |
| charOffset, |
| charEndOffset, |
| fieldReference, |
| fieldGetterReference, |
| fieldSetterReference, |
| lateIsSetFieldReference, |
| lateIsSetGetterReference, |
| lateIsSetSetterReference, |
| lateGetterReference, |
| lateSetterReference, |
| isCovariantByDeclaration, |
| isSetStrategy); |
| } else { |
| _fieldEncoding = new LateFieldWithoutInitializerEncoding( |
| name, |
| fieldNameScheme, |
| fileUri, |
| charOffset, |
| charEndOffset, |
| fieldReference, |
| fieldGetterReference, |
| fieldSetterReference, |
| lateIsSetFieldReference, |
| lateIsSetGetterReference, |
| lateIsSetSetterReference, |
| lateGetterReference, |
| lateSetterReference, |
| isCovariantByDeclaration, |
| isSetStrategy); |
| } |
| } |
| } else if (libraryBuilder |
| .loader.target.backendTarget.useStaticFieldLowering && |
| !isInstanceMember && |
| !isConst && |
| hasInitializer) { |
| assert(!isEnumElement, "Unexpected non-const enum element"); |
| if (isFinal) { |
| _fieldEncoding = new LateFinalFieldWithInitializerEncoding( |
| name, |
| fieldNameScheme, |
| fileUri, |
| charOffset, |
| charEndOffset, |
| fieldReference, |
| fieldGetterReference, |
| fieldSetterReference, |
| lateIsSetFieldReference, |
| lateIsSetGetterReference, |
| lateIsSetSetterReference, |
| lateGetterReference, |
| lateSetterReference, |
| isCovariantByDeclaration, |
| isSetStrategy); |
| } else { |
| _fieldEncoding = new LateFieldWithInitializerEncoding( |
| name, |
| fieldNameScheme, |
| fileUri, |
| charOffset, |
| charEndOffset, |
| fieldReference, |
| fieldGetterReference, |
| fieldSetterReference, |
| lateIsSetFieldReference, |
| lateIsSetGetterReference, |
| lateIsSetSetterReference, |
| lateGetterReference, |
| lateSetterReference, |
| isCovariantByDeclaration, |
| isSetStrategy); |
| } |
| } else { |
| assert(lateIsSetFieldReference == null); |
| assert(lateIsSetGetterReference == null); |
| assert(lateIsSetSetterReference == null); |
| assert(lateGetterReference == null); |
| assert(lateSetterReference == null); |
| _fieldEncoding = new RegularFieldEncoding( |
| name, fieldNameScheme, fileUri, charOffset, charEndOffset, |
| isFinal: isFinal, |
| isConst: isConst, |
| isLate: isLate, |
| hasInitializer: hasInitializer, |
| fieldReference: fieldReference, |
| getterReference: fieldGetterReference, |
| setterReference: fieldSetterReference, |
| isEnumElement: isEnumElement); |
| } |
| |
| if (type is InferableTypeBuilder) { |
| if (!hasInitializer && isStatic) { |
| // A static field without type and initializer will always be inferred |
| // to have type `dynamic`. |
| type.registerInferredType(const DynamicType()); |
| } else { |
| // A field with no type and initializer or an instance field without |
| // type and initializer need to have the type inferred. |
| fieldType = |
| new InferredType.fromFieldInitializer(this, initializerToken); |
| type.registerInferable(this); |
| } |
| } |
| } |
| |
| @override |
| Name get memberName => _memberName.name; |
| |
| bool _typeEnsured = false; |
| Set<ClassMember>? _overrideDependencies; |
| |
| void registerOverrideDependency(Set<ClassMember> overriddenMembers) { |
| assert( |
| overriddenMembers.every((overriddenMember) => |
| overriddenMember.declarationBuilder != classBuilder), |
| // Coverage-ignore(suite): Not run. |
| "Unexpected override dependencies for $this: $overriddenMembers"); |
| _overrideDependencies ??= {}; |
| _overrideDependencies!.addAll(overriddenMembers); |
| } |
| |
| void _ensureType(ClassMembersBuilder membersBuilder) { |
| if (_typeEnsured) return; |
| if (_overrideDependencies != null) { |
| membersBuilder.inferFieldType(this, _overrideDependencies!); |
| _overrideDependencies = null; |
| } else { |
| type.build(libraryBuilder, TypeUse.fieldType, |
| hierarchy: membersBuilder.hierarchyBuilder); |
| } |
| _typeEnsured = true; |
| } |
| |
| @override |
| Member get member => _fieldEncoding.field; |
| |
| @override |
| String get debugName => "FieldBuilder"; |
| |
| @override |
| bool get isField => true; |
| |
| bool get isLate => (modifiers & lateMask) != 0; |
| |
| bool get isCovariantByDeclaration => (modifiers & covariantMask) != 0; |
| |
| bool get hasInitializer => (modifiers & hasInitializerMask) != 0; |
| |
| /// Builds the body of this field using [initializer] as the initializer |
| /// expression. |
| void buildBody(CoreTypes coreTypes, Expression? initializer) { |
| assert( |
| !hasBodyBeenBuilt, // Coverage-ignore(suite): Not run. |
| "Body has already been built for $this."); |
| hasBodyBeenBuilt = true; |
| if (!hasInitializer && |
| initializer != null && |
| initializer is! NullLiteral && |
| // Coverage-ignore(suite): Not run. |
| !isConst && |
| // Coverage-ignore(suite): Not run. |
| !isFinal) { |
| internalProblem( |
| messageInternalProblemAlreadyInitialized, charOffset, fileUri); |
| } |
| _fieldEncoding.createBodies(coreTypes, initializer); |
| } |
| |
| /// Builds the field initializers for each field used to encode this field |
| /// using the [fileOffset] for the created nodes and [value] as the initial |
| /// field value. |
| List<Initializer> buildInitializer(int fileOffset, Expression value, |
| {required bool isSynthetic}) { |
| return _fieldEncoding.createInitializer(fileOffset, value, |
| isSynthetic: isSynthetic); |
| } |
| |
| /// Creates the AST node for this field as the default initializer. |
| void buildImplicitDefaultValue() { |
| _fieldEncoding.buildImplicitDefaultValue(); |
| } |
| |
| /// Create the [Initializer] for the implicit initialization of this field |
| /// in a constructor. |
| Initializer buildImplicitInitializer() { |
| return _fieldEncoding.buildImplicitInitializer(); |
| } |
| |
| Initializer buildErroneousInitializer(Expression effect, Expression value, |
| {required int fileOffset}) { |
| return _fieldEncoding.buildErroneousInitializer(effect, value, |
| fileOffset: fileOffset); |
| } |
| |
| @override |
| bool get isAssignable { |
| if (isConst) return false; |
| if (isFinal) { |
| if (isLate) { |
| return !hasInitializer; |
| } |
| return false; |
| } |
| return true; |
| } |
| |
| @override |
| Field get field => _fieldEncoding.field; |
| |
| @override |
| Member get readTarget => _fieldEncoding.readTarget; |
| |
| @override |
| Member? get writeTarget { |
| return isAssignable ? _fieldEncoding.writeTarget : null; |
| } |
| |
| @override |
| Member get invokeTarget => readTarget; |
| |
| @override |
| Iterable<Member> get exportedMembers => _fieldEncoding.exportedMembers; |
| |
| @override |
| void buildOutlineNodes(BuildNodesCallback f) { |
| _build(); |
| _fieldEncoding.registerMembers(libraryBuilder, this, f); |
| } |
| |
| /// Builds the core AST structures for this field as needed for the outline. |
| void _build() { |
| if (type is! InferableTypeBuilder) { |
| fieldType = type.build(libraryBuilder, TypeUse.fieldType); |
| } |
| _fieldEncoding.build(libraryBuilder, this); |
| } |
| |
| @override |
| BodyBuilderContext createBodyBuilderContext( |
| {required bool inOutlineBuildingPhase, |
| required bool inMetadata, |
| required bool inConstFields}) { |
| return new FieldBodyBuilderContext(this, |
| inOutlineBuildingPhase: inOutlineBuildingPhase, |
| inMetadata: inMetadata, |
| inConstFields: inConstFields); |
| } |
| |
| @override |
| Iterable<Annotatable> get annotatables => _fieldEncoding.annotatables; |
| |
| @override |
| void buildOutlineExpressions(ClassHierarchy classHierarchy, |
| List<DelayedDefaultValueCloner> delayedDefaultValueCloners) { |
| for (Annotatable annotatable in annotatables) { |
| MetadataBuilder.buildAnnotations( |
| annotatable, |
| metadata, |
| createBodyBuilderContext( |
| inOutlineBuildingPhase: true, |
| inMetadata: true, |
| inConstFields: false), |
| libraryBuilder, |
| fileUri, |
| declarationBuilder?.scope ?? libraryBuilder.scope); |
| } |
| |
| // For modular compilation we need to include initializers of all const |
| // fields and all non-static final fields in classes with const constructors |
| // into the outline. |
| if ((isConst || |
| (isFinal && |
| !isStatic && |
| isClassMember && |
| classBuilder!.declaresConstConstructor)) && |
| _constInitializerToken != null) { |
| LookupScope scope = declarationBuilder?.scope ?? libraryBuilder.scope; |
| BodyBuilder bodyBuilder = libraryBuilder.loader |
| .createBodyBuilderForOutlineExpression( |
| libraryBuilder, |
| createBodyBuilderContext( |
| inOutlineBuildingPhase: true, |
| inMetadata: false, |
| inConstFields: false), |
| scope, |
| fileUri); |
| bodyBuilder.constantContext = |
| isConst ? ConstantContext.inferred : ConstantContext.required; |
| Expression initializer = bodyBuilder.typeInferrer |
| .inferFieldInitializer(bodyBuilder, fieldType, |
| bodyBuilder.parseFieldInitializer(_constInitializerToken!)) |
| .expression; |
| buildBody(classHierarchy.coreTypes, initializer); |
| bodyBuilder.performBacklogComputations(); |
| } |
| _constInitializerToken = null; |
| } |
| |
| // Coverage-ignore(suite): Not run. |
| bool get hasOutlineExpressionsBuilt => _constInitializerToken == null; |
| |
| DartType get fieldType => _fieldEncoding.type; |
| |
| void set fieldType(DartType value) { |
| _fieldEncoding.type = value; |
| if (!isFinal && !isConst && parent is ClassBuilder) { |
| Class enclosingClass = classBuilder!.cls; |
| if (enclosingClass.typeParameters.isNotEmpty) { |
| IncludesTypeParametersNonCovariantly needsCheckVisitor = |
| new IncludesTypeParametersNonCovariantly( |
| enclosingClass.typeParameters, |
| // We are checking the field type as if it is the type of the |
| // parameter of the implicit setter and this is a contravariant |
| // position. |
| initialVariance: Variance.contravariant); |
| if (value.accept(needsCheckVisitor)) { |
| _fieldEncoding.setGenericCovariantImpl(); |
| } |
| } |
| } |
| } |
| |
| @override |
| void inferTypes(ClassHierarchyBase hierarchy) { |
| inferType(hierarchy); |
| } |
| |
| DartType inferType(ClassHierarchyBase hierarchy) { |
| if (fieldType is! InferredType) { |
| // We have already inferred a type. |
| return fieldType; |
| } |
| |
| return libraryBuilder.loader.withUriForCrashReporting(fileUri, charOffset, |
| () { |
| InferredType implicitFieldType = fieldType as InferredType; |
| DartType inferredType = implicitFieldType.computeType(hierarchy); |
| if (fieldType is InferredType) { |
| // `fieldType` may have changed if a circularity was detected when |
| // [inferredType] was computed. |
| type.registerInferredType(inferredType); |
| |
| IncludesTypeParametersNonCovariantly? needsCheckVisitor; |
| if (parent is ClassBuilder) { |
| Class enclosingClass = classBuilder!.cls; |
| if (enclosingClass.typeParameters.isNotEmpty) { |
| needsCheckVisitor = new IncludesTypeParametersNonCovariantly( |
| enclosingClass.typeParameters, |
| // We are checking the field type as if it is the type of the |
| // parameter of the implicit setter and this is a contravariant |
| // position. |
| initialVariance: Variance.contravariant); |
| } |
| } |
| if (needsCheckVisitor != null) { |
| if (fieldType.accept(needsCheckVisitor)) { |
| _fieldEncoding.setGenericCovariantImpl(); |
| } |
| } |
| } |
| return fieldType; |
| }); |
| } |
| |
| @override |
| void onInferredType(DartType type) { |
| fieldType = type; |
| } |
| |
| DartType get builtType => fieldType; |
| |
| List<ClassMember>? _localMembers; |
| List<ClassMember>? _localSetters; |
| |
| @override |
| List<ClassMember> get localMembers => |
| _localMembers ??= _fieldEncoding.getLocalMembers(this); |
| |
| @override |
| List<ClassMember> get localSetters => |
| _localSetters ??= _fieldEncoding.getLocalSetters(this); |
| |
| @override |
| void checkVariance( |
| SourceClassBuilder sourceClassBuilder, TypeEnvironment typeEnvironment) { |
| sourceClassBuilder.checkVarianceInField( |
| this, typeEnvironment, sourceClassBuilder.cls.typeParameters); |
| } |
| |
| @override |
| void checkTypes( |
| SourceLibraryBuilder library, TypeEnvironment typeEnvironment) { |
| library.checkTypesInField(this, typeEnvironment); |
| } |
| |
| @override |
| int buildBodyNodes(BuildNodesCallback f) { |
| return 0; |
| } |
| } |
| |
| /// Strategy pattern for creating different encodings of a declared field. |
| /// |
| /// This is used to provide lowerings for late fields using synthesized getters |
| /// and setters. |
| abstract class FieldEncoding { |
| /// The type of the declared field. |
| abstract DartType type; |
| |
| /// Creates the bodies needed for the field encoding using [initializer] as |
| /// the declared initializer expression. |
| /// |
| /// This method is not called for fields in outlines unless their are constant |
| /// or part of a const constructor. |
| void createBodies(CoreTypes coreTypes, Expression? initializer); |
| |
| List<Initializer> createInitializer(int fileOffset, Expression value, |
| {required bool isSynthetic}); |
| |
| /// Creates the AST node for this field as the default initializer. |
| void buildImplicitDefaultValue(); |
| |
| /// Create the [Initializer] for the implicit initialization of this field |
| /// in a constructor. |
| Initializer buildImplicitInitializer(); |
| |
| Initializer buildErroneousInitializer(Expression effect, Expression value, |
| {required int fileOffset}); |
| |
| /// Registers that the (implicit) setter associated with this field needs to |
| /// contain a runtime type check to deal with generic covariance. |
| void setGenericCovariantImpl(); |
| |
| /// Returns the field that holds the field value at runtime. |
| Field get field; |
| |
| /// Returns the members that holds the field annotations. |
| Iterable<Annotatable> get annotatables; |
| |
| /// Returns the member used to read the field value. |
| Member get readTarget; |
| |
| /// Returns the member used to write to the field. |
| Member? get writeTarget; |
| |
| /// Returns the generated members that are visible through exports. |
| Iterable<Member> get exportedMembers; |
| |
| /// Creates the members necessary for this field encoding. |
| /// |
| /// This method is called for both outline and full compilation so the created |
| /// members should be without body. The member bodies are created through |
| /// [createBodies]. |
| void build( |
| SourceLibraryBuilder libraryBuilder, SourceFieldBuilder fieldBuilder); |
| |
| /// Calls [f] for each member needed for this field encoding. |
| void registerMembers(SourceLibraryBuilder library, |
| SourceFieldBuilder fieldBuilder, BuildNodesCallback f); |
| |
| /// Returns a list of the field, getters and methods created by this field |
| /// encoding. |
| List<ClassMember> getLocalMembers(SourceFieldBuilder fieldBuilder); |
| |
| /// Returns a list of the setters created by this field encoding. |
| List<ClassMember> getLocalSetters(SourceFieldBuilder fieldBuilder); |
| } |
| |
| class RegularFieldEncoding implements FieldEncoding { |
| late final Field _field; |
| |
| RegularFieldEncoding(String name, NameScheme nameScheme, Uri fileUri, |
| int charOffset, int charEndOffset, |
| {required bool isFinal, |
| required bool isConst, |
| required bool isLate, |
| required bool hasInitializer, |
| required Reference? fieldReference, |
| required Reference? getterReference, |
| required Reference? setterReference, |
| required bool isEnumElement}) { |
| bool isImmutable = |
| isLate ? (isFinal && hasInitializer) : (isFinal || isConst); |
| _field = isImmutable |
| ? new Field.immutable(dummyName, |
| isFinal: isFinal, |
| isConst: isConst, |
| isLate: isLate, |
| fileUri: fileUri, |
| fieldReference: fieldReference, |
| getterReference: getterReference, |
| isEnumElement: isEnumElement) |
| : new Field.mutable(dummyName, |
| isFinal: isFinal, |
| isLate: isLate, |
| fileUri: fileUri, |
| fieldReference: fieldReference, |
| getterReference: getterReference, |
| setterReference: setterReference); |
| nameScheme |
| .getFieldMemberName(FieldNameType.Field, name, isSynthesized: false) |
| .attachMember(_field); |
| _field |
| ..fileOffset = charOffset |
| ..fileEndOffset = charEndOffset; |
| } |
| |
| @override |
| DartType get type => _field.type; |
| |
| @override |
| void set type(DartType value) { |
| _field.type = value; |
| } |
| |
| @override |
| void createBodies(CoreTypes coreTypes, Expression? initializer) { |
| if (initializer != null) { |
| _field.initializer = initializer..parent = _field; |
| } |
| } |
| |
| @override |
| List<Initializer> createInitializer(int fileOffset, Expression value, |
| {required bool isSynthetic}) { |
| return <Initializer>[ |
| new FieldInitializer(_field, value) |
| ..fileOffset = fileOffset |
| ..isSynthetic = isSynthetic |
| ]; |
| } |
| |
| @override |
| void build( |
| SourceLibraryBuilder libraryBuilder, SourceFieldBuilder fieldBuilder) { |
| _field..isCovariantByDeclaration = fieldBuilder.isCovariantByDeclaration; |
| if (fieldBuilder.isExtensionMember) { |
| _field |
| ..isStatic = true |
| ..isExtensionMember = true; |
| } else if (fieldBuilder.isExtensionTypeMember) { |
| _field |
| ..isStatic = fieldBuilder.isStatic |
| ..isExtensionTypeMember = true; |
| } else { |
| bool isInstanceMember = |
| !fieldBuilder.isStatic && !fieldBuilder.isTopLevel; |
| _field |
| ..isStatic = !isInstanceMember |
| ..isExtensionMember = false; |
| } |
| _field.isLate = fieldBuilder.isLate; |
| } |
| |
| @override |
| void registerMembers(SourceLibraryBuilder library, |
| SourceFieldBuilder fieldBuilder, BuildNodesCallback f) { |
| f( |
| member: _field, |
| kind: |
| fieldBuilder.isExtensionMember || fieldBuilder.isExtensionTypeMember |
| ? BuiltMemberKind.ExtensionField |
| : BuiltMemberKind.Field); |
| } |
| |
| @override |
| void setGenericCovariantImpl() { |
| _field.isCovariantByClass = true; |
| } |
| |
| @override |
| Field get field => _field; |
| |
| @override |
| Iterable<Annotatable> get annotatables => [_field]; |
| |
| @override |
| Member get readTarget => _field; |
| |
| @override |
| Member get writeTarget => _field; |
| |
| @override |
| Iterable<Member> get exportedMembers => [_field]; |
| |
| @override |
| List<ClassMember> getLocalMembers(SourceFieldBuilder fieldBuilder) => |
| <ClassMember>[ |
| new SourceFieldMember(fieldBuilder, ClassMemberKind.Getter) |
| ]; |
| |
| @override |
| List<ClassMember> getLocalSetters(SourceFieldBuilder fieldBuilder) => |
| fieldBuilder.isAssignable |
| ? <ClassMember>[ |
| new SourceFieldMember(fieldBuilder, ClassMemberKind.Setter) |
| ] |
| : const <ClassMember>[]; |
| |
| @override |
| void buildImplicitDefaultValue() { |
| _field.initializer = new NullLiteral()..parent = _field; |
| } |
| |
| @override |
| Initializer buildImplicitInitializer() { |
| return new FieldInitializer(_field, new NullLiteral())..isSynthetic = true; |
| } |
| |
| @override |
| Initializer buildErroneousInitializer(Expression effect, Expression value, |
| {required int fileOffset}) { |
| return new ShadowInvalidFieldInitializer(type, value, effect) |
| ..fileOffset = fileOffset; |
| } |
| } |
| |
| class SourceFieldMember extends BuilderClassMember { |
| @override |
| final SourceFieldBuilder memberBuilder; |
| |
| Covariance? _covariance; |
| |
| @override |
| final ClassMemberKind memberKind; |
| |
| SourceFieldMember(this.memberBuilder, this.memberKind); |
| |
| @override |
| void inferType(ClassMembersBuilder membersBuilder) { |
| memberBuilder._ensureType(membersBuilder); |
| } |
| |
| @override |
| void registerOverrideDependency(Set<ClassMember> overriddenMembers) { |
| memberBuilder.registerOverrideDependency(overriddenMembers); |
| } |
| |
| @override |
| Member getMember(ClassMembersBuilder membersBuilder) { |
| memberBuilder._ensureType(membersBuilder); |
| return memberBuilder.field; |
| } |
| |
| @override |
| // Coverage-ignore(suite): Not run. |
| Member? getTearOff(ClassMembersBuilder membersBuilder) { |
| // Ensure field type is computed. |
| getMember(membersBuilder); |
| return null; |
| } |
| |
| @override |
| Covariance getCovariance(ClassMembersBuilder membersBuilder) { |
| return _covariance ??= forSetter |
| ? new Covariance.fromMember(getMember(membersBuilder), |
| forSetter: forSetter) |
| : const Covariance.empty(); |
| } |
| |
| @override |
| bool get isSourceDeclaration => true; |
| |
| @override |
| bool get isSynthesized => memberBuilder.isSynthesized; |
| |
| @override |
| bool isSameDeclaration(ClassMember other) { |
| return other is SourceFieldMember && memberBuilder == other.memberBuilder; |
| } |
| } |
| |
| abstract class AbstractLateFieldEncoding implements FieldEncoding { |
| final String name; |
| final int fileOffset; |
| final int fileEndOffset; |
| DartType? _type; |
| late final Field _field; |
| Field? _lateIsSetField; |
| late Procedure _lateGetter; |
| Procedure? _lateSetter; |
| |
| // If `true`, an isSet field is used even when the type of the field is |
| // not potentially nullable. |
| // |
| // This is used to force use isSet fields in mixed mode encoding since |
| // we cannot trust non-nullable fields to be initialized with non-null values. |
| final late_lowering.IsSetStrategy _isSetStrategy; |
| late_lowering.IsSetEncoding? _isSetEncoding; |
| |
| // If `true`, the is-set field was register before the type was known to be |
| // nullable or non-nullable. In this case we do not try to remove it from |
| // the generated AST to avoid inconsistency between the class hierarchy used |
| // during and after inference. |
| // |
| // This is also used to force use isSet fields in mixed mode encoding since |
| // we cannot trust non-nullable fields to be initialized with non-null values. |
| bool _forceIncludeIsSetField; |
| |
| AbstractLateFieldEncoding( |
| this.name, |
| NameScheme nameScheme, |
| Uri fileUri, |
| int charOffset, |
| int charEndOffset, |
| Reference? fieldReference, |
| Reference? fieldGetterReference, |
| Reference? fieldSetterReference, |
| Reference? lateIsSetFieldReference, |
| Reference? lateIsSetGetterReference, |
| Reference? lateIsSetSetterReference, |
| Reference? lateGetterReference, |
| Reference? lateSetterReference, |
| bool isCovariantByDeclaration, |
| late_lowering.IsSetStrategy isSetStrategy) |
| : fileOffset = charOffset, |
| fileEndOffset = charEndOffset, |
| _isSetStrategy = isSetStrategy, |
| _forceIncludeIsSetField = |
| isSetStrategy == late_lowering.IsSetStrategy.forceUseIsSetField { |
| _field = new Field.mutable(dummyName, |
| fileUri: fileUri, |
| fieldReference: fieldReference, |
| getterReference: fieldGetterReference, |
| setterReference: fieldSetterReference) |
| ..fileOffset = charOffset |
| ..fileEndOffset = charEndOffset |
| ..isInternalImplementation = true; |
| nameScheme |
| .getFieldMemberName(FieldNameType.Field, name, isSynthesized: true) |
| .attachMember(_field); |
| switch (_isSetStrategy) { |
| case late_lowering.IsSetStrategy.useSentinelOrNull: |
| case late_lowering.IsSetStrategy.forceUseSentinel: |
| // [_lateIsSetField] is never needed. |
| break; |
| case late_lowering.IsSetStrategy.forceUseIsSetField: |
| case late_lowering.IsSetStrategy.useIsSetFieldOrNull: |
| _lateIsSetField = new Field.mutable(dummyName, |
| fileUri: fileUri, |
| fieldReference: lateIsSetFieldReference, |
| getterReference: lateIsSetGetterReference, |
| setterReference: lateIsSetSetterReference) |
| ..fileOffset = charOffset |
| ..fileEndOffset = charEndOffset |
| ..isInternalImplementation = true; |
| nameScheme |
| .getFieldMemberName(FieldNameType.IsSetField, name, |
| isSynthesized: true) |
| .attachMember(_lateIsSetField!); |
| break; |
| } |
| _lateGetter = new Procedure( |
| dummyName, |
| ProcedureKind.Getter, |
| new FunctionNode(null) |
| ..fileOffset = charOffset |
| ..fileEndOffset = charEndOffset, |
| fileUri: fileUri, |
| reference: lateGetterReference) |
| ..fileOffset = charOffset |
| ..fileEndOffset = charEndOffset; |
| nameScheme |
| .getFieldMemberName(FieldNameType.Getter, name, isSynthesized: true) |
| .attachMember(_lateGetter); |
| _lateSetter = _createSetter(fileUri, charOffset, lateSetterReference, |
| isCovariantByDeclaration: isCovariantByDeclaration); |
| if (_lateSetter != null) { |
| nameScheme |
| .getFieldMemberName(FieldNameType.Setter, name, isSynthesized: true) |
| .attachMember(_lateSetter!); |
| } |
| } |
| |
| late_lowering.IsSetEncoding get isSetEncoding { |
| assert( |
| _type != null, // Coverage-ignore(suite): Not run. |
| "Type has not been computed for field $name."); |
| return _isSetEncoding ??= |
| late_lowering.computeIsSetEncoding(_type!, _isSetStrategy); |
| } |
| |
| @override |
| void createBodies(CoreTypes coreTypes, Expression? initializer) { |
| assert( |
| _type != null, // Coverage-ignore(suite): Not run. |
| "Type has not been computed for field $name."); |
| if (isSetEncoding == late_lowering.IsSetEncoding.useSentinel) { |
| _field.initializer = new StaticInvocation(coreTypes.createSentinelMethod, |
| new Arguments([], types: [_type!])..fileOffset = fileOffset) |
| ..fileOffset = fileOffset |
| ..parent = _field; |
| } else { |
| _field.initializer = new NullLiteral() |
| ..fileOffset = fileOffset |
| ..parent = _field; |
| } |
| if (_lateIsSetField != null) { |
| _lateIsSetField!.initializer = new BoolLiteral(false) |
| ..fileOffset = fileOffset |
| ..parent = _lateIsSetField; |
| } |
| _lateGetter.function.body = _createGetterBody(coreTypes, name, initializer) |
| ..parent = _lateGetter.function; |
| // The initializer is copied from [_field] to [_lateGetter] so we copy the |
| // transformer flags to reflect whether the getter contains super calls. |
| _lateGetter.transformerFlags = _field.transformerFlags; |
| |
| if (_lateSetter != null) { |
| _lateSetter!.function.body = _createSetterBody( |
| coreTypes, name, _lateSetter!.function.positionalParameters.first) |
| ..parent = _lateSetter!.function; |
| } |
| } |
| |
| @override |
| List<Initializer> createInitializer(int fileOffset, Expression value, |
| {required bool isSynthetic}) { |
| List<Initializer> initializers = <Initializer>[]; |
| if (_lateIsSetField != null) { |
| initializers.add(new FieldInitializer( |
| _lateIsSetField!, new BoolLiteral(true)..fileOffset = fileOffset) |
| ..fileOffset = fileOffset |
| ..isSynthetic = isSynthetic); |
| } |
| initializers.add(new FieldInitializer(_field, value) |
| ..fileOffset = fileOffset |
| ..isSynthetic = isSynthetic); |
| return initializers; |
| } |
| |
| /// Creates an [Expression] that reads [_field]. |
| /// |
| /// If [needsPromotion] is `true`, the field will be read through a `let` |
| /// expression that promotes the expression to [_type]. This is needed for a |
| /// sound encoding of fields with type variable type of undetermined |
| /// nullability. |
| Expression _createFieldRead({bool needsPromotion = false}) { |
| assert( |
| _type != null, // Coverage-ignore(suite): Not run. |
| "Type has not been computed for field $name."); |
| if (needsPromotion) { |
| VariableDeclaration variable = new VariableDeclaration.forValue( |
| _createFieldGet(_field), |
| type: _type!.withDeclaredNullability(Nullability.nullable)) |
| ..fileOffset = fileOffset; |
| return new Let( |
| variable, new VariableGet(variable, _type)..fileOffset = fileOffset); |
| } else { |
| return _createFieldGet(_field); |
| } |
| } |
| |
| /// Creates an [Expression] that reads [field]. |
| Expression _createFieldGet(Field field) { |
| if (field.isStatic) { |
| return new StaticGet(field)..fileOffset = fileOffset; |
| } else { |
| // No substitution needed for the result type, since any type variables |
| // in there are also in scope at the access site. |
| return new InstanceGet(InstanceAccessKind.Instance, |
| new ThisExpression()..fileOffset = fileOffset, field.name, |
| interfaceTarget: field, resultType: field.type) |
| ..fileOffset = fileOffset; |
| } |
| } |
| |
| /// Creates an [Expression] that writes [value] to [field]. |
| Expression _createFieldSet(Field field, Expression value) { |
| if (field.isStatic) { |
| return new StaticSet(field, value)..fileOffset = fileOffset; |
| } else { |
| return new InstanceSet(InstanceAccessKind.Instance, |
| new ThisExpression()..fileOffset = fileOffset, field.name, value, |
| interfaceTarget: field) |
| ..fileOffset = fileOffset; |
| } |
| } |
| |
| Statement _createGetterBody( |
| CoreTypes coreTypes, String name, Expression? initializer); |
| |
| Procedure? _createSetter(Uri fileUri, int charOffset, Reference? reference, |
| {required bool isCovariantByDeclaration}) { |
| VariableDeclaration parameter = new VariableDeclaration("${name}#param") |
| ..isCovariantByDeclaration = isCovariantByDeclaration |
| ..fileOffset = fileOffset; |
| return new Procedure( |
| dummyName, |
| ProcedureKind.Setter, |
| new FunctionNode(null, |
| positionalParameters: [parameter], returnType: const VoidType()) |
| ..fileOffset = charOffset |
| ..fileEndOffset = fileEndOffset, |
| fileUri: fileUri, |
| reference: reference) |
| ..fileOffset = charOffset |
| ..fileEndOffset = fileEndOffset; |
| } |
| |
| Statement _createSetterBody( |
| CoreTypes coreTypes, String name, VariableDeclaration parameter); |
| |
| @override |
| DartType get type { |
| assert( |
| _type != null, // Coverage-ignore(suite): Not run. |
| "Type has not been computed for field $name."); |
| return _type!; |
| } |
| |
| @override |
| void set type(DartType value) { |
| assert( |
| _type == null || _type is InferredType, |
| // Coverage-ignore(suite): Not run. |
| "Type has already been computed for field $name."); |
| _type = value; |
| if (value is! InferredType) { |
| _field.type = value.withDeclaredNullability(Nullability.nullable); |
| _lateGetter.function.returnType = value; |
| if (_lateSetter != null) { |
| _lateSetter!.function.positionalParameters.single.type = value; |
| } |
| if (!_type!.isPotentiallyNullable && !_forceIncludeIsSetField) { |
| // We only need the is-set field if the field is potentially nullable. |
| // Otherwise we use `null` to signal that the field is uninitialized. |
| _lateIsSetField = null; |
| } |
| } |
| } |
| |
| @override |
| void setGenericCovariantImpl() { |
| _field.isCovariantByClass = true; |
| _lateSetter?.function.positionalParameters.single.isCovariantByClass = true; |
| } |
| |
| @override |
| Field get field => _field; |
| |
| @override |
| Iterable<Annotatable> get annotatables { |
| List<Annotatable> list = [_lateGetter]; |
| if (_lateSetter != null) { |
| list.add(_lateSetter!); |
| } |
| return list; |
| } |
| |
| @override |
| Member get readTarget => _lateGetter; |
| |
| @override |
| Member? get writeTarget => _lateSetter; |
| |
| @override |
| Iterable<Member> get exportedMembers { |
| if (_lateSetter != null) { |
| return [_lateGetter, _lateSetter!]; |
| } |
| return [_lateGetter]; |
| } |
| |
| @override |
| void build( |
| SourceLibraryBuilder libraryBuilder, SourceFieldBuilder fieldBuilder) { |
| bool isInstanceMember = !fieldBuilder.isStatic && !fieldBuilder.isTopLevel; |
| bool isExtensionMember = fieldBuilder.isExtensionMember; |
| bool isExtensionTypeMember = fieldBuilder.isExtensionTypeMember; |
| if (isExtensionMember) { |
| _field |
| ..isStatic = true |
| ..isExtensionMember = isExtensionMember; |
| isInstanceMember = false; |
| } else if (isExtensionTypeMember) { |
| // Coverage-ignore-block(suite): Not run. |
| _field |
| ..isStatic = fieldBuilder.isStatic |
| ..isExtensionTypeMember = true; |
| } else { |
| _field |
| ..isStatic = !isInstanceMember |
| ..isExtensionMember = false; |
| } |
| if (_lateIsSetField != null) { |
| _lateIsSetField! |
| ..isStatic = !isInstanceMember |
| ..isExtensionMember = isExtensionMember |
| ..isExtensionTypeMember = isExtensionTypeMember |
| ..type = libraryBuilder.loader |
| .createCoreType('bool', Nullability.nonNullable); |
| } |
| _lateGetter |
| ..isStatic = !isInstanceMember |
| ..isExtensionMember = isExtensionMember |
| ..isExtensionTypeMember = isExtensionTypeMember; |
| if (_lateSetter != null) { |
| _lateSetter! |
| ..isStatic = !isInstanceMember |
| ..isExtensionMember = isExtensionMember |
| ..isExtensionTypeMember = isExtensionTypeMember; |
| } |
| } |
| |
| @override |
| void registerMembers(SourceLibraryBuilder library, |
| SourceFieldBuilder fieldBuilder, BuildNodesCallback f) { |
| f( |
| member: _field, |
| kind: |
| fieldBuilder.isExtensionMember || fieldBuilder.isExtensionTypeMember |
| ? BuiltMemberKind.ExtensionField |
| : BuiltMemberKind.Field); |
| if (_lateIsSetField != null) { |
| _forceIncludeIsSetField = true; |
| f(member: _lateIsSetField!, kind: BuiltMemberKind.LateIsSetField); |
| } |
| f(member: _lateGetter, kind: BuiltMemberKind.LateGetter); |
| if (_lateSetter != null) { |
| f(member: _lateSetter!, kind: BuiltMemberKind.LateSetter); |
| } |
| } |
| |
| @override |
| List<ClassMember> getLocalMembers(SourceFieldBuilder fieldBuilder) { |
| List<ClassMember> list = <ClassMember>[ |
| new _SynthesizedFieldClassMember(fieldBuilder, field, field.name, |
| _SynthesizedFieldMemberKind.LateField, ClassMemberKind.Getter, |
| isInternalImplementation: true), |
| new _SynthesizedFieldClassMember( |
| fieldBuilder, |
| _lateGetter, |
| fieldBuilder.memberName, |
| _SynthesizedFieldMemberKind.LateGetterSetter, |
| ClassMemberKind.Getter, |
| isInternalImplementation: false) |
| ]; |
| if (_lateIsSetField != null) { |
| list.add(new _SynthesizedFieldClassMember( |
| fieldBuilder, |
| _lateIsSetField!, |
| _lateIsSetField!.name, |
| _SynthesizedFieldMemberKind.LateIsSet, |
| ClassMemberKind.Getter, |
| isInternalImplementation: true)); |
| } |
| return list; |
| } |
| |
| @override |
| List<ClassMember> getLocalSetters(SourceFieldBuilder fieldBuilder) { |
| List<ClassMember> list = <ClassMember>[ |
| new _SynthesizedFieldClassMember(fieldBuilder, field, field.name, |
| _SynthesizedFieldMemberKind.LateField, ClassMemberKind.Setter, |
| isInternalImplementation: true), |
| ]; |
| if (_lateIsSetField != null) { |
| list.add(new _SynthesizedFieldClassMember( |
| fieldBuilder, |
| _lateIsSetField!, |
| _lateIsSetField!.name, |
| _SynthesizedFieldMemberKind.LateIsSet, |
| ClassMemberKind.Setter, |
| isInternalImplementation: true)); |
| } |
| if (_lateSetter != null) { |
| list.add(new _SynthesizedFieldClassMember( |
| fieldBuilder, |
| _lateSetter!, |
| fieldBuilder.memberName, |
| _SynthesizedFieldMemberKind.LateGetterSetter, |
| ClassMemberKind.Setter, |
| isInternalImplementation: false)); |
| } |
| return list; |
| } |
| } |
| |
| mixin NonFinalLate on AbstractLateFieldEncoding { |
| @override |
| Statement _createSetterBody( |
| CoreTypes coreTypes, String name, VariableDeclaration parameter) { |
| assert( |
| _type != null, // Coverage-ignore(suite): Not run. |
| "Type has not been computed for field $name."); |
| return late_lowering.createSetterBody( |
| coreTypes, fileOffset, name, parameter, _type!, |
| shouldReturnValue: false, |
| createVariableWrite: (Expression value) => |
| _createFieldSet(_field, value), |
| createIsSetWrite: (Expression value) => |
| _createFieldSet(_lateIsSetField!, value), |
| isSetEncoding: isSetEncoding); |
| } |
| } |
| |
| mixin LateWithoutInitializer on AbstractLateFieldEncoding { |
| @override |
| Statement _createGetterBody( |
| CoreTypes coreTypes, String name, Expression? initializer) { |
| assert( |
| _type != null, // Coverage-ignore(suite): Not run. |
| "Type has not been computed for field $name."); |
| return late_lowering.createGetterBodyWithoutInitializer( |
| coreTypes, fileOffset, name, type, |
| createVariableRead: _createFieldRead, |
| createIsSetRead: () => _createFieldGet(_lateIsSetField!), |
| isSetEncoding: isSetEncoding, |
| forField: true); |
| } |
| |
| @override |
| void buildImplicitDefaultValue() { |
| throw new UnsupportedError("$runtimeType.buildImplicitDefaultValue"); |
| } |
| |
| @override |
| Initializer buildImplicitInitializer() { |
| throw new UnsupportedError("$runtimeType.buildImplicitInitializer"); |
| } |
| |
| @override |
| Initializer buildErroneousInitializer(Expression effect, Expression value, |
| {required int fileOffset}) { |
| throw new UnsupportedError("$runtimeType.buildDuplicatedInitializer"); |
| } |
| } |
| |
| class LateFieldWithoutInitializerEncoding extends AbstractLateFieldEncoding |
| with NonFinalLate, LateWithoutInitializer { |
| LateFieldWithoutInitializerEncoding( |
| String name, |
| NameScheme nameScheme, |
| Uri fileUri, |
| int charOffset, |
| int charEndOffset, |
| Reference? fieldReference, |
| Reference? fieldGetterReference, |
| Reference? fieldSetterReference, |
| Reference? lateIsSetFieldReference, |
| Reference? lateIsSetGetterReference, |
| Reference? lateIsSetSetterReference, |
| Reference? lateGetterReference, |
| Reference? lateSetterReference, |
| bool isCovariantByDeclaration, |
| late_lowering.IsSetStrategy isSetStrategy) |
| : super( |
| name, |
| nameScheme, |
| fileUri, |
| charOffset, |
| charEndOffset, |
| fieldReference, |
| fieldGetterReference, |
| fieldSetterReference, |
| lateIsSetFieldReference, |
| lateIsSetGetterReference, |
| lateIsSetSetterReference, |
| lateGetterReference, |
| lateSetterReference, |
| isCovariantByDeclaration, |
| isSetStrategy); |
| } |
| |
| class LateFieldWithInitializerEncoding extends AbstractLateFieldEncoding |
| with NonFinalLate { |
| LateFieldWithInitializerEncoding( |
| String name, |
| NameScheme nameScheme, |
| Uri fileUri, |
| int charOffset, |
| int charEndOffset, |
| Reference? fieldReference, |
| Reference? fieldGetterReference, |
| Reference? fieldSetterReference, |
| Reference? lateIsSetFieldReference, |
| Reference? lateIsSetGetterReference, |
| Reference? lateIsSetSetterReference, |
| Reference? lateGetterReference, |
| Reference? lateSetterReference, |
| bool isCovariantByDeclaration, |
| late_lowering.IsSetStrategy isSetStrategy) |
| : super( |
| name, |
| nameScheme, |
| fileUri, |
| charOffset, |
| charEndOffset, |
| fieldReference, |
| fieldGetterReference, |
| fieldSetterReference, |
| lateIsSetFieldReference, |
| lateIsSetGetterReference, |
| lateIsSetSetterReference, |
| lateGetterReference, |
| lateSetterReference, |
| isCovariantByDeclaration, |
| isSetStrategy); |
| |
| @override |
| Statement _createGetterBody( |
| CoreTypes coreTypes, String name, Expression? initializer) { |
| assert( |
| _type != null, // Coverage-ignore(suite): Not run. |
| "Type has not been computed for field $name."); |
| return late_lowering.createGetterWithInitializer( |
| coreTypes, fileOffset, name, _type!, initializer!, |
| createVariableRead: _createFieldRead, |
| createVariableWrite: (Expression value) => |
| _createFieldSet(_field, value), |
| createIsSetRead: () => _createFieldGet(_lateIsSetField!), |
| createIsSetWrite: (Expression value) => |
| _createFieldSet(_lateIsSetField!, value), |
| isSetEncoding: isSetEncoding); |
| } |
| |
| @override |
| void buildImplicitDefaultValue() { |
| throw new UnsupportedError("$runtimeType.buildImplicitDefaultValue"); |
| } |
| |
| @override |
| Initializer buildImplicitInitializer() { |
| throw new UnsupportedError("$runtimeType.buildImplicitInitializer"); |
| } |
| |
| @override |
| Initializer buildErroneousInitializer(Expression effect, Expression value, |
| {required int fileOffset}) { |
| throw new UnsupportedError("$runtimeType.buildDuplicatedInitializer"); |
| } |
| } |
| |
| class LateFinalFieldWithoutInitializerEncoding extends AbstractLateFieldEncoding |
| with LateWithoutInitializer { |
| LateFinalFieldWithoutInitializerEncoding( |
| String name, |
| NameScheme nameScheme, |
| Uri fileUri, |
| int charOffset, |
| int charEndOffset, |
| Reference? fieldReference, |
| Reference? fieldGetterReference, |
| Reference? fieldSetterReference, |
| Reference? lateIsSetFieldReference, |
| Reference? lateIsSetGetterReference, |
| Reference? lateIsSetSetterReference, |
| Reference? lateGetterReference, |
| Reference? lateSetterReference, |
| bool isCovariantByDeclaration, |
| late_lowering.IsSetStrategy isSetStrategy) |
| : super( |
| name, |
| nameScheme, |
| fileUri, |
| charOffset, |
| charEndOffset, |
| fieldReference, |
| fieldGetterReference, |
| fieldSetterReference, |
| lateIsSetFieldReference, |
| lateIsSetGetterReference, |
| lateIsSetSetterReference, |
| lateGetterReference, |
| lateSetterReference, |
| isCovariantByDeclaration, |
| isSetStrategy); |
| |
| @override |
| Statement _createSetterBody( |
| CoreTypes coreTypes, String name, VariableDeclaration parameter) { |
| assert( |
| _type != null, // Coverage-ignore(suite): Not run. |
| "Type has not been computed for field $name."); |
| return late_lowering.createSetterBodyFinal( |
| coreTypes, fileOffset, name, parameter, type, |
| shouldReturnValue: false, |
| createVariableRead: () => _createFieldGet(_field), |
| createVariableWrite: (Expression value) => |
| _createFieldSet(_field, value), |
| createIsSetRead: () => _createFieldGet(_lateIsSetField!), |
| createIsSetWrite: (Expression value) => |
| _createFieldSet(_lateIsSetField!, value), |
| isSetEncoding: isSetEncoding, |
| forField: true); |
| } |
| } |
| |
| class LateFinalFieldWithInitializerEncoding extends AbstractLateFieldEncoding { |
| LateFinalFieldWithInitializerEncoding( |
| String name, |
| NameScheme nameScheme, |
| Uri fileUri, |
| int charOffset, |
| int charEndOffset, |
| Reference? fieldReference, |
| Reference? fieldGetterReference, |
| Reference? fieldSetterReference, |
| Reference? lateIsSetFieldReference, |
| Reference? lateIsSetGetterReference, |
| Reference? lateIsSetSetterReference, |
| Reference? lateGetterReference, |
| Reference? lateSetterReference, |
| bool isCovariantByDeclaration, |
| late_lowering.IsSetStrategy isSetStrategy) |
| : super( |
| name, |
| nameScheme, |
| fileUri, |
| charOffset, |
| charEndOffset, |
| fieldReference, |
| fieldGetterReference, |
| fieldSetterReference, |
| lateIsSetFieldReference, |
| lateIsSetGetterReference, |
| lateIsSetSetterReference, |
| lateGetterReference, |
| lateSetterReference, |
| isCovariantByDeclaration, |
| isSetStrategy); |
| |
| @override |
| Statement _createGetterBody( |
| CoreTypes coreTypes, String name, Expression? initializer) { |
| assert( |
| _type != null, // Coverage-ignore(suite): Not run. |
| "Type has not been computed for field $name."); |
| return late_lowering.createGetterWithInitializerWithRecheck( |
| coreTypes, fileOffset, name, _type!, initializer!, |
| createVariableRead: _createFieldRead, |
| createVariableWrite: (Expression value) => |
| _createFieldSet(_field, value), |
| createIsSetRead: () => _createFieldGet(_lateIsSetField!), |
| createIsSetWrite: (Expression value) => |
| _createFieldSet(_lateIsSetField!, value), |
| isSetEncoding: isSetEncoding, |
| forField: true); |
| } |
| |
| @override |
| Procedure? _createSetter(Uri fileUri, int charOffset, Reference? reference, |
| {required bool isCovariantByDeclaration}) => |
| null; |
| |
| @override |
| // Coverage-ignore(suite): Not run. |
| Statement _createSetterBody( |
| CoreTypes coreTypes, String name, VariableDeclaration parameter) => |
| throw new UnsupportedError( |
| '$runtimeType._createSetterBody is not supported.'); |
| |
| @override |
| void buildImplicitDefaultValue() { |
| throw new UnsupportedError("$runtimeType.buildImplicitDefaultValue"); |
| } |
| |
| @override |
| Initializer buildImplicitInitializer() { |
| throw new UnsupportedError("$runtimeType.buildImplicitInitializer"); |
| } |
| |
| @override |
| Initializer buildErroneousInitializer(Expression effect, Expression value, |
| {required int fileOffset}) { |
| throw new UnsupportedError("$runtimeType.buildDuplicatedInitializer"); |
| } |
| } |
| |
| class _SynthesizedFieldClassMember implements ClassMember { |
| final SourceFieldBuilder fieldBuilder; |
| final _SynthesizedFieldMemberKind _kind; |
| |
| final Member _member; |
| |
| final Name _name; |
| |
| Covariance? _covariance; |
| |
| @override |
| final bool isInternalImplementation; |
| |
| @override |
| final ClassMemberKind memberKind; |
| |
| _SynthesizedFieldClassMember( |
| this.fieldBuilder, this._member, this._name, this._kind, this.memberKind, |
| {required this.isInternalImplementation}); |
| |
| @override |
| Member getMember(ClassMembersBuilder membersBuilder) { |
| fieldBuilder._ensureType(membersBuilder); |
| return _member; |
| } |
| |
| @override |
| Member? getTearOff(ClassMembersBuilder membersBuilder) { |
| // Ensure field type is computed. |
| getMember(membersBuilder); |
| return null; |
| } |
| |
| @override |
| Covariance getCovariance(ClassMembersBuilder membersBuilder) { |
| return _covariance ??= new Covariance.fromMember(getMember(membersBuilder), |
| forSetter: forSetter); |
| } |
| |
| @override |
| MemberResult getMemberResult(ClassMembersBuilder membersBuilder) { |
| return new TypeDeclarationInstanceMemberResult( |
| getMember(membersBuilder), memberKind, |
| isDeclaredAsField: true); |
| } |
| |
| @override |
| void inferType(ClassMembersBuilder membersBuilder) { |
| fieldBuilder._ensureType(membersBuilder); |
| } |
| |
| @override |
| void registerOverrideDependency(Set<ClassMember> overriddenMembers) { |
| fieldBuilder.registerOverrideDependency(overriddenMembers); |
| } |
| |
| @override |
| bool get isSourceDeclaration => true; |
| |
| @override |
| bool get forSetter => memberKind == ClassMemberKind.Setter; |
| |
| @override |
| bool get isProperty => memberKind != ClassMemberKind.Method; |
| |
| @override |
| DeclarationBuilder get declarationBuilder => fieldBuilder.declarationBuilder!; |
| |
| @override |
| // Coverage-ignore(suite): Not run. |
| bool isObjectMember(ClassBuilder objectClass) { |
| return declarationBuilder == objectClass; |
| } |
| |
| @override |
| bool get isDuplicate => fieldBuilder.isDuplicate; |
| |
| @override |
| bool get isStatic => fieldBuilder.isStatic; |
| |
| @override |
| bool get isField => _member is Field; |
| |
| @override |
| bool get isSetter { |
| Member procedure = _member; |
| return procedure is Procedure && procedure.kind == ProcedureKind.Setter; |
| } |
| |
| @override |
| bool get isGetter { |
| Member procedure = _member; |
| return procedure is Procedure && procedure.kind == ProcedureKind.Getter; |
| } |
| |
| @override |
| Name get name => _name; |
| |
| @override |
| // Coverage-ignore(suite): Not run. |
| String get fullName { |
| String suffix = isSetter ? "=" : ""; |
| String className = declarationBuilder.fullNameForErrors; |
| return "${className}.${fullNameForErrors}$suffix"; |
| } |
| |
| @override |
| String get fullNameForErrors => fieldBuilder.fullNameForErrors; |
| |
| @override |
| Uri get fileUri => fieldBuilder.fileUri; |
| |
| @override |
| int get charOffset => fieldBuilder.charOffset; |
| |
| @override |
| bool get isAbstract => _member.isAbstract; |
| |
| @override |
| bool get isSynthesized => false; |
| |
| @override |
| bool get hasDeclarations => false; |
| |
| @override |
| // Coverage-ignore(suite): Not run. |
| List<ClassMember> get declarations => |
| throw new UnsupportedError("$runtimeType.declarations"); |
| |
| @override |
| ClassMember get interfaceMember => this; |
| |
| @override |
| bool isSameDeclaration(ClassMember other) { |
| if (identical(this, other)) return true; |
| return other is _SynthesizedFieldClassMember && |
| fieldBuilder == other.fieldBuilder && |
| _kind == other._kind; |
| } |
| |
| @override |
| bool get isNoSuchMethodForwarder => false; |
| |
| @override |
| String toString() => '_SynthesizedFieldClassMember(' |
| '$fieldBuilder,$_member,$_kind,forSetter=${forSetter})'; |
| |
| @override |
| bool get isExtensionTypeMember => fieldBuilder.isExtensionTypeMember; |
| } |
| |
| class AbstractOrExternalFieldEncoding implements FieldEncoding { |
| final SourceFieldBuilder _fieldBuilder; |
| final bool isAbstract; |
| final bool isExternal; |
| final bool _isExtensionInstanceMember; |
| final bool _isExtensionTypeInstanceMember; |
| |
| late Procedure _getter; |
| Procedure? _setter; |
| DartType? _type; |
| |
| AbstractOrExternalFieldEncoding( |
| this._fieldBuilder, |
| String name, |
| NameScheme nameScheme, |
| Uri fileUri, |
| int charOffset, |
| int charEndOffset, |
| Reference? getterReference, |
| Reference? setterReference, |
| {required this.isAbstract, |
| required this.isExternal, |
| required bool isFinal, |
| required bool isCovariantByDeclaration}) |
| : _isExtensionInstanceMember = isExternal && |
| nameScheme.isExtensionMember && |
| nameScheme.isInstanceMember, |
| _isExtensionTypeInstanceMember = isExternal && |
| nameScheme.isExtensionTypeMember && |
| nameScheme.isInstanceMember { |
| if (_isExtensionInstanceMember || _isExtensionTypeInstanceMember) { |
| _getter = new Procedure( |
| dummyName, |
| ProcedureKind.Method, |
| new FunctionNode(null, positionalParameters: [ |
| new VariableDeclaration(syntheticThisName) |
| ..fileOffset = charOffset |
| ..isLowered = true |
| ]), |
| fileUri: fileUri, |
| reference: getterReference) |
| ..fileOffset = charOffset |
| ..fileEndOffset = charEndOffset; |
| nameScheme |
| .getProcedureMemberName(ProcedureKind.Getter, name) |
| .attachMember(_getter); |
| if (!isFinal) { |
| VariableDeclaration parameter = |
| new VariableDeclaration("#externalFieldValue", isSynthesized: true) |
| ..isCovariantByDeclaration = isCovariantByDeclaration |
| ..fileOffset = charOffset; |
| _setter = new Procedure( |
| dummyName, |
| ProcedureKind.Method, |
| new FunctionNode(null, |
| positionalParameters: [ |
| new VariableDeclaration(syntheticThisName) |
| ..fileOffset = charOffset |
| ..isLowered = true, |
| parameter |
| ], |
| returnType: const VoidType()) |
| ..fileOffset = charOffset |
| ..fileEndOffset = charEndOffset, |
| fileUri: fileUri, |
| reference: setterReference) |
| ..fileOffset = charOffset |
| ..fileEndOffset = charEndOffset; |
| nameScheme |
| .getProcedureMemberName(ProcedureKind.Setter, name) |
| .attachMember(_setter!); |
| } |
| } else { |
| _getter = new Procedure( |
| dummyName, ProcedureKind.Getter, new FunctionNode(null), |
| fileUri: fileUri, reference: getterReference) |
| ..fileOffset = charOffset |
| ..fileEndOffset = charEndOffset; |
| nameScheme |
| .getFieldMemberName(FieldNameType.Getter, name, isSynthesized: true) |
| .attachMember(_getter); |
| if (!isFinal) { |
| VariableDeclaration parameter = |
| new VariableDeclaration("#externalFieldValue", isSynthesized: true) |
| ..isCovariantByDeclaration = isCovariantByDeclaration |
| ..fileOffset = charOffset; |
| _setter = new Procedure( |
| dummyName, |
| ProcedureKind.Setter, |
| new FunctionNode(null, |
| positionalParameters: [parameter], returnType: const VoidType()) |
| ..fileOffset = charOffset |
| ..fileEndOffset = charEndOffset, |
| fileUri: fileUri, |
| reference: setterReference) |
| ..fileOffset = charOffset |
| ..fileEndOffset = charEndOffset; |
| nameScheme |
| .getFieldMemberName(FieldNameType.Setter, name, isSynthesized: true) |
| .attachMember(_setter!); |
| } |
| } |
| } |
| |
| @override |
| DartType get type { |
| assert( |
| _type != null, |
| // Coverage-ignore(suite): Not run. |
| "Type has not been computed for field ${_fieldBuilder.name}."); |
| return _type!; |
| } |
| |
| @override |
| void set type(DartType value) { |
| assert( |
| _type == null || _type is InferredType, |
| // Coverage-ignore(suite): Not run. |
| "Type has already been computed for field ${_fieldBuilder.name}."); |
| _type = value; |
| if (value is! InferredType) { |
| if (_isExtensionInstanceMember || _isExtensionTypeInstanceMember) { |
| DartType thisParameterType; |
| List<TypeParameter> typeParameters; |
| if (_isExtensionInstanceMember) { |
| SourceExtensionBuilder extensionBuilder = |
| _fieldBuilder.parent as SourceExtensionBuilder; |
| thisParameterType = extensionBuilder.extension.onType; |
| typeParameters = extensionBuilder.extension.typeParameters; |
| } else { |
| SourceExtensionTypeDeclarationBuilder |
| extensionTypeDeclarationBuilder = |
| _fieldBuilder.parent as SourceExtensionTypeDeclarationBuilder; |
| thisParameterType = extensionTypeDeclarationBuilder |
| .extensionTypeDeclaration.declaredRepresentationType; |
| typeParameters = extensionTypeDeclarationBuilder |
| .extensionTypeDeclaration.typeParameters; |
| } |
| if (typeParameters.isNotEmpty) { |
| FreshTypeParameters getterTypeParameters = |
| getFreshTypeParameters(typeParameters); |
| _getter.function.positionalParameters.first.type = |
| getterTypeParameters.substitute(thisParameterType); |
| _getter.function.returnType = getterTypeParameters.substitute(value); |
| _getter.function.typeParameters = |
| getterTypeParameters.freshTypeParameters; |
| setParents( |
| getterTypeParameters.freshTypeParameters, _getter.function); |
| |
| Procedure? setter = _setter; |
| if (setter != null) { |
| FreshTypeParameters setterTypeParameters = |
| getFreshTypeParameters(typeParameters); |
| setter.function.positionalParameters.first.type = |
| setterTypeParameters.substitute(thisParameterType); |
| setter.function.positionalParameters[1].type = |
| setterTypeParameters.substitute(value); |
| setter.function.typeParameters = |
| setterTypeParameters.freshTypeParameters; |
| setParents( |
| setterTypeParameters.freshTypeParameters, setter.function); |
| } |
| } else { |
| _getter.function.returnType = value; |
| _setter?.function.positionalParameters[1].type = value; |
| _getter.function.positionalParameters.first.type = thisParameterType; |
| _setter?.function.positionalParameters.first.type = thisParameterType; |
| } |
| } else { |
| _getter.function.returnType = value; |
| Procedure? setter = _setter; |
| if (setter != null) { |
| if (setter.kind == ProcedureKind.Method) { |
| // Coverage-ignore-block(suite): Not run. |
| setter.function.positionalParameters[1].type = value; |
| } else { |
| setter.function.positionalParameters.first.type = value; |
| } |
| } |
| } |
| } |
| } |
| |
| @override |
| void createBodies(CoreTypes coreTypes, Expression? initializer) { |
| // TODO(johnniwinther): Enable this assert. |
| //assert(initializer != null); |
| } |
| |
| @override |
| List<Initializer> createInitializer(int fileOffset, Expression value, |
| {required bool isSynthetic}) { |
| throw new UnsupportedError('ExternalFieldEncoding.createInitializer'); |
| } |
| |
| @override |
| void build( |
| SourceLibraryBuilder libraryBuilder, SourceFieldBuilder fieldBuilder) { |
| bool isExtensionMember = fieldBuilder.isExtensionMember; |
| bool isExtensionTypeMember = fieldBuilder.isExtensionTypeMember; |
| bool isInstanceMember = !isExtensionMember && |
| !isExtensionTypeMember && |
| !fieldBuilder.isStatic && |
| !fieldBuilder.isTopLevel; |
| _getter..isConst = fieldBuilder.isConst; |
| _getter |
| ..isStatic = !isInstanceMember |
| ..isExtensionMember = isExtensionMember |
| ..isExtensionTypeMember = isExtensionTypeMember |
| ..isAbstract = isAbstract && !isExternal |
| ..isExternal = isExternal; |
| |
| if (_setter != null) { |
| _setter! |
| ..isStatic = !isInstanceMember |
| ..isExtensionMember = isExtensionMember |
| ..isExtensionTypeMember = isExtensionTypeMember |
| ..isAbstract = isAbstract && !isExternal |
| ..isExternal = isExternal; |
| } |
| } |
| |
| @override |
| void registerMembers(SourceLibraryBuilder library, |
| SourceFieldBuilder fieldBuilder, BuildNodesCallback f) { |
| BuiltMemberKind getterMemberKind; |
| if (fieldBuilder.isExtensionMember) { |
| getterMemberKind = BuiltMemberKind.ExtensionGetter; |
| } else if (fieldBuilder.isExtensionTypeMember) { |
| getterMemberKind = BuiltMemberKind.ExtensionTypeGetter; |
| } else { |
| getterMemberKind = BuiltMemberKind.Method; |
| } |
| f(member: _getter, kind: getterMemberKind); |
| if (_setter != null) { |
| BuiltMemberKind setterMemberKind; |
| if (fieldBuilder.isExtensionMember) { |
| setterMemberKind = BuiltMemberKind.ExtensionSetter; |
| } else if (fieldBuilder.isExtensionTypeMember) { |
| setterMemberKind = BuiltMemberKind.ExtensionTypeSetter; |
| } else { |
| setterMemberKind = BuiltMemberKind.Method; |
| } |
| f(member: _setter!, kind: setterMemberKind); |
| } |
| } |
| |
| @override |
| // Coverage-ignore(suite): Not run. |
| void setGenericCovariantImpl() { |
| _setter!.function.positionalParameters.first.isCovariantByClass = true; |
| } |
| |
| @override |
| Field get field { |
| throw new UnsupportedError("ExternalFieldEncoding.field"); |
| } |
| |
| @override |
| Iterable<Annotatable> get annotatables { |
| List<Annotatable> list = [_getter]; |
| if (_setter != null) { |
| list.add(_setter!); |
| } |
| return list; |
| } |
| |
| @override |
| Member get readTarget => _getter; |
| |
| @override |
| Member? get writeTarget => _setter; |
| |
| @override |
| Iterable<Member> get exportedMembers { |
| if (_setter != null) { |
| return [_getter, _setter!]; |
| } |
| return [_getter]; |
| } |
| |
| @override |
| List<ClassMember> getLocalMembers(SourceFieldBuilder fieldBuilder) => |
| <ClassMember>[ |
| new _SynthesizedFieldClassMember( |
| fieldBuilder, |
| _getter, |
| fieldBuilder.memberName, |
| _SynthesizedFieldMemberKind.AbstractExternalGetterSetter, |
| ClassMemberKind.Getter, |
| isInternalImplementation: false) |
| ]; |
| |
| @override |
| List<ClassMember> getLocalSetters(SourceFieldBuilder fieldBuilder) => |
| _setter != null |
| ? <ClassMember>[ |
| new _SynthesizedFieldClassMember( |
| fieldBuilder, |
| _setter!, |
| fieldBuilder.memberName, |
| _SynthesizedFieldMemberKind.AbstractExternalGetterSetter, |
| ClassMemberKind.Setter, |
| isInternalImplementation: false) |
| ] |
| : const <ClassMember>[]; |
| |
| @override |
| void buildImplicitDefaultValue() { |
| throw new UnsupportedError("$runtimeType.buildImplicitDefaultValue"); |
| } |
| |
| @override |
| Initializer buildImplicitInitializer() { |
| throw new UnsupportedError("$runtimeType.buildImplicitInitializer"); |
| } |
| |
| @override |
| Initializer buildErroneousInitializer(Expression effect, Expression value, |
| {required int fileOffset}) { |
| throw new UnsupportedError("$runtimeType.buildDuplicatedInitializer"); |
| } |
| } |
| |
| /// The encoding of an extension type declaration representation field. |
| class RepresentationFieldEncoding implements FieldEncoding { |
| final SourceFieldBuilder _fieldBuilder; |
| |
| late Procedure _getter; |
| DartType? _type; |
| |
| RepresentationFieldEncoding( |
| this._fieldBuilder, |
| String name, |
| NameScheme nameScheme, |
| Uri fileUri, |
| int charOffset, |
| int charEndOffset, |
| Reference? getterReference) { |
| _getter = new Procedure( |
| dummyName, ProcedureKind.Getter, new FunctionNode(null), |
| fileUri: fileUri, reference: getterReference) |
| ..stubKind = ProcedureStubKind.RepresentationField |
| ..fileOffset = charOffset |
| ..fileEndOffset = charEndOffset; |
| nameScheme |
| .getFieldMemberName(FieldNameType.RepresentationField, name, |
| isSynthesized: true) |
| .attachMember(_getter); |
| } |
| |
| @override |
| DartType get type { |
| assert( |
| _type != null, |
| // Coverage-ignore(suite): Not run. |
| "Type has not been computed for field ${_fieldBuilder.name}."); |
| return _type!; |
| } |
| |
| @override |
| void set type(DartType value) { |
| assert( |
| _type == null || _type is InferredType, |
| // Coverage-ignore(suite): Not run. |
| "Type has already been computed for field ${_fieldBuilder.name}."); |
| _type = value; |
| if (value is! InferredType) { |
| _getter.function.returnType = value; |
| } |
| } |
| |
| @override |
| void createBodies(CoreTypes coreTypes, Expression? initializer) { |
| // TODO(johnniwinther): Enable this assert. |
| //assert(initializer != null); |
| } |
| |
| @override |
| List<Initializer> createInitializer(int fileOffset, Expression value, |
| {required bool isSynthetic}) { |
| return <Initializer>[ |
| new ExtensionTypeRepresentationFieldInitializer(_getter, value) |
| ]; |
| } |
| |
| @override |
| void build( |
| SourceLibraryBuilder libraryBuilder, SourceFieldBuilder fieldBuilder) { |
| _getter..isConst = fieldBuilder.isConst; |
| _getter |
| ..isStatic = false |
| ..isExtensionMember = false |
| ..isExtensionTypeMember = true |
| ..isAbstract = true |
| ..isExternal = false; |
| } |
| |
| @override |
| void registerMembers(SourceLibraryBuilder library, |
| SourceFieldBuilder fieldBuilder, BuildNodesCallback f) { |
| f(member: _getter, kind: BuiltMemberKind.ExtensionTypeRepresentationField); |
| } |
| |
| @override |
| void setGenericCovariantImpl() { |
| throw new UnsupportedError("$runtimeType.setGenericCovariantImpl"); |
| } |
| |
| @override |
| Field get field { |
| throw new UnsupportedError("$runtimeType.field"); |
| } |
| |
| @override |
| Iterable<Annotatable> get annotatables => [_getter]; |
| |
| @override |
| Member get readTarget => _getter; |
| |
| @override |
| // Coverage-ignore(suite): Not run. |
| Member? get writeTarget => null; |
| |
| @override |
| // Coverage-ignore(suite): Not run. |
| Iterable<Member> get exportedMembers => [_getter]; |
| |
| @override |
| List<ClassMember> getLocalMembers(SourceFieldBuilder fieldBuilder) => |
| <ClassMember>[ |
| new _SynthesizedFieldClassMember( |
| fieldBuilder, |
| _getter, |
| fieldBuilder.memberName, |
| _SynthesizedFieldMemberKind.RepresentationField, |
| ClassMemberKind.Getter, |
| isInternalImplementation: false) |
| ]; |
| |
| @override |
| List<ClassMember> getLocalSetters(SourceFieldBuilder fieldBuilder) => |
| const <ClassMember>[]; |
| |
| @override |
| // Coverage-ignore(suite): Not run. |
| void buildImplicitDefaultValue() { |
| // Not needed. |
| } |
| |
| @override |
| Initializer buildImplicitInitializer() { |
| return new ExtensionTypeRepresentationFieldInitializer( |
| _getter, new NullLiteral()); |
| } |
| |
| @override |
| Initializer buildErroneousInitializer(Expression effect, Expression value, |
| {required int fileOffset}) { |
| return new ShadowInvalidFieldInitializer(type, value, effect) |
| ..fileOffset = fileOffset; |
| } |
| } |
| |
| enum _SynthesizedFieldMemberKind { |
| /// A `isSet` field used for late lowering. |
| LateIsSet, |
| |
| /// A field used for the value of a late lowered field. |
| LateField, |
| |
| /// A getter or setter used for late lowering. |
| LateGetterSetter, |
| |
| /// A getter or setter used for abstract or external fields. |
| AbstractExternalGetterSetter, |
| |
| /// A getter for an extension type declaration representation field. |
| RepresentationField, |
| } |