From a6b99afdeaff69f1ca67baf34c90d47fdc355883 Mon Sep 17 00:00:00 2001 From: Johnni Winther Date: Thu, 9 Jan 2025 01:46:33 -0800 Subject: [PATCH] [cfe] Create fields through SourcePropertyBuilder Change-Id: I20c9dd7baa705aba77d90b94ba0a46ed64eb02ec Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/403600 Commit-Queue: Johnni Winther Reviewed-by: Chloe Stefantsova --- .../lib/src/base/incremental_compiler.dart | 5 +- pkg/front_end/lib/src/base/scope.dart | 13 +- .../lib/src/builder/builder_mixins.dart | 9 +- .../src/builder/formal_parameter_builder.dart | 4 +- .../invalid_type_declaration_builder.dart | 2 +- .../lib/src/builder/member_builder.dart | 4 + .../lib/src/builder/property_builder.dart | 41 + pkg/front_end/lib/src/fragment/field.dart | 372 ++++- .../fragment/field/body_builder_context.dart | 74 + .../lib/src/fragment/field/class_member.dart | 339 +++++ .../lib/src/fragment/field/encoding.dart | 1326 +++++++++++++++++ pkg/front_end/lib/src/fragment/fragment.dart | 18 +- pkg/front_end/lib/src/fragment/getter.dart | 40 +- pkg/front_end/lib/src/fragment/setter.dart | 40 +- .../lib/src/kernel/body_builder.dart | 24 +- .../lib/src/kernel/body_builder_context.dart | 14 +- .../lib/src/kernel/expression_generator.dart | 4 + .../src/kernel/hierarchy/class_member.dart | 2 + .../lib/src/kernel/implicit_field_type.dart | 128 +- .../lib/src/kernel/kernel_target.dart | 52 +- .../lib/src/kernel/macro/introspectors.dart | 98 +- .../lib/src/kernel/macro/metadata.dart | 19 + .../src/source/constructor_declaration.dart | 6 +- .../lib/src/source/diet_listener.dart | 8 +- pkg/front_end/lib/src/source/offset_map.dart | 7 +- .../lib/src/source/source_class_builder.dart | 36 +- .../source/source_constructor_builder.dart | 34 +- ...ce_extension_type_declaration_builder.dart | 31 +- .../src/source/source_factory_builder.dart | 8 + .../lib/src/source/source_field_builder.dart | 147 +- .../src/source/source_library_builder.dart | 40 +- .../lib/src/source/source_member_builder.dart | 8 + .../lib/src/source/source_method_builder.dart | 8 + .../src/source/source_property_builder.dart | 527 ++++++- .../src/source/synthetic_method_builder.dart | 8 + .../source/type_parameter_scope_builder.dart | 207 +-- .../inference_visitor_base.dart | 9 +- .../test/coverage_suite_expected.dart | 59 +- .../application/macro_application_test.dart | 4 + pkg/front_end/test/testing/suite.dart | 3 +- 40 files changed, 3310 insertions(+), 468 deletions(-) create mode 100644 pkg/front_end/lib/src/builder/property_builder.dart create mode 100644 pkg/front_end/lib/src/fragment/field/body_builder_context.dart create mode 100644 pkg/front_end/lib/src/fragment/field/class_member.dart create mode 100644 pkg/front_end/lib/src/fragment/field/encoding.dart diff --git a/pkg/front_end/lib/src/base/incremental_compiler.dart b/pkg/front_end/lib/src/base/incremental_compiler.dart index f2ffaebb78a0..ca404aa34d99 100644 --- a/pkg/front_end/lib/src/base/incremental_compiler.dart +++ b/pkg/front_end/lib/src/base/incremental_compiler.dart @@ -73,7 +73,6 @@ import '../base/processed_options.dart' show ProcessedOptions; import '../builder/builder.dart' show Builder; import '../builder/declaration_builders.dart' show ClassBuilder, ExtensionBuilder, ExtensionTypeDeclarationBuilder; -import '../builder/field_builder.dart' show FieldBuilder; import '../builder/library_builder.dart' show CompilationUnit, LibraryBuilder, SourceCompilationUnit; import '../builder/member_builder.dart' show MemberBuilder; @@ -741,7 +740,9 @@ class IncrementalCompiler implements IncrementalKernelGenerator { if (sourceBuilder == null) { sourceBuilder = sourceLibraryBuilder.exportNameSpace .lookupLocalMember(name, setter: false); - if (sourceBuilder is FieldBuilder && sourceBuilder.isAssignable) { + if (sourceBuilder is MemberBuilder && + sourceBuilder.isField && + sourceBuilder.isAssignable) { // Assignable fields can be lowered into a getter and setter. return; } diff --git a/pkg/front_end/lib/src/base/scope.dart b/pkg/front_end/lib/src/base/scope.dart index 38b029d0e191..45bb7944da79 100644 --- a/pkg/front_end/lib/src/base/scope.dart +++ b/pkg/front_end/lib/src/base/scope.dart @@ -687,6 +687,14 @@ mixin ErroneousMemberBuilderMixin implements SourceMemberBuilder { // Coverage-ignore(suite): Not run. bool get isAbstract => false; + @override + // Coverage-ignore(suite): Not run. + bool get isFinal => false; + + @override + // Coverage-ignore(suite): Not run. + bool get isSynthesized => false; + @override bool get isConflictingSetter => false; @@ -1503,8 +1511,9 @@ extension on Builder { return _hasPatchAnnotation(self.metadata); } else if (self is SourceMethodBuilder) { return _hasPatchAnnotation(self.metadata); - } else if (self is SourceExtensionTypeDeclarationBuilder) { - // Coverage-ignore-block(suite): Not run. + } + // Coverage-ignore(suite): Not run. + else if (self is SourceExtensionTypeDeclarationBuilder) { return _hasPatchAnnotation(self.metadata); } return false; diff --git a/pkg/front_end/lib/src/builder/builder_mixins.dart b/pkg/front_end/lib/src/builder/builder_mixins.dart index 68bd1c3e08a3..2817a1472cd1 100644 --- a/pkg/front_end/lib/src/builder/builder_mixins.dart +++ b/pkg/front_end/lib/src/builder/builder_mixins.dart @@ -10,7 +10,6 @@ import '../base/problems.dart'; import '../base/scope.dart'; import 'builder.dart'; import 'declaration_builders.dart'; -import 'field_builder.dart'; import 'library_builder.dart'; import 'member_builder.dart'; import 'nullability_builder.dart'; @@ -96,16 +95,16 @@ mixin DeclarationBuilderMixin implements IDeclarationBuilder { if (builder == null && setter) { // When looking up setters, we include assignable fields. builder = lookupLocalMember(name.text, setter: false, required: required); - if (builder is! FieldBuilder || !builder.isAssignable) { + if (builder is! MemberBuilder || + !builder.isField || + !builder.isAssignable) { builder = null; } } if (builder != null) { if (name.isPrivate && libraryBuilder.library != name.library) { builder = null; - } else if (builder is FieldBuilder && - !builder.isStatic && - !builder.isExternal) { + } else if (builder.isField && !builder.isStatic && !builder.isExternal) { // Non-external extension instance fields are invalid. builder = null; } else if (builder.isDuplicate) { diff --git a/pkg/front_end/lib/src/builder/formal_parameter_builder.dart b/pkg/front_end/lib/src/builder/formal_parameter_builder.dart index 774db867a143..1d984b3d5d6c 100644 --- a/pkg/front_end/lib/src/builder/formal_parameter_builder.dart +++ b/pkg/front_end/lib/src/builder/formal_parameter_builder.dart @@ -19,13 +19,13 @@ import '../kernel/wildcard_lowering.dart'; import '../source/builder_factory.dart'; import '../source/constructor_declaration.dart'; import '../source/source_factory_builder.dart'; -import '../source/source_field_builder.dart'; import '../source/source_library_builder.dart'; import 'builder.dart'; import 'constructor_builder.dart'; import 'declaration_builders.dart'; import 'member_builder.dart'; import 'omitted_type_builder.dart'; +import 'property_builder.dart'; import 'type_builder.dart'; import 'variable_builder.dart'; @@ -229,7 +229,7 @@ class FormalParameterBuilder extends BuilderImpl ClassHierarchyBase hierarchy) { String fieldName = isWildcardLoweredFormalParameter(name) ? '_' : name; Builder? fieldBuilder = declarationBuilder.lookupLocalMember(fieldName); - if (fieldBuilder is SourceFieldBuilder) { + if (fieldBuilder is PropertyBuilder && fieldBuilder.isField) { DartType fieldType = fieldBuilder.inferType(hierarchy); fieldType = constructorDeclaration.substituteFieldType(fieldType); type.registerInferredType(fieldType); diff --git a/pkg/front_end/lib/src/builder/invalid_type_declaration_builder.dart b/pkg/front_end/lib/src/builder/invalid_type_declaration_builder.dart index b4dc83d1b060..fb8ec6ed405c 100644 --- a/pkg/front_end/lib/src/builder/invalid_type_declaration_builder.dart +++ b/pkg/front_end/lib/src/builder/invalid_type_declaration_builder.dart @@ -28,7 +28,7 @@ class InvalidTypeDeclarationBuilder extends TypeDeclarationBuilderImpl @override // Coverage-ignore(suite): Not run. - Uri? get fileUri => message.uri; + Uri get fileUri => message.uri!; @override DartType buildAliasedType( diff --git a/pkg/front_end/lib/src/builder/member_builder.dart b/pkg/front_end/lib/src/builder/member_builder.dart index 98af57c79f15..0c5c795268bc 100644 --- a/pkg/front_end/lib/src/builder/member_builder.dart +++ b/pkg/front_end/lib/src/builder/member_builder.dart @@ -186,6 +186,7 @@ abstract class BuilderClassMember implements ClassMember { Uri get fileUri => memberBuilder.fileUri; @override + // Coverage-ignore(suite): Not run. bool get isExtensionTypeMember => memberBuilder.isExtensionTypeMember; @override @@ -206,6 +207,7 @@ abstract class BuilderClassMember implements ClassMember { bool get isDuplicate => memberBuilder.isDuplicate; @override + // Coverage-ignore(suite): Not run. bool get isField => memberBuilder.isField; @override @@ -231,9 +233,11 @@ abstract class BuilderClassMember implements ClassMember { bool get isSynthesized => false; @override + // Coverage-ignore(suite): Not run. bool get isInternalImplementation => false; @override + // Coverage-ignore(suite): Not run. bool get isNoSuchMethodForwarder => false; @override diff --git a/pkg/front_end/lib/src/builder/property_builder.dart b/pkg/front_end/lib/src/builder/property_builder.dart new file mode 100644 index 000000000000..fe65c6242b99 --- /dev/null +++ b/pkg/front_end/lib/src/builder/property_builder.dart @@ -0,0 +1,41 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:kernel/ast.dart'; +import 'package:kernel/class_hierarchy.dart'; + +import 'member_builder.dart'; + +abstract class PropertyBuilder implements MemberBuilder { + bool get hasInitializer; + + @override + Uri get fileUri; + + bool get isExtensionTypeDeclaredInstanceField; + + bool get isLate; + + bool get isFinal; + + abstract DartType fieldType; + + DartType inferType(ClassHierarchyBase hierarchy); + + /// 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 buildInitializer(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}); +} diff --git a/pkg/front_end/lib/src/fragment/field.dart b/pkg/front_end/lib/src/fragment/field.dart index 0648f1569d53..93694e2faede 100644 --- a/pkg/front_end/lib/src/fragment/field.dart +++ b/pkg/front_end/lib/src/fragment/field.dart @@ -4,7 +4,7 @@ part of 'fragment.dart'; -class FieldFragment implements Fragment { +class FieldFragment implements Fragment, Inferable, InferredTypeListener { @override final String name; @@ -21,7 +21,9 @@ class FieldFragment implements Fragment { // fields. final bool isPrimaryConstructorField; - SourceFieldBuilder? _builder; + SourcePropertyBuilder? _builder; + + late final _FieldEncoding _encoding; FieldFragment( {required this.name, @@ -59,6 +61,7 @@ class FieldFragment implements Fragment { return result; } + // Coverage-ignore(suite): Not run. Token? get constInitializerToken { Token? result = _constInitializerToken; // Ensure that we don't hold onto the token. @@ -67,16 +70,377 @@ class FieldFragment implements Fragment { } @override - SourceFieldBuilder get builder { + SourcePropertyBuilder get builder { assert(_builder != null, "Builder has not been computed for $this."); return _builder!; } - void set builder(SourceFieldBuilder value) { + void set builder(SourcePropertyBuilder value) { assert(_builder == null, "Builder has already been computed for $this."); _builder = value; + + SourceLibraryBuilder libraryBuilder = builder.libraryBuilder; + + bool isAbstract = modifiers.isAbstract; + bool isExternal = modifiers.isExternal; + bool isInstanceMember = builder.isDeclarationInstanceMember; + bool isExtensionMember = builder.isExtensionMember; + bool isExtensionTypeMember = builder.isExtensionTypeMember; + + // 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) { + _encoding = new AbstractOrExternalFieldEncoding(this, + isExtensionInstanceMember: isExtensionMember && isInstanceMember, + isExtensionTypeInstanceMember: + isExtensionTypeMember && isInstanceMember, + isAbstract: isAbstract, + isExternal: isExternal); + } else if (isExtensionTypeMember && isInstanceMember) { + if (isPrimaryConstructorField) { + _encoding = new RepresentationFieldEncoding(this); + } else { + // Field on a extension type. Encode as abstract. + // TODO(johnniwinther): Should we have an erroneous flag on such + // members? + _encoding = new AbstractOrExternalFieldEncoding(this, + isExtensionInstanceMember: isExtensionMember && isInstanceMember, + isExtensionTypeInstanceMember: + isExtensionTypeMember && isInstanceMember, + isAbstract: true, + isExternal: false, + isForcedExtension: true); + } + } else if (isLate && + libraryBuilder.loader.target.backendTarget.isLateFieldLoweringEnabled( + hasInitializer: hasInitializer, + isFinal: isFinal, + isStatic: !isInstanceMember)) { + if (hasInitializer) { + if (isFinal) { + _encoding = new LateFinalFieldWithInitializerEncoding(this, + isSetStrategy: isSetStrategy); + } else { + _encoding = new LateFieldWithInitializerEncoding(this, + isSetStrategy: isSetStrategy); + } + } else { + if (isFinal) { + _encoding = new LateFinalFieldWithoutInitializerEncoding(this, + isSetStrategy: isSetStrategy); + } else { + _encoding = new LateFieldWithoutInitializerEncoding(this, + isSetStrategy: isSetStrategy); + } + } + } else if (libraryBuilder + .loader.target.backendTarget.useStaticFieldLowering && + !isInstanceMember && + !modifiers.isConst && + hasInitializer) { + if (isFinal) { + _encoding = new LateFinalFieldWithInitializerEncoding(this, + isSetStrategy: isSetStrategy); + } else { + _encoding = new LateFieldWithInitializerEncoding(this, + isSetStrategy: isSetStrategy); + } + } else { + _encoding = new RegularFieldEncoding(this, isEnumElement: false); + } + + type.registerInferredTypeListener(this); + Token? token = initializerToken; + if (type is InferableTypeBuilder) { + if (!modifiers.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. + _encoding.type = + new InferredType.fromFieldFragmentInitializer(this, token); + type.registerInferable(this); + } + } + } + + BodyBuilderContext createBodyBuilderContext() { + return new _FieldFragmentBodyBuilderContext( + this, builder.libraryBuilder, builder.declarationBuilder, + isDeclarationInstanceMember: builder.isDeclarationInstanceMember); + } + + /// Registers that a `super` call has occurred in the initializer of this + /// field. + void registerSuperCall() { + _encoding.registerSuperCall(); + } + + void buildOutlineNode(SourceLibraryBuilder libraryBuilder, + NameScheme nameScheme, BuildNodesCallback f, FieldReference references, + {required List? classTypeParameters}) { + _encoding.buildOutlineNode(libraryBuilder, nameScheme, references, + isAbstractOrExternal: modifiers.isAbstract || modifiers.isExternal, + classTypeParameters: classTypeParameters); + if (type is! InferableTypeBuilder) { + fieldType = type.build(libraryBuilder, TypeUse.fieldType); + } + _encoding.registerMembers(f); + } + + Iterable getExportedMemberReferences(FieldReference references) { + return [ + references.getterReference!, + if (hasSetter) references.setterReference! + ]; + } + + shared.Expression? _initializerExpression; + + // Coverage-ignore(suite): Not run. + shared.Expression? get initializerExpression => _initializerExpression; + + void buildOutlineExpressions( + ClassHierarchy classHierarchy, + SourceLibraryBuilder libraryBuilder, + DeclarationBuilder? declarationBuilder, + LookupScope parentScope, + List annotatables, + {required bool isClassInstanceMember, + required bool createFileUriExpression}) { + BodyBuilderContext bodyBuilderContext = createBodyBuilderContext(); + for (Annotatable annotatable in annotatables) { + _buildMetadataForOutlineExpressions(libraryBuilder, parentScope, + bodyBuilderContext, annotatable, metadata, + fileUri: fileUri, createFileUriExpression: createFileUriExpression); + } + // 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 ((modifiers.isConst || + (isFinal && + isClassInstanceMember && + (declarationBuilder as SourceClassBuilder) + .declaresConstConstructor)) && + _constInitializerToken != null) { + Token initializerToken = _constInitializerToken!; + LookupScope scope = declarationBuilder?.scope ?? libraryBuilder.scope; + BodyBuilder bodyBuilder = libraryBuilder.loader + .createBodyBuilderForOutlineExpression( + libraryBuilder, createBodyBuilderContext(), scope, fileUri); + bodyBuilder.constantContext = modifiers.isConst + ? ConstantContext.inferred + : ConstantContext.required; + Expression initializer = bodyBuilder.typeInferrer + .inferFieldInitializer(bodyBuilder, fieldType, + bodyBuilder.parseFieldInitializer(initializerToken)) + .expression; + buildBody(classHierarchy.coreTypes, initializer); + bodyBuilder.performBacklogComputations(); + if (computeSharedExpressionForTesting) { + // Coverage-ignore-block(suite): Not run. + _initializerExpression = parseFieldInitializer(libraryBuilder.loader, + initializerToken, libraryBuilder.importUri, fileUri, scope); + } + } + _constInitializerToken = null; + } + + void checkTypes(SourceLibraryBuilder libraryBuilder, + TypeEnvironment typeEnvironment, SourcePropertyBuilder? setterBuilder, + {required bool isAbstract, required bool isExternal}) { + libraryBuilder.checkTypesInField(typeEnvironment, + isInstanceMember: builder.isDeclarationInstanceMember, + isLate: isLate, + isExternal: isExternal, + hasInitializer: hasInitializer, + fieldType: fieldType, + name: name, + nameLength: name.length, + nameOffset: nameOffset, + fileUri: fileUri); + } + + void ensureTypes( + ClassMembersBuilder membersBuilder, + Set? getterOverrideDependencies, + Set? setterOverrideDependencies) { + if (getterOverrideDependencies != null || + setterOverrideDependencies != null) { + membersBuilder.inferFieldType( + builder.declarationBuilder as SourceClassBuilder, + type, + [...?getterOverrideDependencies, ...?setterOverrideDependencies], + name: name, + fileUri: fileUri, + nameOffset: nameOffset, + nameLength: name.length, + isAssignable: hasSetter); + } else { + type.build(builder.libraryBuilder, TypeUse.fieldType, + hierarchy: membersBuilder.hierarchyBuilder); + } + } + + void checkVariance( + SourceClassBuilder sourceClassBuilder, TypeEnvironment typeEnvironment) { + sourceClassBuilder.checkVarianceInField(typeEnvironment, + fieldType: fieldType, + isInstanceMember: !_isStatic, + hasSetter: hasSetter, + isCovariantByDeclaration: modifiers.isCovariant, + fileUri: fileUri, + fileOffset: nameOffset); } + int computeDefaultTypes(ComputeDefaultTypeContext context) { + if (type is! OmittedTypeBuilder) { + context.reportInboundReferenceIssuesForType(type); + context.recursivelyReportGenericFunctionTypesAsBoundsForType(type); + } + return 0; + } + + Member get readTarget => _encoding.readTarget; + + Member? get writeTarget => _encoding.writeTarget; + + /// 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; + + /// Builds the body of this field using [initializer] as the initializer + /// expression. + void buildBody(CoreTypes coreTypes, Expression? initializer) { + assert(!hasBodyBeenBuilt, "Body has already been built for $this."); + hasBodyBeenBuilt = true; + if (!modifiers.hasInitializer && + initializer != null && + initializer is! NullLiteral && + // Coverage-ignore(suite): Not run. + !modifiers.isConst && + // Coverage-ignore(suite): Not run. + !modifiers.isFinal) { + internalProblem( + messageInternalProblemAlreadyInitialized, nameOffset, fileUri); + } + _encoding.createBodies(coreTypes, initializer); + } + + DartType get fieldType => _encoding.type; + + @override + void inferTypes(ClassHierarchyBase hierarchy) { + inferType(hierarchy); + } + + DartType inferType(ClassHierarchyBase hierarchy) { + if (fieldType is! InferredType) { + // We have already inferred a type. + return fieldType; + } + + return builder.libraryBuilder.loader + .withUriForCrashReporting(fileUri, nameOffset, () { + 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); + + // TODO(johnniwinther): Isn't this handled in the [fieldType] setter? + IncludesTypeParametersNonCovariantly? needsCheckVisitor; + DeclarationBuilder? declarationBuilder = builder.declarationBuilder; + if (declarationBuilder is ClassBuilder) { + Class enclosingClass = declarationBuilder.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)) { + _encoding.setCovariantByClass(); + } + } + } + return fieldType; + }); + } + + void set fieldType(DartType value) { + _encoding.type = value; + DeclarationBuilder? declarationBuilder = builder.declarationBuilder; + // TODO(johnniwinther): Should this be `hasSetter`? + if (!isFinal && !modifiers.isConst && declarationBuilder is ClassBuilder) { + Class enclosingClass = declarationBuilder.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)) { + _encoding.setCovariantByClass(); + } + } + } + } + + Initializer buildErroneousInitializer(Expression effect, Expression value, + {required int fileOffset}) { + return _encoding.buildErroneousInitializer(effect, value, + fileOffset: fileOffset); + } + + void buildImplicitDefaultValue() { + _encoding.buildImplicitDefaultValue(); + } + + Initializer buildImplicitInitializer() { + return _encoding.buildImplicitInitializer(); + } + + List buildInitializer(int fileOffset, Expression value, + {required bool isSynthetic}) { + return _encoding.createInitializer(fileOffset, value, + isSynthetic: isSynthetic); + } + + bool get hasInitializer => modifiers.hasInitializer; + + bool get isExtensionTypeDeclaredInstanceField => + builder.isExtensionTypeInstanceMember && !isPrimaryConstructorField; + + bool get isFinal => modifiers.isFinal; + + bool get isLate => modifiers.isLate; + + bool get _isStatic => + modifiers.isStatic || builder.declarationBuilder == null; + @override String toString() => '$runtimeType($name,$fileUri,$nameOffset)'; + + @override + void onInferredType(DartType type) { + fieldType = type; + } + + List get localMembers => _encoding.localMembers; + + List get localSetters => _encoding.localSetters; } diff --git a/pkg/front_end/lib/src/fragment/field/body_builder_context.dart b/pkg/front_end/lib/src/fragment/field/body_builder_context.dart new file mode 100644 index 000000000000..a79fcb5fed58 --- /dev/null +++ b/pkg/front_end/lib/src/fragment/field/body_builder_context.dart @@ -0,0 +1,74 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +part of '../fragment.dart'; + +class _FieldFragmentBodyBuilderContext extends BodyBuilderContext { + final FieldFragment _fragment; + + _FieldFragmentBodyBuilderContext( + this._fragment, + SourceLibraryBuilder libraryBuilder, + DeclarationBuilder? declarationBuilder, + {required bool isDeclarationInstanceMember}) + : super(libraryBuilder, declarationBuilder, + isDeclarationInstanceMember: isDeclarationInstanceMember); + + @override + // Coverage-ignore(suite): Not run. + LocalScope computeFormalParameterInitializerScope(LocalScope parent) { + /// Initializer formals or super parameters cannot occur in getters so + /// we don't need to create a new scope. + return parent; + } + + @override + bool get isLateField => _fragment.modifiers.isLate; + + @override + bool get isAbstractField => _fragment.modifiers.isAbstract; + + @override + bool get isExternalField => _fragment.modifiers.isExternal; + + @override + // Coverage-ignore(suite): Not run. + int get memberNameOffset => _fragment.nameOffset; + + @override + // Coverage-ignore(suite): Not run. + int get memberNameLength => _fragment.name.length; + + @override + InstanceTypeParameterAccessState get instanceTypeParameterAccessState { + if (_fragment.builder.isExtensionMember && !isExternalField) { + return InstanceTypeParameterAccessState.Invalid; + } else { + return super.instanceTypeParameterAccessState; + } + } + + @override + void registerSuperCall() { + _fragment.registerSuperCall(); + } + + @override + // Coverage-ignore(suite): Not run. + AugmentSuperTarget? get augmentSuperTarget { + if (_fragment.builder.isAugmentation) { + return _fragment.builder.augmentSuperTarget; + } + return null; + } + + @override + ConstantContext get constantContext { + return _fragment.modifiers.isConst + ? ConstantContext.inferred + : !_fragment._isStatic && declarationDeclaresConstConstructor + ? ConstantContext.required + : ConstantContext.none; + } +} diff --git a/pkg/front_end/lib/src/fragment/field/class_member.dart b/pkg/front_end/lib/src/fragment/field/class_member.dart new file mode 100644 index 000000000000..8d0daa02149a --- /dev/null +++ b/pkg/front_end/lib/src/fragment/field/class_member.dart @@ -0,0 +1,339 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +part of '../fragment.dart'; + +class _FieldClassMember implements ClassMember { + final SourcePropertyBuilder _builder; + final FieldFragment _fragment; + + @override + final bool forSetter; + + Covariance? _covariance; + + _FieldClassMember(this._builder, this._fragment, {required this.forSetter}); + + @override + int get charOffset => _fragment.nameOffset; + + @override + DeclarationBuilder get declarationBuilder => _builder.declarationBuilder!; + + @override + // Coverage-ignore(suite): Not run. + List get declarations => + throw new UnsupportedError('$runtimeType.declarations'); + + @override + Uri get fileUri => _fragment.fileUri; + + @override + // Coverage-ignore(suite): Not run. + String get fullName { + String className = declarationBuilder.fullNameForErrors; + return "${className}.${fullNameForErrors}"; + } + + @override + String get fullNameForErrors => _builder.fullNameForErrors; + + @override + Covariance getCovariance(ClassMembersBuilder membersBuilder) { + return _covariance ??= forSetter + ? new Covariance.fromMember(getMember(membersBuilder), + forSetter: forSetter) + : const Covariance.empty(); + } + + @override + Member getMember(ClassMembersBuilder membersBuilder) { + _builder.ensureTypes(membersBuilder); + return forSetter ? _builder.writeTarget! : _builder.readTarget!; + } + + @override + // Coverage-ignore(suite): Not run. + MemberResult getMemberResult(ClassMembersBuilder membersBuilder) { + if (isStatic) { + return new StaticMemberResult(getMember(membersBuilder), memberKind, + isDeclaredAsField: true, + fullName: '${declarationBuilder.name}.${_builder.memberName.text}'); + } else if (_builder.isExtensionTypeMember) { + ExtensionTypeDeclaration extensionTypeDeclaration = + (declarationBuilder as ExtensionTypeDeclarationBuilder) + .extensionTypeDeclaration; + Member member = getTearOff(membersBuilder) ?? getMember(membersBuilder); + return new ExtensionTypeMemberResult( + extensionTypeDeclaration, member, memberKind, name, + isDeclaredAsField: true); + } else { + return new TypeDeclarationInstanceMemberResult( + getMember(membersBuilder), memberKind, + isDeclaredAsField: true); + } + } + + @override + // Coverage-ignore(suite): Not run. + Member? getTearOff(ClassMembersBuilder membersBuilder) => null; + + @override + bool get hasDeclarations => false; + + @override + void inferType(ClassMembersBuilder membersBuilder) { + _builder.ensureTypes(membersBuilder); + } + + @override + ClassMember get interfaceMember => this; + + @override + // TODO(johnniwinther): This should not be determined by the builder. A + // property can have a non-abstract getter and an abstract setter or the + // reverse. With augmentations, abstract introductory declarations might even + // be implemented by augmentations. + bool get isAbstract => _fragment.modifiers.isAbstract; + + @override + bool get isDuplicate => _builder.isDuplicate; + + @override + bool get isExtensionTypeMember => _builder.isExtensionTypeMember; + + @override + bool get isField => true; + + @override + // Coverage-ignore(suite): Not run. + bool get isGetter => false; //!forSetter; + + @override + bool get isInternalImplementation => false; + + @override + bool get isNoSuchMethodForwarder => false; + + @override + // Coverage-ignore(suite): Not run. + bool isObjectMember(ClassBuilder objectClass) { + return declarationBuilder == objectClass; + } + + @override + bool get isProperty => true; + + @override + bool isSameDeclaration(ClassMember other) { + return other is _FieldClassMember && _builder == other._builder; + } + + @override + bool get isSetter => false; //forSetter; + + @override + bool get isSourceDeclaration => true; + + @override + bool get isStatic => _fragment.modifiers.isStatic; + + @override + bool get isSynthesized => false; + + @override + ClassMemberKind get memberKind => + forSetter ? ClassMemberKind.Setter : ClassMemberKind.Getter; + + @override + Name get name => _builder.memberName; + + @override + void registerOverrideDependency(Set overriddenMembers) { + if (forSetter) { + _builder.registerSetterOverrideDependency(overriddenMembers); + } else { + _builder.registerGetterOverrideDependency(overriddenMembers); + } + } + + @override + String toString() => '$runtimeType($fullName,forSetter=${forSetter})'; +} + +class _SynthesizedFieldClassMember implements ClassMember { + final SourcePropertyBuilder _builder; + final _SynthesizedFieldMemberKind _kind; + + final Member _member; + + final Name _name; + + Covariance? _covariance; + + @override + final ClassMemberKind memberKind; + + _SynthesizedFieldClassMember( + this._builder, this._member, this._name, this._kind, this.memberKind); + + @override + bool get isInternalImplementation => _kind.isInternalImplementation; + + @override + Member getMember(ClassMembersBuilder membersBuilder) { + _builder.ensureTypes(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: _builder.isField); + } + + @override + void inferType(ClassMembersBuilder membersBuilder) { + _builder.ensureTypes(membersBuilder); + } + + @override + void registerOverrideDependency(Set overriddenMembers) { + if (forSetter) { + _builder.registerSetterOverrideDependency(overriddenMembers); + } else { + _builder.registerGetterOverrideDependency(overriddenMembers); + } + } + + @override + bool get isSourceDeclaration => true; + + @override + bool get forSetter => memberKind == ClassMemberKind.Setter; + + @override + bool get isProperty => memberKind != ClassMemberKind.Method; + + @override + DeclarationBuilder get declarationBuilder => _builder.declarationBuilder!; + + @override + // Coverage-ignore(suite): Not run. + bool isObjectMember(ClassBuilder objectClass) { + return declarationBuilder == objectClass; + } + + @override + bool get isDuplicate => _builder.isDuplicate; + + @override + bool get isStatic => _builder.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 => _builder.fullNameForErrors; + + @override + Uri get fileUri => _builder.fileUri; + + @override + int get charOffset => _builder.fileOffset; + + @override + bool get isAbstract => _member.isAbstract; + + @override + bool get isSynthesized => false; + + @override + bool get hasDeclarations => false; + + @override + // Coverage-ignore(suite): Not run. + List 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 && + _builder == other._builder && + _kind == other._kind; + } + + @override + bool get isNoSuchMethodForwarder => false; + + @override + String toString() => '_SynthesizedFieldClassMember(' + '$_builder,$_member,$_kind,forSetter=${forSetter})'; + + @override + bool get isExtensionTypeMember => _builder.isExtensionTypeMember; +} + +enum _SynthesizedFieldMemberKind { + /// A `isSet` field used for late lowering. + LateIsSet(isInternalImplementation: true), + + /// A field used for the value of a late lowered field. + LateField(isInternalImplementation: true), + + /// A getter or setter used for late lowering. + LateGetterSetter(isInternalImplementation: false), + + /// A getter or setter used for abstract or external fields. + AbstractExternalGetterSetter(isInternalImplementation: false), + + /// A getter for an extension type declaration representation field. + RepresentationField(isInternalImplementation: false), + ; + + final bool isInternalImplementation; + + const _SynthesizedFieldMemberKind({required this.isInternalImplementation}); +} diff --git a/pkg/front_end/lib/src/fragment/field/encoding.dart b/pkg/front_end/lib/src/fragment/field/encoding.dart new file mode 100644 index 000000000000..4aaf45d59667 --- /dev/null +++ b/pkg/front_end/lib/src/fragment/field/encoding.dart @@ -0,0 +1,1326 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +part of '../fragment.dart'; + +/// Strategy pattern for creating different encodings of a declared field. +/// +/// This is used to provide lowerings for late fields using synthesized getters +/// and setters. +sealed class _FieldEncoding { + /// 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 buildOutlineNode(SourceLibraryBuilder libraryBuilder, + NameScheme nameScheme, FieldReference references, + {required bool isAbstractOrExternal, + required List? classTypeParameters}); + + /// Calls [f] for each member needed for this field encoding. + void registerMembers(BuildNodesCallback f); + + /// 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); + + /// The type of the declared field. + abstract DartType type; + + List 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 setCovariantByClass(); + + /// Returns the field that holds the field value at runtime. + Field get field; + + /// The [Member] built during [SourceFieldBuilder.buildOutlineExpressions]. + Member get builtMember; + + /// Returns the members that holds the field annotations. + Iterable get annotatables; + + /// Returns the member used to read the field value. + Member get readTarget; + + /// Returns the reference used to read the field value. + Reference get readTargetReference; + + /// Returns the member used to write to the field. + Member? get writeTarget; + + /// Returns the reference used to write to the field. + Reference? get writeTargetReference; + + /// Returns the references to the generated members that are visible through + /// exports. + /// + /// This is the getter reference, and, if available, the setter reference. + Iterable get exportedReferenceMembers; + + /// Returns a list of the field, getters and methods created by this field + /// encoding. + List get localMembers; + + /// Returns a list of the setters created by this field encoding. + List get localSetters; + + /// Registers that a `super` call has occurred in the initializer of this + /// field. + void registerSuperCall(); +} + +class RegularFieldEncoding implements _FieldEncoding { + final FieldFragment _fragment; + final bool isEnumElement; + Field? _field; + DartType _type = const DynamicType(); + + RegularFieldEncoding(this._fragment, {required this.isEnumElement}) {} + + @override + DartType get type => _type; + + @override + void set type(DartType value) { + _type = value; + _field?.type = value; + } + + @override + void createBodies(CoreTypes coreTypes, Expression? initializer) { + if (initializer != null) { + _field!.initializer = initializer..parent = _field; + } + } + + @override + List createInitializer(int fileOffset, Expression value, + {required bool isSynthetic}) { + return [ + new FieldInitializer(_field!, value) + ..fileOffset = fileOffset + ..isSynthetic = isSynthetic + ]; + } + + @override + void buildOutlineNode(SourceLibraryBuilder libraryBuilder, + NameScheme nameScheme, FieldReference references, + {required bool isAbstractOrExternal, + required List? classTypeParameters}) { + bool isImmutable = _fragment.modifiers.isLate + ? (_fragment.modifiers.isFinal && _fragment.hasInitializer) + : (_fragment.modifiers.isFinal || _fragment.modifiers.isConst); + _field = isImmutable + ? new Field.immutable(dummyName, + type: _type, + isFinal: _fragment.modifiers.isFinal, + isConst: _fragment.modifiers.isConst, + isLate: _fragment.modifiers.isLate, + fileUri: _fragment.fileUri, + fieldReference: references.fieldReference, + getterReference: references.fieldGetterReference, + isEnumElement: isEnumElement) + : new Field.mutable(dummyName, + type: _type, + isFinal: _fragment.modifiers.isFinal, + isLate: _fragment.modifiers.isLate, + fileUri: _fragment.fileUri, + fieldReference: references.fieldReference, + getterReference: references.fieldGetterReference, + setterReference: references.fieldSetterReference); + nameScheme + .getFieldMemberName(FieldNameType.Field, _fragment.name, + isSynthesized: false) + .attachMember(_field!); + _field! + ..fileOffset = _fragment.nameOffset + ..fileEndOffset = _fragment.endOffset; + _field!..isCovariantByDeclaration = _fragment.modifiers.isCovariant; + if (_fragment.builder.isExtensionMember) { + _field! + ..isStatic = true + ..isExtensionMember = true; + } else if (_fragment.builder.isExtensionTypeMember) { + _field! + ..isStatic = _fragment.builder.isStatic + ..isExtensionTypeMember = true; + } else { + bool isInstanceMember = + !_fragment.builder.isStatic && !_fragment.builder.isTopLevel; + _field! + ..isStatic = !isInstanceMember + ..isExtensionMember = false; + } + _field!.isLate = _fragment.modifiers.isLate; + } + + @override + void registerMembers(BuildNodesCallback f) { + f( + member: _field!, + kind: _fragment.builder.isExtensionMember || + _fragment.builder.isExtensionTypeMember + ? BuiltMemberKind.ExtensionField + : BuiltMemberKind.Field); + } + + @override + void setCovariantByClass() { + if (_field!.hasSetter) { + _field!.isCovariantByClass = true; + } + } + + @override + // Coverage-ignore(suite): Not run. + Field get field => _field!; + + @override + // Coverage-ignore(suite): Not run. + Member get builtMember => _field!; + + @override + // Coverage-ignore(suite): Not run. + Iterable get annotatables => [_field!]; + + @override + Member get readTarget => _field!; + + @override + // Coverage-ignore(suite): Not run. + Reference get readTargetReference => _field!.getterReference; + + @override + Member get writeTarget => _field!; + + @override + // Coverage-ignore(suite): Not run. + Reference? get writeTargetReference => _field!.setterReference; + + @override + // Coverage-ignore(suite): Not run. + Iterable get exportedReferenceMembers => [ + _field!.getterReference, + if (_field!.hasSetter) _field!.setterReference! + ]; + + @override + List get localMembers => [ + new _FieldClassMember(_fragment.builder, _fragment, forSetter: false) + ]; + + @override + List get localSetters => _fragment.hasSetter + ? [new _FieldClassMember(_fragment.builder, _fragment, forSetter: true)] + : const []; + + @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; + } + + @override + void registerSuperCall() { + _field!.transformerFlags |= TransformerFlag.superCalls; + } +} + +abstract class AbstractLateFieldEncoding implements _FieldEncoding { + final FieldFragment _fragment; + DartType? _type; + Field? _field; + Field? _lateIsSetField; + 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._fragment, + {required late_lowering.IsSetStrategy isSetStrategy}) + : _isSetStrategy = isSetStrategy, + _forceIncludeIsSetField = + isSetStrategy == late_lowering.IsSetStrategy.forceUseIsSetField {} + + late_lowering.IsSetEncoding get isSetEncoding { + assert(_type != null, + "Type has not been computed for field ${_fragment.name}."); + return _isSetEncoding ??= + late_lowering.computeIsSetEncoding(_type!, _isSetStrategy); + } + + @override + void createBodies(CoreTypes coreTypes, Expression? initializer) { + assert(_type != null, + "Type has not been computed for field ${_fragment.name}."); + if (isSetEncoding == late_lowering.IsSetEncoding.useSentinel) { + _field!.initializer = new StaticInvocation(coreTypes.createSentinelMethod, + new Arguments([], types: [_type!])..fileOffset = _fragment.nameOffset) + ..fileOffset = _fragment.nameOffset + ..parent = _field; + } else { + _field!.initializer = new NullLiteral() + ..fileOffset = _fragment.nameOffset + ..parent = _field; + } + if (_lateIsSetField != null) { + _lateIsSetField!.initializer = new BoolLiteral(false) + ..fileOffset = _fragment.nameOffset + ..parent = _lateIsSetField; + } + _lateGetter!.function.body = + _createGetterBody(coreTypes, _fragment.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, _fragment.name, + _lateSetter!.function.positionalParameters.first) + ..parent = _lateSetter!.function; + } + } + + @override + List createInitializer(int fileOffset, Expression value, + {required bool isSynthetic}) { + List initializers = []; + 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 parameter type of undetermined + /// nullability. + Expression _createFieldRead({bool needsPromotion = false}) { + assert(_type != null, + "Type has not been computed for field ${_fragment.name}."); + if (needsPromotion) { + VariableDeclaration variable = new VariableDeclaration.forValue( + _createFieldGet(_field!), + type: _type!.withDeclaredNullability(Nullability.nullable)) + ..fileOffset = _fragment.nameOffset; + return new Let(variable, + new VariableGet(variable, _type)..fileOffset = _fragment.nameOffset); + } else { + return _createFieldGet(_field!); + } + } + + /// Creates an [Expression] that reads [field]. + Expression _createFieldGet(Field field) { + if (field.isStatic) { + return new StaticGet(field)..fileOffset = _fragment.nameOffset; + } else { + // No substitution needed for the result type, since any type parameters + // in there are also in scope at the access site. + return new InstanceGet(InstanceAccessKind.Instance, + new ThisExpression()..fileOffset = _fragment.nameOffset, field.name, + interfaceTarget: field, resultType: field.type) + ..fileOffset = _fragment.nameOffset; + } + } + + /// Creates an [Expression] that writes [value] to [field]. + Expression _createFieldSet(Field field, Expression value) { + if (field.isStatic) { + return new StaticSet(field, value)..fileOffset = _fragment.nameOffset; + } else { + return new InstanceSet( + InstanceAccessKind.Instance, + new ThisExpression()..fileOffset = _fragment.nameOffset, + field.name, + value, + interfaceTarget: field) + ..fileOffset = _fragment.nameOffset; + } + } + + Statement _createGetterBody( + CoreTypes coreTypes, String name, Expression? initializer); + + Procedure? _createSetter(Uri fileUri, int charOffset, Reference? reference, + {required bool isCovariantByDeclaration}) { + VariableDeclaration parameter = + new VariableDeclaration("${_fragment.name}#param") + ..isCovariantByDeclaration = isCovariantByDeclaration + ..fileOffset = _fragment.nameOffset; + return new Procedure( + dummyName, + ProcedureKind.Setter, + new FunctionNode(null, + positionalParameters: [parameter], returnType: const VoidType()) + ..fileOffset = charOffset + ..fileEndOffset = _fragment.endOffset, + fileUri: fileUri, + reference: reference) + ..fileOffset = charOffset + ..fileEndOffset = _fragment.endOffset; + } + + Statement _createSetterBody( + CoreTypes coreTypes, String name, VariableDeclaration parameter); + + @override + DartType get type { + assert(_type != null, + "Type has not been computed for field ${_fragment.name}."); + return _type!; + } + + /// Updates the field/getter/setter types of [_field], [_lateGetter] and + /// [_lateSetter] to match the value of [_type]. + /// + /// This allows for creating the members and computing the type in arbitrary + /// order. + void _updateMemberTypes() { + DartType? type = _type; + Field? field = _field; + if (type != null && type is! InferredType && field != null) { + field.type = type.withDeclaredNullability(Nullability.nullable); + _lateGetter!.function.returnType = type; + _lateSetter?.function.positionalParameters.single.type = type; + 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 set type(DartType value) { + assert(_type == null || _type is InferredType, + "Type has already been computed for field ${_fragment.name}."); + _type = value; + _updateMemberTypes(); + } + + @override + void setCovariantByClass() { + if (_field!.hasSetter) { + _field!.isCovariantByClass = true; + } + _lateSetter?.function.positionalParameters.single.isCovariantByClass = true; + } + + @override + Field get field => _field!; + + @override + // Coverage-ignore(suite): Not run. + Member get builtMember => _field!; + + @override + // Coverage-ignore(suite): Not run. + Iterable get annotatables { + List list = [_lateGetter!]; + if (_lateSetter != null) { + list.add(_lateSetter!); + } + return list; + } + + @override + Member get readTarget => _lateGetter!; + + @override + // Coverage-ignore(suite): Not run. + Reference get readTargetReference => _lateGetter!.reference; + + @override + Member? get writeTarget => _lateSetter; + + @override + // Coverage-ignore(suite): Not run. + Reference? get writeTargetReference => _lateSetter?.reference; + + @override + // Coverage-ignore(suite): Not run. + Iterable get exportedReferenceMembers { + if (_lateSetter != null) { + return [_lateGetter!.reference, _lateSetter!.reference]; + } + return [_lateGetter!.reference]; + } + + @override + void buildOutlineNode(SourceLibraryBuilder libraryBuilder, + NameScheme nameScheme, FieldReference references, + {required bool isAbstractOrExternal, + required List? classTypeParameters}) { + _field = new Field.mutable(dummyName, + fileUri: _fragment.fileUri, + fieldReference: references.fieldReference, + getterReference: references.fieldGetterReference, + setterReference: references.fieldSetterReference) + ..fileOffset = _fragment.nameOffset + ..fileEndOffset = _fragment.endOffset + ..isInternalImplementation = true; + nameScheme + .getFieldMemberName(FieldNameType.Field, _fragment.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: _fragment.fileUri, + fieldReference: references.lateIsSetFieldReference, + getterReference: references.lateIsSetGetterReference, + setterReference: references.lateIsSetSetterReference) + ..fileOffset = _fragment.nameOffset + ..fileEndOffset = _fragment.endOffset + ..isInternalImplementation = true; + nameScheme + .getFieldMemberName(FieldNameType.IsSetField, _fragment.name, + isSynthesized: true) + .attachMember(_lateIsSetField!); + break; + } + _lateGetter = new Procedure( + dummyName, + ProcedureKind.Getter, + new FunctionNode(null) + ..fileOffset = _fragment.nameOffset + ..fileEndOffset = _fragment.endOffset, + fileUri: _fragment.fileUri, + reference: references.lateGetterReference) + ..fileOffset = _fragment.nameOffset + ..fileEndOffset = _fragment.endOffset; + nameScheme + .getFieldMemberName(FieldNameType.Getter, _fragment.name, + isSynthesized: true) + .attachMember(_lateGetter!); + _lateSetter = _createSetter( + _fragment.fileUri, _fragment.nameOffset, references.lateSetterReference, + isCovariantByDeclaration: _fragment.modifiers.isCovariant); + if (_lateSetter != null) { + nameScheme + .getFieldMemberName(FieldNameType.Setter, _fragment.name, + isSynthesized: true) + .attachMember(_lateSetter!); + } + + bool isInstanceMember = + !_fragment.builder.isStatic && !_fragment.builder.isTopLevel; + bool isExtensionMember = _fragment.builder.isExtensionMember; + bool isExtensionTypeMember = _fragment.builder.isExtensionTypeMember; + if (isExtensionMember) { + _field! + ..isStatic = true + ..isExtensionMember = isExtensionMember; + isInstanceMember = false; + } else if (isExtensionTypeMember) { + // Coverage-ignore-block(suite): Not run. + _field! + ..isStatic = _fragment.builder.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; + } + _updateMemberTypes(); + } + + @override + void registerMembers(BuildNodesCallback f) { + f( + member: _field!, + kind: _fragment.builder.isExtensionMember || + _fragment.builder.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 get localMembers { + List list = [ + new _SynthesizedFieldClassMember(_fragment.builder, field, field.name, + _SynthesizedFieldMemberKind.LateField, ClassMemberKind.Getter), + new _SynthesizedFieldClassMember( + _fragment.builder, + _lateGetter!, + _fragment.builder.memberName, + _SynthesizedFieldMemberKind.LateGetterSetter, + ClassMemberKind.Getter) + ]; + if (_lateIsSetField != null) { + list.add(new _SynthesizedFieldClassMember( + _fragment.builder, + _lateIsSetField!, + _lateIsSetField!.name, + _SynthesizedFieldMemberKind.LateIsSet, + ClassMemberKind.Getter)); + } + return list; + } + + @override + List get localSetters { + List list = [ + new _SynthesizedFieldClassMember(_fragment.builder, field, field.name, + _SynthesizedFieldMemberKind.LateField, ClassMemberKind.Setter), + ]; + if (_lateIsSetField != null) { + list.add(new _SynthesizedFieldClassMember( + _fragment.builder, + _lateIsSetField!, + _lateIsSetField!.name, + _SynthesizedFieldMemberKind.LateIsSet, + ClassMemberKind.Setter)); + } + if (_lateSetter != null) { + list.add(new _SynthesizedFieldClassMember( + _fragment.builder, + _lateSetter!, + _fragment.builder.memberName, + _SynthesizedFieldMemberKind.LateGetterSetter, + ClassMemberKind.Setter)); + } + return list; + } + + @override + void registerSuperCall() { + _field!.transformerFlags |= TransformerFlag.superCalls; + } +} + +mixin NonFinalLate on AbstractLateFieldEncoding { + @override + Statement _createSetterBody( + CoreTypes coreTypes, String name, VariableDeclaration parameter) { + assert(_type != null, "Type has not been computed for field $name."); + return late_lowering.createSetterBody( + coreTypes, _fragment.nameOffset, 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, "Type has not been computed for field $name."); + return late_lowering.createGetterBodyWithoutInitializer( + coreTypes, _fragment.nameOffset, 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(super._fragment, + {required super.isSetStrategy}); +} + +class LateFieldWithInitializerEncoding extends AbstractLateFieldEncoding + with NonFinalLate { + LateFieldWithInitializerEncoding(super._fragment, + {required super.isSetStrategy}); + + @override + Statement _createGetterBody( + CoreTypes coreTypes, String name, Expression? initializer) { + assert(_type != null, "Type has not been computed for field $name."); + return late_lowering.createGetterWithInitializer( + coreTypes, _fragment.nameOffset, 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(super._fragment, + {required super.isSetStrategy}); + + @override + Statement _createSetterBody( + CoreTypes coreTypes, String name, VariableDeclaration parameter) { + assert(_type != null, "Type has not been computed for field $name."); + return late_lowering.createSetterBodyFinal( + coreTypes, _fragment.nameOffset, 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(super._fragment, + {required super.isSetStrategy}); + + @override + Statement _createGetterBody( + CoreTypes coreTypes, String name, Expression? initializer) { + assert(_type != null, "Type has not been computed for field $name."); + return late_lowering.createGetterWithInitializerWithRecheck( + coreTypes, _fragment.nameOffset, 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 AbstractOrExternalFieldEncoding implements _FieldEncoding { + final FieldFragment _fragment; + final bool isAbstract; + final bool isExternal; + final bool _isExtensionInstanceMember; + final bool _isExtensionTypeInstanceMember; + + Procedure? _getter; + Procedure? _setter; + DartType? _type; + + AbstractOrExternalFieldEncoding(this._fragment, + {required bool isExtensionInstanceMember, + required bool isExtensionTypeInstanceMember, + required this.isAbstract, + required this.isExternal, + bool isForcedExtension = false}) + : _isExtensionInstanceMember = + (isExternal || isForcedExtension) && isExtensionInstanceMember, + _isExtensionTypeInstanceMember = + (isExternal || isForcedExtension) && isExtensionTypeInstanceMember; + + @override + DartType get type { + assert(_type != null, + "Type has not been computed for field ${_fragment.name}."); + return _type!; + } + + /// Updates the getter/setter types of [_getter] and [_setter] to match the + /// value of [_type]. + /// + /// This allows for creating the members and computing the type in arbitrary + /// order. + void _updateMemberTypes() { + Procedure? getter = _getter; + Procedure? setter = _setter; + DartType? type = _type; + if (type != null && type is! InferredType && getter != null) { + if (_isExtensionInstanceMember || _isExtensionTypeInstanceMember) { + DartType thisParameterType; + List typeParameters; + if (_isExtensionInstanceMember) { + SourceExtensionBuilder extensionBuilder = + _fragment.builder.parent as SourceExtensionBuilder; + thisParameterType = extensionBuilder.extension.onType; + typeParameters = extensionBuilder.extension.typeParameters; + } else { + SourceExtensionTypeDeclarationBuilder + extensionTypeDeclarationBuilder = + _fragment.builder.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(type); + getter.function.typeParameters = + getterTypeParameters.freshTypeParameters; + setParents(getterTypeParameters.freshTypeParameters, getter.function); + + if (setter != null) { + FreshTypeParameters setterTypeParameters = + getFreshTypeParameters(typeParameters); + setter.function.positionalParameters.first.type = + setterTypeParameters.substitute(thisParameterType); + setter.function.positionalParameters[1].type = + setterTypeParameters.substitute(type); + setter.function.typeParameters = + setterTypeParameters.freshTypeParameters; + setParents( + setterTypeParameters.freshTypeParameters, setter.function); + } + } else { + getter.function.returnType = type; + setter?.function.positionalParameters[1].type = type; + getter.function.positionalParameters.first.type = thisParameterType; + setter?.function.positionalParameters.first.type = thisParameterType; + } + } else { + getter.function.returnType = type; + if (setter != null) { + if (setter.kind == ProcedureKind.Method) { + // Coverage-ignore-block(suite): Not run. + setter.function.positionalParameters[1].type = type; + } else { + setter.function.positionalParameters.first.type = type; + } + } + } + } + } + + @override + void set type(DartType value) { + assert(_type == null || _type is InferredType, + "Type has already been computed for field ${_fragment.name}."); + _type = value; + _updateMemberTypes(); + } + + @override + void createBodies(CoreTypes coreTypes, Expression? initializer) { + // TODO(johnniwinther): Enable this assert. + //assert(initializer != null); + } + + @override + List createInitializer(int fileOffset, Expression value, + {required bool isSynthetic}) { + throw new UnsupportedError('ExternalFieldEncoding.createInitializer'); + } + + @override + void buildOutlineNode(SourceLibraryBuilder libraryBuilder, + NameScheme nameScheme, FieldReference references, + {required bool isAbstractOrExternal, + required List? classTypeParameters}) { + if (_isExtensionInstanceMember || _isExtensionTypeInstanceMember) { + _getter = new Procedure( + dummyName, + ProcedureKind.Method, + new FunctionNode(null, positionalParameters: [ + new VariableDeclaration(syntheticThisName) + ..fileOffset = _fragment.nameOffset + ..isLowered = true + ]), + fileUri: _fragment.fileUri, + reference: references.fieldGetterReference) + ..fileOffset = _fragment.nameOffset + ..fileEndOffset = _fragment.endOffset; + nameScheme + .getProcedureMemberName(ProcedureKind.Getter, _fragment.name) + .attachMember(_getter!); + if (!_fragment.modifiers.isFinal) { + VariableDeclaration parameter = + new VariableDeclaration("#externalFieldValue", isSynthesized: true) + ..isCovariantByDeclaration = _fragment.modifiers.isCovariant + ..fileOffset = _fragment.nameOffset; + _setter = new Procedure( + dummyName, + ProcedureKind.Method, + new FunctionNode(null, + positionalParameters: [ + new VariableDeclaration(syntheticThisName) + ..fileOffset = _fragment.nameOffset + ..isLowered = true, + parameter + ], + returnType: const VoidType()) + ..fileOffset = _fragment.nameOffset + ..fileEndOffset = _fragment.endOffset, + fileUri: _fragment.fileUri, + reference: references.fieldSetterReference) + ..fileOffset = _fragment.nameOffset + ..fileEndOffset = _fragment.endOffset; + nameScheme + .getProcedureMemberName(ProcedureKind.Setter, _fragment.name) + .attachMember(_setter!); + } + } else { + _getter = new Procedure( + dummyName, ProcedureKind.Getter, new FunctionNode(null), + fileUri: _fragment.fileUri, + reference: references.fieldGetterReference) + ..fileOffset = _fragment.nameOffset + ..fileEndOffset = _fragment.endOffset; + nameScheme + .getFieldMemberName(FieldNameType.Getter, _fragment.name, + isSynthesized: true) + .attachMember(_getter!); + if (!_fragment.modifiers.isFinal) { + VariableDeclaration parameter = + new VariableDeclaration("#externalFieldValue", isSynthesized: true) + ..isCovariantByDeclaration = _fragment.modifiers.isCovariant + ..fileOffset = _fragment.nameOffset; + _setter = new Procedure( + dummyName, + ProcedureKind.Setter, + new FunctionNode(null, + positionalParameters: [parameter], returnType: const VoidType()) + ..fileOffset = _fragment.nameOffset + ..fileEndOffset = _fragment.endOffset, + fileUri: _fragment.fileUri, + reference: references.fieldSetterReference) + ..fileOffset = _fragment.nameOffset + ..fileEndOffset = _fragment.endOffset; + nameScheme + .getFieldMemberName(FieldNameType.Setter, _fragment.name, + isSynthesized: true) + .attachMember(_setter!); + } + } + + bool isExtensionMember = _fragment.builder.isExtensionMember; + bool isExtensionTypeMember = _fragment.builder.isExtensionTypeMember; + bool isInstanceMember = !isExtensionMember && + !isExtensionTypeMember && + !_fragment.builder.isStatic && + !_fragment.builder.isTopLevel; + _getter! + ..isConst = _fragment.modifiers.isConst + ..isStatic = !isInstanceMember + ..isExtensionMember = isExtensionMember + ..isExtensionTypeMember = isExtensionTypeMember + ..isAbstract = isAbstract && !isExternal + ..isExternal = isExternal; + + _setter + ?..isStatic = !isInstanceMember + ..isExtensionMember = isExtensionMember + ..isExtensionTypeMember = isExtensionTypeMember + ..isAbstract = isAbstract && !isExternal + ..isExternal = isExternal; + + _updateMemberTypes(); + } + + @override + void registerMembers(BuildNodesCallback f) { + BuiltMemberKind getterMemberKind; + if (_fragment.builder.isExtensionMember) { + getterMemberKind = BuiltMemberKind.ExtensionGetter; + } else if (_fragment.builder.isExtensionTypeMember) { + getterMemberKind = BuiltMemberKind.ExtensionTypeGetter; + } else { + getterMemberKind = BuiltMemberKind.Method; + } + f(member: _getter!, kind: getterMemberKind); + if (_setter != null) { + BuiltMemberKind setterMemberKind; + if (_fragment.builder.isExtensionMember) { + setterMemberKind = BuiltMemberKind.ExtensionSetter; + } else if (_fragment.builder.isExtensionTypeMember) { + setterMemberKind = BuiltMemberKind.ExtensionTypeSetter; + } else { + setterMemberKind = BuiltMemberKind.Method; + } + f(member: _setter!, kind: setterMemberKind); + } + } + + @override + // Coverage-ignore(suite): Not run. + void setCovariantByClass() { + _setter!.function.positionalParameters.first.isCovariantByClass = true; + } + + @override + Field get field { + throw new UnsupportedError("ExternalFieldEncoding.field"); + } + + @override + // Coverage-ignore(suite): Not run. + Member get builtMember => _getter!; + + @override + // Coverage-ignore(suite): Not run. + Iterable get annotatables { + List list = [_getter!]; + if (_setter != null) { + list.add(_setter!); + } + return list; + } + + @override + Member get readTarget => _getter!; + + @override + // Coverage-ignore(suite): Not run. + Reference get readTargetReference => _getter!.reference; + + @override + Member? get writeTarget => _setter; + + @override + // Coverage-ignore(suite): Not run. + Reference? get writeTargetReference => _setter?.reference; + + @override + // Coverage-ignore(suite): Not run. + Iterable get exportedReferenceMembers { + if (_setter != null) { + return [_getter!.reference, _setter!.reference]; + } + return [_getter!.reference]; + } + + @override + List get localMembers => [ + new _SynthesizedFieldClassMember( + _fragment.builder, + _getter!, + _fragment.builder.memberName, + _SynthesizedFieldMemberKind.AbstractExternalGetterSetter, + ClassMemberKind.Getter) + ]; + + @override + List get localSetters => _setter != null + ? [ + new _SynthesizedFieldClassMember( + _fragment.builder, + _setter!, + _fragment.builder.memberName, + _SynthesizedFieldMemberKind.AbstractExternalGetterSetter, + ClassMemberKind.Setter) + ] + : const []; + + @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}) { + return new ShadowInvalidFieldInitializer(type, value, effect) + ..fileOffset = fileOffset; + } + + @override + void registerSuperCall() { + throw new UnsupportedError( + "Unexpected call to ${runtimeType}.registerSuperCall()."); + } +} + +/// The encoding of an extension type declaration representation field. +class RepresentationFieldEncoding implements _FieldEncoding { + final FieldFragment _fragment; + + late Procedure _getter; + DartType? _type; + + RepresentationFieldEncoding(this._fragment); + @override + DartType get type { + assert(_type != null, + "Type has not been computed for field ${_fragment.name}."); + return _type!; + } + + @override + void set type(DartType value) { + assert( + _type == null || + // Coverage-ignore(suite): Not run. + _type is InferredType, + "Type has already been computed for field ${_fragment.name}."); + _type = value; + if (value is! InferredType) { + _getter.function.returnType = value; + } + } + + @override + // Coverage-ignore(suite): Not run. + void createBodies(CoreTypes coreTypes, Expression? initializer) { + // TODO(johnniwinther): Enable this assert. + //assert(initializer != null); + } + + @override + List createInitializer(int fileOffset, Expression value, + {required bool isSynthetic}) { + return [ + new ExtensionTypeRepresentationFieldInitializer(_getter, value) + ]; + } + + @override + void buildOutlineNode(SourceLibraryBuilder libraryBuilder, + NameScheme nameScheme, FieldReference references, + {required bool isAbstractOrExternal, + required List? classTypeParameters}) { + _getter = new Procedure( + dummyName, ProcedureKind.Getter, new FunctionNode(null), + fileUri: _fragment.fileUri, reference: references.fieldGetterReference) + ..stubKind = ProcedureStubKind.RepresentationField + ..fileOffset = _fragment.nameOffset + ..fileEndOffset = _fragment.endOffset; + nameScheme + .getFieldMemberName(FieldNameType.RepresentationField, _fragment.name, + isSynthesized: true) + .attachMember(_getter); + _getter..isConst = _fragment.modifiers.isConst; + _getter + ..isStatic = false + ..isExtensionMember = false + ..isExtensionTypeMember = true + ..isAbstract = true + ..isExternal = false; + } + + @override + void registerMembers(BuildNodesCallback f) { + f(member: _getter, kind: BuiltMemberKind.ExtensionTypeRepresentationField); + } + + @override + void setCovariantByClass() { + throw new UnsupportedError("$runtimeType.setGenericCovariantImpl"); + } + + @override + Field get field { + throw new UnsupportedError("$runtimeType.field"); + } + + @override + // Coverage-ignore(suite): Not run. + Member get builtMember => _getter; + + @override + // Coverage-ignore(suite): Not run. + Iterable get annotatables => [_getter]; + + @override + Member get readTarget => _getter; + + @override + // Coverage-ignore(suite): Not run. + Reference get readTargetReference => _getter.reference; + + @override + Member? get writeTarget => null; + + @override + // Coverage-ignore(suite): Not run. + Reference? get writeTargetReference => null; + + @override + // Coverage-ignore(suite): Not run. + Iterable get exportedReferenceMembers => [_getter.reference]; + + @override + List get localMembers => [ + new _SynthesizedFieldClassMember( + _fragment.builder, + _getter, + _fragment.builder.memberName, + _SynthesizedFieldMemberKind.RepresentationField, + ClassMemberKind.Getter) + ]; + + @override + List get localSetters => const []; + + @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; + } + + @override + void registerSuperCall() { + throw new UnsupportedError( + "Unexpected call to ${runtimeType}.registerSuperCall()."); + } +} diff --git a/pkg/front_end/lib/src/fragment/fragment.dart b/pkg/front_end/lib/src/fragment/fragment.dart index 4fd060f96cde..3b3a13130f5a 100644 --- a/pkg/front_end/lib/src/fragment/fragment.dart +++ b/pkg/front_end/lib/src/fragment/fragment.dart @@ -2,16 +2,22 @@ // 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/metadata/expressions.dart' as shared; import 'package:_fe_analyzer_shared/src/parser/member_kind.dart'; 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/transformations/flags.dart'; import 'package:kernel/type_algebra.dart'; import 'package:kernel/type_environment.dart'; +import '../api_prototype/codes.dart'; +import '../api_prototype/lowering_predicates.dart'; +import '../base/constant_context.dart'; import '../base/local_scope.dart'; import '../base/modifiers.dart'; +import '../base/problems.dart'; import '../base/scope.dart'; import '../builder/builder.dart'; import '../builder/constructor_reference_builder.dart'; @@ -19,27 +25,32 @@ import '../builder/declaration_builders.dart'; import '../builder/formal_parameter_builder.dart'; import '../builder/metadata_builder.dart'; import '../builder/mixin_application_builder.dart'; +import '../builder/named_type_builder.dart'; import '../builder/omitted_type_builder.dart'; import '../builder/type_builder.dart'; +import '../kernel/body_builder.dart'; 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/late_lowering.dart' as late_lowering; +import '../kernel/macro/metadata.dart' hide FieldReference; +import '../kernel/member_covariance.dart'; import '../kernel/type_algorithms.dart'; import '../source/name_scheme.dart'; -import '../source/source_property_builder.dart'; import '../source/source_class_builder.dart'; import '../source/source_constructor_builder.dart'; import '../source/source_enum_builder.dart'; import '../source/source_extension_builder.dart'; import '../source/source_extension_type_declaration_builder.dart'; import '../source/source_factory_builder.dart'; -import '../source/source_field_builder.dart'; import '../source/source_function_builder.dart'; import '../source/source_library_builder.dart'; import '../source/source_loader.dart'; import '../source/source_member_builder.dart'; import '../source/source_method_builder.dart'; +import '../source/source_property_builder.dart'; import '../source/source_type_alias_builder.dart'; import '../source/type_parameter_scope_builder.dart'; import '../type_inference/type_inference_engine.dart'; @@ -52,6 +63,9 @@ part 'extension.dart'; part 'extension_type.dart'; part 'factory.dart'; part 'field.dart'; +part 'field/body_builder_context.dart'; +part 'field/class_member.dart'; +part 'field/encoding.dart'; part 'function.dart'; part 'getter.dart'; part 'method.dart'; diff --git a/pkg/front_end/lib/src/fragment/getter.dart b/pkg/front_end/lib/src/fragment/getter.dart index 5097931c75ff..96e7659c494b 100644 --- a/pkg/front_end/lib/src/fragment/getter.dart +++ b/pkg/front_end/lib/src/fragment/getter.dart @@ -133,11 +133,9 @@ class GetterFragment implements Fragment, FunctionFragment { } void buildOutlineNode(SourceLibraryBuilder libraryBuilder, - NameScheme nameScheme, BuildNodesCallback f, - {required Reference getterReference, - required List? classTypeParameters}) { - _encoding.buildOutlineNode(libraryBuilder, nameScheme, f, - getterReference: getterReference, + NameScheme nameScheme, BuildNodesCallback f, GetterReference references, + {required List? classTypeParameters}) { + _encoding.buildOutlineNode(libraryBuilder, nameScheme, f, references, isAbstractOrExternal: modifiers.isAbstract || modifiers.isExternal, classTypeParameters: classTypeParameters); } @@ -161,6 +159,9 @@ class GetterFragment implements Fragment, FunctionFragment { createFileUriExpression: createFileUriExpression); } + Iterable getExportedMemberReferences(GetterReference references) => + [references.getterReference]; + BodyBuilderContext createBodyBuilderContext() { return new _GetterFragmentBodyBuilderContext( this, builder.libraryBuilder, builder.declarationBuilder, @@ -175,20 +176,20 @@ class GetterFragment implements Fragment, FunctionFragment { return _encoding.computeDefaultTypes(context); } - void ensureTypes( - ClassMembersBuilder membersBuilder, - SourceClassBuilder enclosingClassBuilder, + void ensureTypes(ClassMembersBuilder membersBuilder, Set? getterOverrideDependencies) { if (getterOverrideDependencies != null) { membersBuilder.inferGetterType( - enclosingClassBuilder, returnType, getterOverrideDependencies, + builder.declarationBuilder as SourceClassBuilder, + returnType, + getterOverrideDependencies, name: name, fileUri: fileUri, nameOffset: nameOffset, nameLength: name.length); } _encoding.ensureTypes( - enclosingClassBuilder.libraryBuilder, membersBuilder.hierarchyBuilder); + builder.libraryBuilder, membersBuilder.hierarchyBuilder); } void checkTypes(SourceLibraryBuilder libraryBuilder, @@ -269,9 +270,8 @@ sealed class _GetterEncoding implements InferredTypeListener { Procedure get readTarget; void buildOutlineNode(SourceLibraryBuilder libraryBuilder, - NameScheme nameScheme, BuildNodesCallback f, - {required Reference getterReference, - required bool isAbstractOrExternal, + NameScheme nameScheme, BuildNodesCallback f, GetterReference references, + {required bool isAbstractOrExternal, required List? classTypeParameters}); void buildOutlineExpressions( @@ -328,9 +328,8 @@ mixin _DirectGetterEncodingMixin implements _GetterEncoding { @override void buildOutlineNode(SourceLibraryBuilder libraryBuilder, - NameScheme nameScheme, BuildNodesCallback f, - {required Reference getterReference, - required bool isAbstractOrExternal, + NameScheme nameScheme, BuildNodesCallback f, GetterReference references, + {required bool isAbstractOrExternal, List? classTypeParameters}) { FunctionNode function = new FunctionNode( isAbstractOrExternal ? null : new EmptyStatement(), @@ -349,7 +348,7 @@ mixin _DirectGetterEncodingMixin implements _GetterEncoding { nameScheme.getProcedureMemberName(ProcedureKind.Getter, _fragment.name); Procedure procedure = _procedure = new Procedure( memberName.name, ProcedureKind.Getter, function, - reference: getterReference, fileUri: _fragment.fileUri) + reference: references.getterReference, fileUri: _fragment.fileUri) ..fileStartOffset = _fragment.startOffset ..fileOffset = _fragment.nameOffset ..fileEndOffset = _fragment.endOffset @@ -556,9 +555,8 @@ mixin _ExtensionInstanceGetterEncodingMixin implements _GetterEncoding { @override void buildOutlineNode(SourceLibraryBuilder libraryBuilder, - NameScheme nameScheme, BuildNodesCallback f, - {required Reference getterReference, - required bool isAbstractOrExternal, + NameScheme nameScheme, BuildNodesCallback f, GetterReference references, + {required bool isAbstractOrExternal, required List? classTypeParameters}) { List? typeParameters; if (_clonedDeclarationTypeParameters != null) { @@ -589,7 +587,7 @@ mixin _ExtensionInstanceGetterEncodingMixin implements _GetterEncoding { nameScheme.getProcedureMemberName(ProcedureKind.Getter, _fragment.name); Procedure procedure = _procedure = new Procedure( memberName.name, ProcedureKind.Method, function, - reference: getterReference, fileUri: _fragment.fileUri) + reference: references.getterReference, fileUri: _fragment.fileUri) ..fileStartOffset = _fragment.startOffset ..fileOffset = _fragment.nameOffset ..fileEndOffset = _fragment.endOffset diff --git a/pkg/front_end/lib/src/fragment/setter.dart b/pkg/front_end/lib/src/fragment/setter.dart index 952b59e0df1c..d28c135c5a7e 100644 --- a/pkg/front_end/lib/src/fragment/setter.dart +++ b/pkg/front_end/lib/src/fragment/setter.dart @@ -125,11 +125,9 @@ class SetterFragment implements Fragment, FunctionFragment { } void buildOutlineNode(SourceLibraryBuilder libraryBuilder, - NameScheme nameScheme, BuildNodesCallback f, - {required Reference setterReference, - required List? classTypeParameters}) { - _encoding.buildOutlineNode(libraryBuilder, nameScheme, f, - setterReference: setterReference, + NameScheme nameScheme, BuildNodesCallback f, SetterReference references, + {required List? classTypeParameters}) { + _encoding.buildOutlineNode(libraryBuilder, nameScheme, f, references, isAbstractOrExternal: modifiers.isAbstract || modifiers.isExternal, classTypeParameters: classTypeParameters); } @@ -153,20 +151,23 @@ class SetterFragment implements Fragment, FunctionFragment { createFileUriExpression: createFileUriExpression); } - void ensureTypes( - ClassMembersBuilder membersBuilder, - SourceClassBuilder enclosingClassBuilder, + Iterable getExportedMemberReferences(SetterReference references) => + [references.setterReference]; + + void ensureTypes(ClassMembersBuilder membersBuilder, Set? setterOverrideDependencies) { if (setterOverrideDependencies != null) { membersBuilder.inferSetterType( - enclosingClassBuilder, declaredFormals, setterOverrideDependencies, + builder.declarationBuilder as SourceClassBuilder, + declaredFormals, + setterOverrideDependencies, name: name, fileUri: fileUri, nameOffset: nameOffset, nameLength: name.length); } _encoding.ensureTypes( - enclosingClassBuilder.libraryBuilder, membersBuilder.hierarchyBuilder); + builder.libraryBuilder, membersBuilder.hierarchyBuilder); } void checkTypes( @@ -266,9 +267,8 @@ sealed class _SetterEncoding { Procedure get writeTarget; void buildOutlineNode(SourceLibraryBuilder libraryBuilder, - NameScheme nameScheme, BuildNodesCallback f, - {required Reference setterReference, - required bool isAbstractOrExternal, + NameScheme nameScheme, BuildNodesCallback f, SetterReference references, + {required bool isAbstractOrExternal, required List? classTypeParameters}); void buildOutlineExpressions( @@ -353,9 +353,8 @@ mixin _DirectSetterEncodingMixin implements _SetterEncoding { @override void buildOutlineNode(SourceLibraryBuilder libraryBuilder, - NameScheme nameScheme, BuildNodesCallback f, - {required Reference setterReference, - required bool isAbstractOrExternal, + NameScheme nameScheme, BuildNodesCallback f, SetterReference references, + {required bool isAbstractOrExternal, List? classTypeParameters}) { FunctionNode function = new FunctionNode( isAbstractOrExternal ? null : new EmptyStatement(), @@ -385,7 +384,7 @@ mixin _DirectSetterEncodingMixin implements _SetterEncoding { nameScheme.getProcedureMemberName(ProcedureKind.Setter, _fragment.name); Procedure procedure = _procedure = new Procedure( memberName.name, ProcedureKind.Setter, function, - reference: setterReference, fileUri: _fragment.fileUri) + reference: references.setterReference, fileUri: _fragment.fileUri) ..fileStartOffset = _fragment.startOffset ..fileOffset = _fragment.nameOffset ..fileEndOffset = _fragment.endOffset @@ -580,9 +579,8 @@ mixin _ExtensionInstanceSetterEncodingMixin implements _SetterEncoding { @override void buildOutlineNode(SourceLibraryBuilder libraryBuilder, - NameScheme nameScheme, BuildNodesCallback f, - {required Reference setterReference, - required bool isAbstractOrExternal, + NameScheme nameScheme, BuildNodesCallback f, SetterReference references, + {required bool isAbstractOrExternal, required List? classTypeParameters}) { List? typeParameters; if (_clonedDeclarationTypeParameters != null) { @@ -630,7 +628,7 @@ mixin _ExtensionInstanceSetterEncodingMixin implements _SetterEncoding { nameScheme.getProcedureMemberName(ProcedureKind.Setter, _fragment.name); Procedure procedure = _procedure = new Procedure( memberName.name, ProcedureKind.Method, function, - reference: setterReference, fileUri: _fragment.fileUri) + reference: references.setterReference, fileUri: _fragment.fileUri) ..fileStartOffset = _fragment.startOffset ..fileOffset = _fragment.nameOffset ..fileEndOffset = _fragment.endOffset diff --git a/pkg/front_end/lib/src/kernel/body_builder.dart b/pkg/front_end/lib/src/kernel/body_builder.dart index 920295e11caf..8dd76774754b 100644 --- a/pkg/front_end/lib/src/kernel/body_builder.dart +++ b/pkg/front_end/lib/src/kernel/body_builder.dart @@ -73,6 +73,7 @@ import '../builder/named_type_builder.dart'; import '../builder/nullability_builder.dart'; import '../builder/omitted_type_builder.dart'; import '../builder/prefix_builder.dart'; +import '../builder/property_builder.dart'; import '../builder/record_type_builder.dart'; import '../builder/type_builder.dart'; import '../builder/variable_builder.dart'; @@ -91,9 +92,9 @@ import '../codes/cfe_codes.dart' templateLocalVariableUsedBeforeDeclaredContext; import '../codes/cfe_codes.dart' as cfe; import '../dill/dill_library_builder.dart' show DillLibraryBuilder; +import '../fragment/fragment.dart'; import '../source/diet_parser.dart'; import '../source/offset_map.dart'; -import '../source/source_field_builder.dart'; import '../source/source_library_builder.dart'; import '../source/source_member_builder.dart'; import '../source/stack_listener_impl.dart' @@ -977,16 +978,16 @@ class BodyBuilder extends StackListenerImpl ])); Expression? initializer = pop() as Expression?; Identifier identifier = pop() as Identifier; - SourceFieldBuilder fieldBuilder = offsetMap.lookupField(identifier); + FieldFragment fieldFragment = offsetMap.lookupField(identifier); if (initializer != null) { - if (!fieldBuilder.hasBodyBeenBuilt) { + if (!fieldFragment.hasBodyBeenBuilt) { initializer = typeInferrer - .inferFieldInitializer(this, fieldBuilder.builtType, initializer) + .inferFieldInitializer(this, fieldFragment.fieldType, initializer) .expression; - fieldBuilder.buildBody(coreTypes, initializer); + fieldFragment.buildBody(coreTypes, initializer); } - } else if (!fieldBuilder.hasBodyBeenBuilt) { - fieldBuilder.buildBody(coreTypes, null); + } else if (!fieldFragment.hasBodyBeenBuilt) { + fieldFragment.buildBody(coreTypes, null); } } assert(checkState( @@ -9070,7 +9071,7 @@ class BodyBuilder extends StackListenerImpl } Initializer buildDuplicatedInitializer( - SourceFieldBuilder fieldBuilder, + PropertyBuilder fieldBuilder, Expression value, String name, int offset, @@ -9105,7 +9106,9 @@ class BodyBuilder extends StackListenerImpl if (builder?.next != null) { // Duplicated name, already reported. while (builder != null) { - if (builder.next == null && builder is SourceFieldBuilder) { + if (builder.next == null && + builder is PropertyBuilder && + builder.isField) { // Assume the first field has been initialized. _context.registerInitializedField(builder); } @@ -9122,7 +9125,8 @@ class BodyBuilder extends StackListenerImpl ), fieldNameOffset) ]; - } else if (builder is SourceFieldBuilder && + } else if (builder is PropertyBuilder && + builder.isField && builder.isDeclarationInstanceMember) { if (builder.isExtensionTypeDeclaredInstanceField) { // Operating on an invalid field. Don't report anything though diff --git a/pkg/front_end/lib/src/kernel/body_builder_context.dart b/pkg/front_end/lib/src/kernel/body_builder_context.dart index 684fe4c6e35e..511db32dbada 100644 --- a/pkg/front_end/lib/src/kernel/body_builder_context.dart +++ b/pkg/front_end/lib/src/kernel/body_builder_context.dart @@ -15,6 +15,7 @@ import '../builder/declaration_builders.dart'; import '../builder/formal_parameter_builder.dart'; import '../builder/library_builder.dart'; import '../builder/named_type_builder.dart'; +import '../builder/property_builder.dart'; import '../builder/type_builder.dart'; import '../dill/dill_class_builder.dart'; import '../source/constructor_declaration.dart'; @@ -50,6 +51,10 @@ abstract class BodyBuilderContext { _declarationContext = new BodyBuilderDeclarationContext( libraryBuilder, declarationBuilder); + /// Returns `true` if the enclosing declaration declares a const constructor. + bool get declarationDeclaresConstConstructor => + _declarationContext.declaresConstConstructor; + /// Returns the file offset of the name of the member whose body is being /// built. /// @@ -282,7 +287,7 @@ abstract class BodyBuilderContext { /// Registers that the field [builder] has been initialized in generative /// constructor whose body is being built. - void registerInitializedField(SourceFieldBuilder builder) { + void registerInitializedField(PropertyBuilder builder) { throw new UnsupportedError('${runtimeType}.registerInitializedField'); } @@ -748,15 +753,19 @@ class FieldBodyBuilderContext extends BodyBuilderContext isDeclarationInstanceMember: _member.isDeclarationInstanceMember); @override + // Coverage-ignore(suite): Not run. bool get isLateField => _member.isLate; @override + // Coverage-ignore(suite): Not run. bool get isAbstractField => _member.isAbstract; @override + // Coverage-ignore(suite): Not run. bool get isExternalField => _member.isExternal; @override + // Coverage-ignore(suite): Not run. InstanceTypeParameterAccessState get instanceTypeParameterAccessState { if (_member.isExtensionMember && !_member.isExternal) { return InstanceTypeParameterAccessState.Invalid; @@ -766,6 +775,7 @@ class FieldBodyBuilderContext extends BodyBuilderContext } @override + // Coverage-ignore(suite): Not run. ConstantContext get constantContext { return _member.isConst ? ConstantContext.inferred @@ -852,7 +862,7 @@ mixin _ConstructorBodyBuilderContextMixin } @override - void registerInitializedField(SourceFieldBuilder builder) { + void registerInitializedField(PropertyBuilder builder) { _member.registerInitializedField(builder); } diff --git a/pkg/front_end/lib/src/kernel/expression_generator.dart b/pkg/front_end/lib/src/kernel/expression_generator.dart index 48cb7cf5a75b..4e77f1b62d8b 100644 --- a/pkg/front_end/lib/src/kernel/expression_generator.dart +++ b/pkg/front_end/lib/src/kernel/expression_generator.dart @@ -1979,6 +1979,10 @@ class ExplicitExtensionInstanceAccessGenerator extends Generator { } else if (getterBuilder.isField) { assert(!getterBuilder.isStatic); MemberBuilder memberBuilder = getterBuilder as MemberBuilder; + assert( + memberBuilder.invokeTarget is Procedure?, + "Unexpected invoke target ${memberBuilder.invokeTarget} " + "(${memberBuilder.invokeTarget.runtimeType}) on ${memberBuilder}."); readTarget = memberBuilder.invokeTarget as Procedure?; } else { return unhandled( diff --git a/pkg/front_end/lib/src/kernel/hierarchy/class_member.dart b/pkg/front_end/lib/src/kernel/hierarchy/class_member.dart index 2c280dd66d11..b2849dcd2de5 100644 --- a/pkg/front_end/lib/src/kernel/hierarchy/class_member.dart +++ b/pkg/front_end/lib/src/kernel/hierarchy/class_member.dart @@ -170,6 +170,8 @@ class ExtensionTypeMemberResult implements MemberResult { @override DartType getMemberType( ClassMembersBuilder membersBuilder, TypeDeclarationType thisType) { + assert(member.getterType is FunctionType, + "Unexpected member type for $member (${member.runtimeType})."); FunctionType type = member.getterType as FunctionType; if (type.typeParameters.isNotEmpty) { // Coverage-ignore-block(suite): Not run. diff --git a/pkg/front_end/lib/src/kernel/implicit_field_type.dart b/pkg/front_end/lib/src/kernel/implicit_field_type.dart index 8cb46661decd..5a9646c9e787 100644 --- a/pkg/front_end/lib/src/kernel/implicit_field_type.dart +++ b/pkg/front_end/lib/src/kernel/implicit_field_type.dart @@ -11,10 +11,14 @@ import 'package:kernel/src/printer.dart'; import '../base/constant_context.dart'; import '../base/problems.dart' show unsupported; import '../builder/builder.dart'; +import '../builder/declaration_builders.dart'; import '../builder/inferable_type_builder.dart'; import '../codes/cfe_codes.dart'; +import '../fragment/fragment.dart'; +import '../source/source_class_builder.dart'; import '../source/source_enum_builder.dart'; import '../source/source_field_builder.dart'; +import '../source/source_library_builder.dart'; import '../type_inference/type_inferrer.dart'; import 'body_builder.dart'; import 'body_builder_context.dart'; @@ -29,6 +33,10 @@ abstract class InferredType extends AuxiliaryType { SourceFieldBuilder fieldBuilder, Token? initializerToken) = _ImplicitFieldTypeRoot; + factory InferredType.fromFieldFragmentInitializer( + FieldFragment fieldFragment, Token? initializerToken) = + _ImplicitFieldFragmentTypeRoot; + factory InferredType.fromInferableTypeUse(InferableTypeUse inferableTypeUse) = _InferredTypeUse; @@ -114,6 +122,7 @@ class _ImplicitFieldTypeRoot extends InferredType { @override DartType computeType(ClassHierarchyBase hierarchy) { if (isStarted) { + // Coverage-ignore-block(suite): Not run. fieldBuilder.libraryBuilder.addProblem( templateCantInferTypeDueToCircularity .withArguments(fieldBuilder.name), @@ -131,7 +140,9 @@ class _ImplicitFieldTypeRoot extends InferredType { parent.elementBuilders.contains(fieldBuilder)) { inferredType = parent.buildElement( fieldBuilder, parent.libraryBuilder.loader.coreTypes); - } else if (initializerToken != null) { + } + // Coverage-ignore(suite): Not run. + else if (initializerToken != null) { InterfaceType? enclosingClassThisType = fieldBuilder.classBuilder == null ? null : fieldBuilder.libraryBuilder.loader.typeInferenceEngine.coreTypes @@ -143,10 +154,7 @@ class _ImplicitFieldTypeRoot extends InferredType { fieldBuilder.fileUri, enclosingClassThisType, fieldBuilder.libraryBuilder, - fieldBuilder - .dataForTesting - // Coverage-ignore(suite): Not run. - ?.inferenceData); + fieldBuilder.dataForTesting?.inferenceData); BodyBuilderContext bodyBuilderContext = fieldBuilder.createBodyBuilderContext(); BodyBuilder bodyBuilder = fieldBuilder.libraryBuilder.loader @@ -195,6 +203,116 @@ class _ImplicitFieldTypeRoot extends InferredType { String toString() => 'ImplicitFieldType(${toStringInternal()})'; } +class _ImplicitFieldFragmentTypeRoot extends InferredType { + final FieldFragment _fieldFragment; + + Token? initializerToken; + bool isStarted = false; + + _ImplicitFieldFragmentTypeRoot(this._fieldFragment, this.initializerToken) + : super._(); + + @override + // Coverage-ignore(suite): Not run. + Uri get fileUri => _fieldFragment.fileUri; + + @override + // Coverage-ignore(suite): Not run. + int get charOffset => _fieldFragment.nameOffset; + + @override + DartType inferType(ClassHierarchyBase hierarchy) { + return _fieldFragment.inferType(hierarchy); + } + + @override + DartType computeType(ClassHierarchyBase hierarchy) { + if (isStarted) { + _fieldFragment.builder.libraryBuilder.addProblem( + templateCantInferTypeDueToCircularity + .withArguments(_fieldFragment.name), + _fieldFragment.nameOffset, + _fieldFragment.name.length, + _fieldFragment.fileUri); + DartType type = const InvalidType(); + _fieldFragment.type.registerInferredType(type); + return type; + } + isStarted = true; + DartType? inferredType; + SourceLibraryBuilder libraryBuilder = _fieldFragment.builder.libraryBuilder; + DeclarationBuilder? declarationBuilder = + _fieldFragment.builder.declarationBuilder; + if (declarationBuilder is SourceEnumBuilder && + declarationBuilder.elementBuilders.contains(_fieldFragment.builder)) { + // Coverage-ignore-block(suite): Not run. + inferredType = declarationBuilder.buildElement( + // TODO(johnniwinther): Create a EnumElementFragment to avoid this. + _fieldFragment.builder as SourceFieldBuilder, + libraryBuilder.loader.coreTypes); + } else if (initializerToken != null) { + InterfaceType? enclosingClassThisType = declarationBuilder + is SourceClassBuilder + ? libraryBuilder.loader.typeInferenceEngine.coreTypes + .thisInterfaceType( + declarationBuilder.cls, libraryBuilder.library.nonNullable) + : null; + TypeInferrer typeInferrer = + libraryBuilder.loader.typeInferenceEngine.createTopLevelTypeInferrer( + _fieldFragment.fileUri, + enclosingClassThisType, + libraryBuilder, + _fieldFragment + .builder + .dataForTesting + // Coverage-ignore(suite): Not run. + ?.inferenceData); + BodyBuilderContext bodyBuilderContext = + _fieldFragment.createBodyBuilderContext(); + BodyBuilder bodyBuilder = libraryBuilder.loader.createBodyBuilderForField( + libraryBuilder, + bodyBuilderContext, + declarationBuilder?.scope ?? libraryBuilder.scope, + typeInferrer, + _fieldFragment.fileUri); + bodyBuilder.constantContext = _fieldFragment.modifiers.isConst + ? ConstantContext.inferred + : ConstantContext.none; + bodyBuilder.inFieldInitializer = true; + bodyBuilder.inLateFieldInitializer = _fieldFragment.modifiers.isLate; + Expression initializer = + bodyBuilder.parseFieldInitializer(initializerToken!); + initializerToken = null; + + inferredType = + typeInferrer.inferImplicitFieldType(bodyBuilder, initializer); + } else { + inferredType = const DynamicType(); + } + return inferredType; + } + + @override + // Coverage-ignore(suite): Not run. + void toTextInternal(AstPrinter printer) { + printer.write(''); + } + + @override + // Coverage-ignore(suite): Not run. + bool equals(Object other, Assumptions? assumptions) { + if (identical(this, other)) return true; + return other is _ImplicitFieldFragmentTypeRoot && + _fieldFragment == other._fieldFragment; + } + + @override + int get hashCode => _fieldFragment.hashCode; + + @override + String toString() => 'ImplicitFieldType(${toStringInternal()})'; +} + class _InferredTypeUse extends InferredType { final InferableTypeUse inferableTypeUse; diff --git a/pkg/front_end/lib/src/kernel/kernel_target.dart b/pkg/front_end/lib/src/kernel/kernel_target.dart index 05953dc5f129..7386f7c5997f 100644 --- a/pkg/front_end/lib/src/kernel/kernel_target.dart +++ b/pkg/front_end/lib/src/kernel/kernel_target.dart @@ -47,13 +47,13 @@ import '../base/ticker.dart' show Ticker; import '../base/uri_translator.dart' show UriTranslator; import '../builder/builder.dart'; import '../builder/declaration_builders.dart'; -import '../builder/field_builder.dart'; import '../builder/library_builder.dart'; import '../builder/member_builder.dart'; import '../builder/name_iterator.dart'; import '../builder/named_type_builder.dart'; import '../builder/nullability_builder.dart'; import '../builder/procedure_builder.dart'; +import '../builder/property_builder.dart'; import '../builder/type_builder.dart'; import '../dill/dill_target.dart' show DillTarget; import '../source/class_declaration.dart'; @@ -62,13 +62,13 @@ import '../source/name_scheme.dart'; import '../source/source_class_builder.dart' show SourceClassBuilder; import '../source/source_constructor_builder.dart'; import '../source/source_extension_type_declaration_builder.dart'; -import '../source/source_field_builder.dart'; import '../source/source_library_builder.dart' show SourceLibraryBuilder; import '../source/source_loader.dart' show CompilationPhaseForProblemReporting, SourceLoader; import '../source/source_method_builder.dart'; import '../type_inference/type_schema.dart'; import 'benchmarker.dart' show BenchmarkPhases, Benchmarker; +import 'cfe_verifier.dart' show verifyComponent, verifyGetStaticType; import 'constant_evaluator.dart' as constants show EvaluationMode, @@ -81,7 +81,6 @@ import 'dynamic_module_validator.dart' as dynamic_module_validator; import 'kernel_constants.dart' show KernelConstantErrorReporter; import 'kernel_helper.dart'; import 'macro/macro.dart'; -import 'cfe_verifier.dart' show verifyComponent, verifyGetStaticType; class KernelTarget { final Ticker ticker; @@ -1533,14 +1532,17 @@ class KernelTarget { /// Quotes below are from [Dart Programming Language Specification, 4th /// Edition](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf): - List uninitializedFields = []; - List nonFinalFields = []; - List lateFinalFields = []; + List uninitializedFields = []; + List nonFinalFields = []; + List lateFinalFields = []; - Iterator fieldIterator = - classDeclaration.fullMemberIterator(); + Iterator fieldIterator = + classDeclaration.fullMemberIterator(); while (fieldIterator.moveNext()) { - SourceFieldBuilder fieldBuilder = fieldIterator.current; + PropertyBuilder fieldBuilder = fieldIterator.current; + if (!fieldBuilder.isField) { + continue; + } if (fieldBuilder.isAbstract || fieldBuilder.isExternal) { // Skip abstract and external fields. These are abstract/external // getters/setters and have no initialization. @@ -1559,10 +1561,10 @@ class KernelTarget { } } - Map> + Map> constructorInitializedFields = new Map.identity(); - Set? initializedFieldBuilders = null; - Set? uninitializedInstanceFields; + Set? initializedFieldBuilders = null; + Set? uninitializedInstanceFields; Iterator constructorIterator = classDeclaration.fullConstructorIterator(); @@ -1579,14 +1581,14 @@ class KernelTarget { nonFinalFields.clear(); } if (constructor.isConst && lateFinalFields.isNotEmpty) { - for (FieldBuilder field in lateFinalFields) { + for (PropertyBuilder field in lateFinalFields) { classDeclaration.addProblem( messageConstConstructorLateFinalFieldError, field.fileOffset, noLength, context: [ messageConstConstructorLateFinalFieldCause.withLocation( - constructor.fileUri!, constructor.fileOffset, noLength) + constructor.fileUri, constructor.fileOffset, noLength) ]); } lateFinalFields.clear(); @@ -1595,23 +1597,23 @@ class KernelTarget { // Assume that an external constructor initializes all uninitialized // instance fields. uninitializedInstanceFields ??= uninitializedFields - .where((SourceFieldBuilder fieldBuilder) => !fieldBuilder.isStatic) + .where((PropertyBuilder fieldBuilder) => !fieldBuilder.isStatic) .toSet(); constructorInitializedFields[constructor] = uninitializedInstanceFields; - (initializedFieldBuilders ??= new Set.identity()) + (initializedFieldBuilders ??= new Set.identity()) .addAll(uninitializedInstanceFields); } else { - Set fields = + Set fields = constructor.takeInitializedFields() ?? const {}; constructorInitializedFields[constructor] = fields; - (initializedFieldBuilders ??= new Set.identity()) + (initializedFieldBuilders ??= new Set.identity()) .addAll(fields); } } // Run through all fields that aren't initialized by any constructor, and // set their initializer to `null`. - for (SourceFieldBuilder fieldBuilder in uninitializedFields) { + for (PropertyBuilder fieldBuilder in uninitializedFields) { if (fieldBuilder.isExtensionTypeDeclaredInstanceField) continue; if (initializedFieldBuilders == null || !initializedFieldBuilders.contains(fieldBuilder)) { @@ -1651,11 +1653,11 @@ class KernelTarget { // Run through all fields that are initialized by some constructor, and // make sure that all other constructors also initialize them. - for (MapEntry> entry + for (MapEntry> entry in constructorInitializedFields.entries) { ConstructorDeclaration constructorBuilder = entry.key; - Set fieldBuilders = entry.value; - for (SourceFieldBuilder fieldBuilder + Set fieldBuilders = entry.value; + for (PropertyBuilder fieldBuilder in initializedFieldBuilders!.difference(fieldBuilders)) { if (fieldBuilder.isExtensionTypeDeclaredInstanceField) continue; if (!fieldBuilder.hasInitializer && !fieldBuilder.isLate) { @@ -1674,12 +1676,12 @@ class KernelTarget { .withLocation(fieldBuilder.fileUri, fieldBuilder.fileOffset, fieldBuilder.name.length) ]); - } else if (fieldBuilder.field.type is! InvalidType && + } else if (fieldBuilder.fieldType is! InvalidType && !fieldBuilder.isLate && - fieldBuilder.field.type.isPotentiallyNonNullable) { + fieldBuilder.fieldType.isPotentiallyNonNullable) { libraryBuilder.addProblem( templateFieldNonNullableNotInitializedByConstructorError - .withArguments(fieldBuilder.name, fieldBuilder.field.type), + .withArguments(fieldBuilder.name, fieldBuilder.fieldType), constructorBuilder.fileOffset, noLength, constructorBuilder.fileUri, diff --git a/pkg/front_end/lib/src/kernel/macro/introspectors.dart b/pkg/front_end/lib/src/kernel/macro/introspectors.dart index 29679e1a2ee3..afc8a1892ce6 100644 --- a/pkg/front_end/lib/src/kernel/macro/introspectors.dart +++ b/pkg/front_end/lib/src/kernel/macro/introspectors.dart @@ -129,8 +129,12 @@ class MacroIntrospection { macro.Declaration _createMemberDeclaration(MemberBuilder memberBuilder) { if (memberBuilder is SourceMethodBuilder) { return _createMethodDeclaration(memberBuilder); - } else if (memberBuilder is SourcePropertyBuilder) { + } else if (memberBuilder is SourcePropertyBuilder && + (memberBuilder.isGetter || memberBuilder.isSetter)) { return _createGetterDeclaration(memberBuilder); + } else if (memberBuilder is SourcePropertyBuilder && + memberBuilder.isField) { + return _createFieldDeclaration(memberBuilder); } else if (memberBuilder is SourceFieldBuilder) { return _createVariableDeclaration(memberBuilder); } else if (memberBuilder is SourceConstructorBuilder) { @@ -445,10 +449,8 @@ class MacroIntrospection { // TODO(johnniwinther): Support typeParameters typeParameters: const [], ); - if (builder.fileUri != null) { - _declarationOffsets[declaration] = - new UriOffset(builder.fileUri!, builder.fileOffset); - } + _declarationOffsets[declaration] = + new UriOffset(builder.fileUri, builder.fileOffset); return declaration; } @@ -640,6 +642,64 @@ class MacroIntrospection { return declaration; } + /// Creates the [macro.VariableDeclaration] corresponding to [builder]. + macro.VariableDeclaration _createFieldDeclaration( + SourcePropertyBuilder builder) { + macro.ParameterizedTypeDeclaration? definingTypeDeclaration = null; + Builder? parent = builder.parent; + if (parent is ClassBuilder) { + definingTypeDeclaration = getClassDeclaration(parent); + } else if (parent is ExtensionTypeDeclarationBuilder) { + definingTypeDeclaration = getExtensionTypeDeclaration(parent); + } + final macro.LibraryImpl library = getLibrary(builder.libraryBuilder); + macro.VariableDeclaration declaration; + if (definingTypeDeclaration != null) { + // TODO(johnniwinther): Should static fields be field or variable + // declarations? + declaration = new macro.FieldDeclarationImpl( + id: macro.RemoteInstance.uniqueId, + identifier: new MemberBuilderIdentifier( + memberBuilder: builder, + id: macro.RemoteInstance.uniqueId, + name: builder.name), + library: library, + // TODO: Provide metadata annotations. + metadata: const [], + definingType: + definingTypeDeclaration.identifier as macro.IdentifierImpl, + hasAbstract: builder.isAbstract, + hasConst: builder.isConst, + hasExternal: builder.isExternal, + hasFinal: builder.isFinal, + hasInitializer: builder.hasInitializer, + hasLate: builder.isLate, + hasStatic: builder.isStatic, + type: types.getTypeAnnotation( + builder.libraryBuilder, builder.typeForTesting)); + } else { + declaration = new macro.VariableDeclarationImpl( + id: macro.RemoteInstance.uniqueId, + identifier: new MemberBuilderIdentifier( + memberBuilder: builder, + id: macro.RemoteInstance.uniqueId, + name: builder.name), + library: library, + // TODO: Provide metadata annotations. + metadata: const [], + hasConst: builder.isConst, + hasExternal: builder.isExternal, + hasFinal: builder.isFinal, + hasInitializer: builder.hasInitializer, + hasLate: builder.isLate, + type: types.getTypeAnnotation( + builder.libraryBuilder, builder.typeForTesting)); + } + _declarationOffsets[declaration] = + new UriOffset(builder.fileUri, builder.fileOffset); + return declaration; + } + /// Creates the [macro.VariableDeclaration] corresponding to [builder]. macro.VariableDeclaration _createVariableDeclaration( SourceFieldBuilder builder) { @@ -867,20 +927,26 @@ class _DeclarationPhaseIntrospector extends _TypePhaseIntrospector if (type is macro.ClassDeclaration || type is macro.MixinDeclaration) { ClassBuilder classBuilder = _introspection ._getClassBuilder(type as macro.ParameterizedTypeDeclaration); - Iterator iterator = - classBuilder.fullMemberIterator(); + Iterator iterator = + classBuilder.fullMemberIterator(); while (iterator.moveNext()) { - result.add(_introspection.getMemberDeclaration(iterator.current) - as macro.FieldDeclaration); + SourceMemberBuilder memberBuilder = iterator.current; + if (memberBuilder.isField) { + result.add(_introspection.getMemberDeclaration(memberBuilder) + as macro.FieldDeclaration); + } } } else if (type is macro.ExtensionTypeDeclaration) { ExtensionTypeDeclarationBuilder extensionTypeDeclarationBuilder = _introspection._getExtensionTypeDeclarationBuilder(type); - Iterator iterator = extensionTypeDeclarationBuilder - .fullMemberIterator(); + Iterator iterator = extensionTypeDeclarationBuilder + .fullMemberIterator(); while (iterator.moveNext()) { - result.add(_introspection.getMemberDeclaration(iterator.current) - as macro.FieldDeclaration); + SourceMemberBuilder memberBuilder = iterator.current; + if (memberBuilder.isField) { + result.add(_introspection.getMemberDeclaration(memberBuilder) + as macro.FieldDeclaration); + } } } else { throw new UnsupportedError('Only introspection on classes is supported'); @@ -899,7 +965,8 @@ class _DeclarationPhaseIntrospector extends _TypePhaseIntrospector while (iterator.moveNext()) { SourceMemberBuilder memberBuilder = iterator.current; if (memberBuilder is SourceMethodBuilder || - memberBuilder is SourcePropertyBuilder) { + (memberBuilder is SourcePropertyBuilder && + (memberBuilder.isGetter || memberBuilder.isSetter))) { result.add(_introspection.getMemberDeclaration(memberBuilder) as macro.MethodDeclaration); } @@ -912,7 +979,8 @@ class _DeclarationPhaseIntrospector extends _TypePhaseIntrospector while (iterator.moveNext()) { SourceMemberBuilder memberBuilder = iterator.current; if (memberBuilder is SourceMethodBuilder || - memberBuilder is SourcePropertyBuilder) { + (memberBuilder is SourcePropertyBuilder && + (memberBuilder.isGetter || memberBuilder.isSetter))) { result.add(_introspection.getMemberDeclaration(memberBuilder) as macro.MethodDeclaration); } diff --git a/pkg/front_end/lib/src/kernel/macro/metadata.dart b/pkg/front_end/lib/src/kernel/macro/metadata.dart index f270f6eb0f42..763aa31ba80f 100644 --- a/pkg/front_end/lib/src/kernel/macro/metadata.dart +++ b/pkg/front_end/lib/src/kernel/macro/metadata.dart @@ -24,8 +24,10 @@ import '../../builder/never_type_declaration_builder.dart'; import '../../builder/null_type_declaration_builder.dart'; import '../../builder/prefix_builder.dart'; import '../../builder/procedure_builder.dart'; +import '../../builder/property_builder.dart'; import '../../source/source_field_builder.dart'; import '../../source/source_method_builder.dart'; +import '../../source/source_property_builder.dart'; // Coverage-ignore(suite): Not run. final Uri dummyUri = Uri.parse('dummy:uri'); @@ -79,6 +81,11 @@ shared.Expression? getFieldInitializer(shared.FieldReference reference) { if (element is SourceFieldBuilder) { return element.initializerExpression; } + } else if (reference is PropertyReference) { + PropertyBuilder element = reference.builder; + if (element is SourcePropertyBuilder) { + return element.initializerExpression; + } } else { assert(false, "Unexpected field reference $reference (${reference.runtimeType})"); @@ -90,6 +97,8 @@ shared.Expression? getFieldInitializer(shared.FieldReference reference) { shared.Proto builderToProto(Builder builder, String name) { if (builder is FieldBuilder) { return new shared.FieldProto(new FieldReference(builder)); + } else if (builder is PropertyBuilder) { + return new shared.FieldProto(new PropertyReference(builder)); } else if (builder is ProcedureBuilder) { return new shared.FunctionProto(new FunctionReference(builder)); } else if (builder is SourceMethodBuilder) { @@ -352,6 +361,16 @@ class FieldReference extends shared.FieldReference { String get name => builder.name; } +// Coverage-ignore(suite): Not run. +class PropertyReference extends shared.FieldReference { + final PropertyBuilder builder; + + PropertyReference(this.builder); + + @override + String get name => builder.name; +} + // Coverage-ignore(suite): Not run. class FunctionReference extends shared.FunctionReference { final ProcedureBuilder builder; diff --git a/pkg/front_end/lib/src/source/constructor_declaration.dart b/pkg/front_end/lib/src/source/constructor_declaration.dart index ef5edc3c6124..17a90bcbf6a3 100644 --- a/pkg/front_end/lib/src/source/constructor_declaration.dart +++ b/pkg/front_end/lib/src/source/constructor_declaration.dart @@ -4,9 +4,9 @@ import 'package:kernel/ast.dart'; +import '../builder/property_builder.dart'; import '../kernel/expression_generator_helper.dart'; import '../type_inference/inference_results.dart'; -import 'source_field_builder.dart'; import 'source_function_builder.dart'; /// Common interface for builders for generative constructor declarations in @@ -41,14 +41,14 @@ abstract class ConstructorDeclaration implements SourceFunctionBuilder { /// /// The field can be initialized either via an initializing formal or via an /// entry in the constructor initializer list. - void registerInitializedField(SourceFieldBuilder fieldBuilder); + void registerInitializedField(PropertyBuilder 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? takeInitializedFields(); + Set? takeInitializedFields(); /// Substitute [fieldType] from the context of the enclosing class or /// extension type declaration to this constructor. diff --git a/pkg/front_end/lib/src/source/diet_listener.dart b/pkg/front_end/lib/src/source/diet_listener.dart index 4cb8778bf644..50731ffc2f42 100644 --- a/pkg/front_end/lib/src/source/diet_listener.dart +++ b/pkg/front_end/lib/src/source/diet_listener.dart @@ -45,7 +45,6 @@ import '../type_inference/type_inference_engine.dart' import '../type_inference/type_inferrer.dart' show TypeInferrer; import 'diet_parser.dart'; import 'offset_map.dart'; -import 'source_field_builder.dart'; import 'source_library_builder.dart' show SourceLibraryBuilder; import 'stack_listener_impl.dart'; @@ -932,13 +931,14 @@ class DietListener extends StackListenerImpl { if (names == null || currentClassIsParserRecovery) return; Identifier first = names.first!; - SourceFieldBuilder declaration = _offsetMap.lookupField(first); + FieldFragment fragment = _offsetMap.lookupField(first); // TODO(paulberry): don't re-parse the field if we've already parsed it // for type inference. _parseFields( _offsetMap, - createListener(declaration.createBodyBuilderContext(), memberScope, - inferenceDataForTesting: declaration + createListener(fragment.createBodyBuilderContext(), memberScope, + inferenceDataForTesting: fragment + .builder .dataForTesting // Coverage-ignore(suite): Not run. ?.inferenceData), diff --git a/pkg/front_end/lib/src/source/offset_map.dart b/pkg/front_end/lib/src/source/offset_map.dart index 8dd2b2718a73..5ff70979db8e 100644 --- a/pkg/front_end/lib/src/source/offset_map.dart +++ b/pkg/front_end/lib/src/source/offset_map.dart @@ -14,7 +14,6 @@ import '../builder/builder.dart'; import '../builder/declaration_builders.dart'; import '../codes/cfe_codes.dart'; import '../fragment/fragment.dart'; -import 'source_field_builder.dart'; /// Map from offsets of directives and declarations to the objects the define. /// @@ -99,9 +98,9 @@ class OffsetMap { _fields[identifier.nameOffset] = fragment; } - SourceFieldBuilder lookupField(Identifier identifier) { - return _checkBuilder(_fields[identifier.nameOffset]?.builder, - identifier.name, identifier.nameOffset); + FieldFragment lookupField(Identifier identifier) { + return _checkFragment( + _fields[identifier.nameOffset], identifier.name, identifier.nameOffset); } void registerPrimaryConstructor( diff --git a/pkg/front_end/lib/src/source/source_class_builder.dart b/pkg/front_end/lib/src/source/source_class_builder.dart index 54f06f6817b8..ddfb129b6a53 100644 --- a/pkg/front_end/lib/src/source/source_class_builder.dart +++ b/pkg/front_end/lib/src/source/source_class_builder.dart @@ -48,7 +48,6 @@ import 'name_scheme.dart'; import 'source_builder_mixins.dart'; import 'source_constructor_builder.dart'; import 'source_factory_builder.dart'; -import 'source_field_builder.dart'; import 'source_library_builder.dart'; import 'source_loader.dart'; import 'source_member_builder.dart'; @@ -1037,21 +1036,26 @@ class SourceClassBuilder extends ClassBuilderImpl return supertype; } - void checkVarianceInField(SourceFieldBuilder fieldBuilder, - TypeEnvironment typeEnvironment, List typeParameters) { - for (TypeParameter typeParameter in typeParameters) { - Variance fieldVariance = - computeVariance(typeParameter, fieldBuilder.fieldType); - if (fieldBuilder.isClassInstanceMember) { - reportVariancePositionIfInvalid(fieldVariance, typeParameter, - fieldBuilder.fileUri, fieldBuilder.fileOffset); - } - if (fieldBuilder.isClassInstanceMember && - fieldBuilder.isAssignable && - !fieldBuilder.isCovariantByDeclaration) { - fieldVariance = Variance.contravariant.combine(fieldVariance); - reportVariancePositionIfInvalid(fieldVariance, typeParameter, - fieldBuilder.fileUri, fieldBuilder.fileOffset); + void checkVarianceInField(TypeEnvironment typeEnvironment, + {required DartType fieldType, + required bool isInstanceMember, + required bool hasSetter, + required bool isCovariantByDeclaration, + required Uri fileUri, + required int fileOffset}) { + List typeParameters = cls.typeParameters; + if (typeParameters.isNotEmpty) { + for (TypeParameter typeParameter in typeParameters) { + Variance fieldVariance = computeVariance(typeParameter, fieldType); + if (isInstanceMember) { + reportVariancePositionIfInvalid( + fieldVariance, typeParameter, fileUri, fileOffset); + } + if (isInstanceMember && hasSetter && !isCovariantByDeclaration) { + fieldVariance = Variance.contravariant.combine(fieldVariance); + reportVariancePositionIfInvalid( + fieldVariance, typeParameter, fileUri, fileOffset); + } } } } diff --git a/pkg/front_end/lib/src/source/source_constructor_builder.dart b/pkg/front_end/lib/src/source/source_constructor_builder.dart index 78a0e8bd46d6..f8f08fc41977 100644 --- a/pkg/front_end/lib/src/source/source_constructor_builder.dart +++ b/pkg/front_end/lib/src/source/source_constructor_builder.dart @@ -30,6 +30,7 @@ import '../builder/formal_parameter_builder.dart'; import '../builder/member_builder.dart'; import '../builder/metadata_builder.dart'; import '../builder/omitted_type_builder.dart'; +import '../builder/property_builder.dart'; import '../builder/type_builder.dart'; import '../kernel/body_builder.dart' show BodyBuilder; import '../kernel/body_builder_context.dart'; @@ -51,7 +52,6 @@ import 'name_scheme.dart'; import 'source_class_builder.dart'; import 'source_enum_builder.dart'; import 'source_extension_type_declaration_builder.dart'; -import 'source_field_builder.dart'; import 'source_function_builder.dart'; import 'source_library_builder.dart' show SourceLibraryBuilder; import 'source_loader.dart' @@ -396,6 +396,14 @@ abstract class AbstractSourceConstructorBuilder @override // Coverage-ignore(suite): Not run. bool get isProperty => false; + + @override + // Coverage-ignore(suite): Not run. + bool get isFinal => false; + + @override + // Coverage-ignore(suite): Not run. + bool get isSynthesized => false; } class DeclaredSourceConstructorBuilder @@ -405,7 +413,7 @@ class DeclaredSourceConstructorBuilder @override late final Procedure? _constructorTearOff; - Set? _initializedFields; + Set? _initializedFields; DeclaredSourceConstructorBuilder? actualOrigin; @@ -1000,7 +1008,7 @@ class DeclaredSourceConstructorBuilder } @override - void registerInitializedField(SourceFieldBuilder fieldBuilder) { + void registerInitializedField(PropertyBuilder fieldBuilder) { if (isAugmenting) { origin.registerInitializedField(fieldBuilder); } else { @@ -1009,8 +1017,8 @@ class DeclaredSourceConstructorBuilder } @override - Set? takeInitializedFields() { - Set? result = _initializedFields; + Set? takeInitializedFields() { + Set? result = _initializedFields; _initializedFields = null; return result; } @@ -1125,6 +1133,14 @@ class SyntheticSourceConstructorBuilder extends MemberBuilderImpl @override bool get isConstructor => true; + @override + // Coverage-ignore(suite): Not run. + bool get isFinal => false; + + @override + // Coverage-ignore(suite): Not run. + bool get isSynthesized => true; + @override // Coverage-ignore(suite): Not run. bool get isAbstract => false; @@ -1302,7 +1318,7 @@ class SourceExtensionTypeConstructorBuilder @override late final Procedure? _constructorTearOff; - Set? _initializedFields; + Set? _initializedFields; @override List initializers = []; @@ -1542,13 +1558,13 @@ class SourceExtensionTypeConstructorBuilder } @override - void registerInitializedField(SourceFieldBuilder fieldBuilder) { + void registerInitializedField(PropertyBuilder fieldBuilder) { (_initializedFields ??= {}).add(fieldBuilder); } @override - Set? takeInitializedFields() { - Set? result = _initializedFields; + Set? takeInitializedFields() { + Set? result = _initializedFields; _initializedFields = null; return result; } diff --git a/pkg/front_end/lib/src/source/source_extension_type_declaration_builder.dart b/pkg/front_end/lib/src/source/source_extension_type_declaration_builder.dart index 020afb8172f8..3ce75847815b 100644 --- a/pkg/front_end/lib/src/source/source_extension_type_declaration_builder.dart +++ b/pkg/front_end/lib/src/source/source_extension_type_declaration_builder.dart @@ -35,9 +35,9 @@ import 'name_scheme.dart'; import 'source_builder_mixins.dart'; import 'source_constructor_builder.dart'; import 'source_factory_builder.dart'; -import 'source_field_builder.dart'; import 'source_library_builder.dart'; import 'source_member_builder.dart'; +import 'source_property_builder.dart'; import 'type_parameter_scope_builder.dart'; class SourceExtensionTypeDeclarationBuilder @@ -90,8 +90,6 @@ class SourceExtensionTypeDeclarationBuilder FieldFragment? _representationFieldFragment; - SourceFieldBuilder? _representationFieldBuilder; - final IndexedContainer? indexedContainer; Nullability? _nullability; @@ -155,13 +153,8 @@ class SourceExtensionTypeDeclarationBuilder @override bool get isAugment => _modifiers.isAugment; - SourceFieldBuilder? get representationFieldBuilder { - if (_representationFieldBuilder == null) { - _representationFieldBuilder = _representationFieldFragment?.builder; - _representationFieldFragment = null; - } - return _representationFieldBuilder; - } + SourcePropertyBuilder? get representationFieldBuilder => + _representationFieldFragment?.builder; @override void buildScopes(LibraryBuilder coreLibrary) { @@ -187,7 +180,7 @@ class SourceExtensionTypeDeclarationBuilder @override TypeBuilder? get declaredRepresentationTypeBuilder => - representationFieldBuilder?.type; + _representationFieldFragment?.type; @override SourceExtensionTypeDeclarationBuilder get origin => _origin ?? this; @@ -347,8 +340,8 @@ class SourceExtensionTypeDeclarationBuilder DartType representationType; String representationName; - if (representationFieldBuilder != null) { - TypeBuilder typeBuilder = representationFieldBuilder!.type; + if (_representationFieldFragment != null) { + TypeBuilder typeBuilder = _representationFieldFragment!.type; if (typeBuilder.isExplicit) { if (_checkRepresentationDependency(typeBuilder, this, {this}, {})) { representationType = const InvalidType(); @@ -373,16 +366,16 @@ class SourceExtensionTypeDeclarationBuilder if (isBottom(representationType)) { libraryBuilder.addProblem( messageExtensionTypeRepresentationTypeBottom, - representationFieldBuilder!.fileOffset, - representationFieldBuilder!.name.length, - representationFieldBuilder!.fileUri); + _representationFieldFragment!.nameOffset, + _representationFieldFragment!.name.length, + _representationFieldFragment!.fileUri); representationType = const InvalidType(); } } } else { representationType = const DynamicType(); } - representationName = representationFieldBuilder!.name; + representationName = _representationFieldFragment!.name; } else { representationType = const InvalidType(); representationName = '#'; @@ -436,9 +429,9 @@ class SourceExtensionTypeDeclarationBuilder } libraryBuilder.addProblem( messageCyclicRepresentationDependency, - representationFieldBuilder!.type.charOffset!, + _representationFieldFragment!.type.charOffset!, noLength, - representationFieldBuilder!.type.fileUri, + _representationFieldFragment!.type.fileUri, context: context); return true; } else { diff --git a/pkg/front_end/lib/src/source/source_factory_builder.dart b/pkg/front_end/lib/src/source/source_factory_builder.dart index 234e348fe950..d7f73c82370b 100644 --- a/pkg/front_end/lib/src/source/source_factory_builder.dart +++ b/pkg/front_end/lib/src/source/source_factory_builder.dart @@ -182,6 +182,14 @@ class SourceFactoryBuilder extends SourceFunctionBuilderImpl { // Coverage-ignore(suite): Not run. bool get isProperty => false; + @override + // Coverage-ignore(suite): Not run. + bool get isFinal => false; + + @override + // Coverage-ignore(suite): Not run. + bool get isSynthesized => false; + Procedure get _procedure => isAugmenting ? origin._procedure : _procedureInternal; diff --git a/pkg/front_end/lib/src/source/source_field_builder.dart b/pkg/front_end/lib/src/source/source_field_builder.dart index 342417e4ff31..9bb0e96c266b 100644 --- a/pkg/front_end/lib/src/source/source_field_builder.dart +++ b/pkg/front_end/lib/src/source/source_field_builder.dart @@ -22,6 +22,7 @@ import '../builder/field_builder.dart'; import '../builder/member_builder.dart'; import '../builder/metadata_builder.dart'; import '../builder/omitted_type_builder.dart'; +import '../builder/property_builder.dart'; import '../builder/type_builder.dart'; import '../codes/cfe_codes.dart' show messageInternalProblemAlreadyInitialized; import '../kernel/body_builder.dart' show BodyBuilder; @@ -45,7 +46,7 @@ import 'source_extension_type_declaration_builder.dart'; import 'source_member_builder.dart'; class SourceFieldBuilder extends SourceMemberBuilderImpl - implements FieldBuilder, InferredTypeListener, Inferable { + implements FieldBuilder, InferredTypeListener, Inferable, PropertyBuilder { @override final SourceLibraryBuilder libraryBuilder; @@ -81,6 +82,7 @@ class SourceFieldBuilder extends SourceMemberBuilderImpl final bool isPrimaryConstructorField; + @override final bool isSynthesized; /// If `true`, this field builder is for the field corresponding to an enum @@ -131,6 +133,7 @@ class SourceFieldBuilder extends SourceMemberBuilderImpl late_lowering.IsSetStrategy isSetStrategy = late_lowering.computeIsSetStrategy(libraryBuilder); if (isAbstract || isExternal) { + // Coverage-ignore-block(suite): Not run. assert(fieldReference == null); assert(lateIsSetFieldReference == null); assert(lateIsSetGetterReference == null); @@ -152,7 +155,9 @@ class SourceFieldBuilder extends SourceMemberBuilderImpl isFinal: isFinal, isCovariantByDeclaration: isCovariantByDeclaration); } else if (nameScheme.isExtensionTypeMember && + // Coverage-ignore(suite): Not run. nameScheme.isInstanceMember) { + // Coverage-ignore-block(suite): Not run. assert(fieldReference == null); assert(fieldSetterReference == null); assert(lateIsSetFieldReference == null); @@ -183,10 +188,12 @@ class SourceFieldBuilder extends SourceMemberBuilderImpl isForcedExtension: true); } } else if (isLate && + // Coverage-ignore(suite): Not run. libraryBuilder.loader.target.backendTarget.isLateFieldLoweringEnabled( hasInitializer: hasInitializer, isFinal: isFinal, isStatic: !isInstanceMember)) { + // Coverage-ignore-block(suite): Not run. assert(!isEnumElement, "Unexpected late enum element"); if (hasInitializer) { if (isFinal) { @@ -265,7 +272,9 @@ class SourceFieldBuilder extends SourceMemberBuilderImpl .loader.target.backendTarget.useStaticFieldLowering && !isInstanceMember && !isConst && + // Coverage-ignore(suite): Not run. hasInitializer) { + // Coverage-ignore-block(suite): Not run. assert(!isEnumElement, "Unexpected non-const enum element"); if (isFinal) { _fieldEncoding = new LateFinalFieldWithInitializerEncoding( @@ -325,7 +334,10 @@ class SourceFieldBuilder extends SourceMemberBuilderImpl } if (type is InferableTypeBuilder) { - if (!hasInitializer && isStatic) { + if (!hasInitializer && + // Coverage-ignore(suite): Not run. + isStatic) { + // Coverage-ignore-block(suite): Not run. // A static field without type and initializer will always be inferred // to have type `dynamic`. type.registerInferredType(const DynamicType()); @@ -351,6 +363,7 @@ class SourceFieldBuilder extends SourceMemberBuilderImpl bool get isProperty => true; @override + // Coverage-ignore(suite): Not run. bool get isAugmentation => modifiers.isAugment; @override @@ -359,22 +372,28 @@ class SourceFieldBuilder extends SourceMemberBuilderImpl @override bool get isAbstract => modifiers.isAbstract; + @override + // Coverage-ignore(suite): Not run. bool get isExtensionTypeDeclaredInstanceField => isExtensionTypeInstanceMember && !isPrimaryConstructorField; @override bool get isConst => modifiers.isConst; + @override bool get isFinal => modifiers.isFinal; @override bool get isStatic => modifiers.isStatic; @override + // Coverage-ignore(suite): Not run. bool get isAugment => modifiers.isAugment; @override - Builder get parent => declarationBuilder ?? libraryBuilder; + Builder get parent => + declarationBuilder ?? // Coverage-ignore(suite): Not run. + libraryBuilder; @override Name get memberName => _memberName.name; @@ -382,6 +401,7 @@ class SourceFieldBuilder extends SourceMemberBuilderImpl bool _typeEnsured = false; Set? _overrideDependencies; + // Coverage-ignore(suite): Not run. void registerOverrideDependency(Set overriddenMembers) { assert( overriddenMembers.every((overriddenMember) => @@ -394,6 +414,7 @@ class SourceFieldBuilder extends SourceMemberBuilderImpl void _ensureType(ClassMembersBuilder membersBuilder) { if (_typeEnsured) return; if (_overrideDependencies != null) { + // Coverage-ignore-block(suite): Not run. membersBuilder.inferFieldType(declarationBuilder as SourceClassBuilder, type, _overrideDependencies!, name: fullNameForErrors, @@ -412,10 +433,12 @@ class SourceFieldBuilder extends SourceMemberBuilderImpl @override bool get isField => true; + @override bool get isLate => modifiers.isLate; bool get isCovariantByDeclaration => modifiers.isCovariant; + @override bool get hasInitializer => modifiers.hasInitializer; /// Builds the body of this field using [initializer] as the initializer @@ -425,6 +448,7 @@ class SourceFieldBuilder extends SourceMemberBuilderImpl hasBodyBeenBuilt = true; if (!hasInitializer && initializer != null && + // Coverage-ignore(suite): Not run. initializer is! NullLiteral && // Coverage-ignore(suite): Not run. !isConst && @@ -436,26 +460,28 @@ class SourceFieldBuilder extends SourceMemberBuilderImpl _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. + @override + // Coverage-ignore(suite): Not run. List 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. + @override + // Coverage-ignore(suite): Not run. void buildImplicitDefaultValue() { _fieldEncoding.buildImplicitDefaultValue(); } - /// Create the [Initializer] for the implicit initialization of this field - /// in a constructor. + @override + // Coverage-ignore(suite): Not run. Initializer buildImplicitInitializer() { return _fieldEncoding.buildImplicitInitializer(); } + @override + // Coverage-ignore(suite): Not run. Initializer buildErroneousInitializer(Expression effect, Expression value, {required int fileOffset}) { return _fieldEncoding.buildErroneousInitializer(effect, value, @@ -465,6 +491,7 @@ class SourceFieldBuilder extends SourceMemberBuilderImpl @override bool get isAssignable { if (isConst) return false; + // Coverage-ignore(suite): Not run. if (isFinal) { if (isLate) { return !hasInitializer; @@ -485,6 +512,7 @@ class SourceFieldBuilder extends SourceMemberBuilderImpl Reference get readTargetReference => _fieldEncoding.readTargetReference; @override + // Coverage-ignore(suite): Not run. Member? get writeTarget { return isAssignable ? _fieldEncoding.writeTarget : null; } @@ -501,6 +529,7 @@ class SourceFieldBuilder extends SourceMemberBuilderImpl Reference get invokeTargetReference => _fieldEncoding.readTargetReference; @override + // Coverage-ignore(suite): Not run. Iterable get exportedMemberReferences => _fieldEncoding.exportedReferenceMembers; @@ -535,18 +564,21 @@ class SourceFieldBuilder extends SourceMemberBuilderImpl createBodyBuilderContext(), libraryBuilder, fileUri, - declarationBuilder?.scope ?? libraryBuilder.scope); + declarationBuilder?.scope ?? // Coverage-ignore(suite): Not run. + 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 || + // Coverage-ignore(suite): Not run. (isFinal && !isStatic && isClassMember && classBuilder!.declaresConstConstructor)) && _constInitializerToken != null) { + // Coverage-ignore-block(suite): Not run. Token initializerToken = _constInitializerToken!; LookupScope scope = declarationBuilder?.scope ?? libraryBuilder.scope; BodyBuilder bodyBuilder = libraryBuilder.loader @@ -561,7 +593,6 @@ class SourceFieldBuilder extends SourceMemberBuilderImpl buildBody(classHierarchy.coreTypes, initializer); bodyBuilder.performBacklogComputations(); if (computeSharedExpressionForTesting) { - // Coverage-ignore-block(suite): Not run. _initializerExpression = parseFieldInitializer(libraryBuilder.loader, initializerToken, libraryBuilder.importUri, fileUri, scope); } @@ -575,11 +606,17 @@ class SourceFieldBuilder extends SourceMemberBuilderImpl // Coverage-ignore(suite): Not run. bool get hasOutlineExpressionsBuilt => _constInitializerToken == null; + @override DartType get fieldType => _fieldEncoding.type; + @override void set fieldType(DartType value) { _fieldEncoding.type = value; - if (!isFinal && !isConst && parent is ClassBuilder) { + if (!isFinal && + !isConst && + // Coverage-ignore(suite): Not run. + parent is ClassBuilder) { + // Coverage-ignore-block(suite): Not run. Class enclosingClass = classBuilder!.cls; if (enclosingClass.typeParameters.isNotEmpty) { IncludesTypeParametersNonCovariantly needsCheckVisitor = @@ -601,8 +638,10 @@ class SourceFieldBuilder extends SourceMemberBuilderImpl inferType(hierarchy); } + @override DartType inferType(ClassHierarchyBase hierarchy) { if (fieldType is! InferredType) { + // Coverage-ignore-block(suite): Not run. // We have already inferred a type. return fieldType; } @@ -630,6 +669,7 @@ class SourceFieldBuilder extends SourceMemberBuilderImpl } if (needsCheckVisitor != null) { if (fieldType.accept(needsCheckVisitor)) { + // Coverage-ignore-block(suite): Not run. _fieldEncoding.setGenericCovariantImpl(); } } @@ -643,6 +683,7 @@ class SourceFieldBuilder extends SourceMemberBuilderImpl fieldType = type; } + // Coverage-ignore(suite): Not run. DartType get builtType => fieldType; List? _localMembers; @@ -670,14 +711,28 @@ class SourceFieldBuilder extends SourceMemberBuilderImpl @override void checkVariance( SourceClassBuilder sourceClassBuilder, TypeEnvironment typeEnvironment) { - sourceClassBuilder.checkVarianceInField( - this, typeEnvironment, sourceClassBuilder.cls.typeParameters); + sourceClassBuilder.checkVarianceInField(typeEnvironment, + fieldType: fieldType, + isInstanceMember: isClassInstanceMember, + hasSetter: isAssignable, + isCovariantByDeclaration: isCovariantByDeclaration, + fileUri: fileUri, + fileOffset: fileOffset); } @override void checkTypes(SourceLibraryBuilder library, NameSpace nameSpace, TypeEnvironment typeEnvironment) { - library.checkTypesInField(this, typeEnvironment); + library.checkTypesInField(typeEnvironment, + isInstanceMember: isDeclarationInstanceMember, + isLate: isLate, + isExternal: isExternal, + hasInitializer: hasInitializer, + fieldType: fieldType, + name: name, + nameLength: name.length, + nameOffset: fileOffset, + fileUri: fileUri); } @override @@ -793,7 +848,9 @@ class RegularFieldEncoding implements FieldEncoding { fieldReference: fieldReference, getterReference: getterReference, isEnumElement: isEnumElement) - : new Field.mutable(dummyName, + : + // Coverage-ignore(suite): Not run. + new Field.mutable(dummyName, isFinal: isFinal, isLate: isLate, fileUri: fileUri, @@ -824,6 +881,7 @@ class RegularFieldEncoding implements FieldEncoding { } @override + // Coverage-ignore(suite): Not run. List createInitializer(int fileOffset, Expression value, {required bool isSynthetic}) { return [ @@ -838,16 +896,19 @@ class RegularFieldEncoding implements FieldEncoding { SourceLibraryBuilder libraryBuilder, SourceFieldBuilder fieldBuilder) { _field..isCovariantByDeclaration = fieldBuilder.isCovariantByDeclaration; if (fieldBuilder.isExtensionMember) { + // Coverage-ignore-block(suite): Not run. _field ..isStatic = true ..isExtensionMember = true; } else if (fieldBuilder.isExtensionTypeMember) { + // Coverage-ignore-block(suite): Not run. _field ..isStatic = fieldBuilder.isStatic ..isExtensionTypeMember = true; } else { - bool isInstanceMember = - !fieldBuilder.isStatic && !fieldBuilder.isTopLevel; + bool isInstanceMember = !fieldBuilder.isStatic && + // Coverage-ignore(suite): Not run. + !fieldBuilder.isTopLevel; _field ..isStatic = !isInstanceMember ..isExtensionMember = false; @@ -867,6 +928,7 @@ class RegularFieldEncoding implements FieldEncoding { } @override + // Coverage-ignore(suite): Not run. void setGenericCovariantImpl() { if (_field.hasSetter) { _field.isCovariantByClass = true; @@ -890,6 +952,7 @@ class RegularFieldEncoding implements FieldEncoding { Reference get readTargetReference => _field.getterReference; @override + // Coverage-ignore(suite): Not run. Member get writeTarget => _field; @override @@ -897,6 +960,7 @@ class RegularFieldEncoding implements FieldEncoding { Reference? get writeTargetReference => _field.setterReference; @override + // Coverage-ignore(suite): Not run. Iterable get exportedReferenceMembers => [_field.getterReference, if (_field.hasSetter) _field.setterReference!]; @@ -909,22 +973,27 @@ class RegularFieldEncoding implements FieldEncoding { @override List getLocalSetters(SourceFieldBuilder fieldBuilder) => fieldBuilder.isAssignable - ? [ + ? + // Coverage-ignore(suite): Not run. + [ new SourceFieldMember(fieldBuilder, ClassMemberKind.Setter) ] : const []; @override + // Coverage-ignore(suite): Not run. void buildImplicitDefaultValue() { _field.initializer = new NullLiteral()..parent = _field; } @override + // Coverage-ignore(suite): Not run. Initializer buildImplicitInitializer() { return new FieldInitializer(_field, new NullLiteral())..isSynthetic = true; } @override + // Coverage-ignore(suite): Not run. Initializer buildErroneousInitializer(Expression effect, Expression value, {required int fileOffset}) { return new ShadowInvalidFieldInitializer(type, value, effect) @@ -944,11 +1013,13 @@ class SourceFieldMember extends BuilderClassMember { SourceFieldMember(this.memberBuilder, this.memberKind); @override + // Coverage-ignore(suite): Not run. void inferType(ClassMembersBuilder membersBuilder) { memberBuilder._ensureType(membersBuilder); } @override + // Coverage-ignore(suite): Not run. void registerOverrideDependency(Set overriddenMembers) { memberBuilder.registerOverrideDependency(overriddenMembers); } @@ -968,6 +1039,7 @@ class SourceFieldMember extends BuilderClassMember { } @override + // Coverage-ignore(suite): Not run. Covariance getCovariance(ClassMembersBuilder membersBuilder) { return _covariance ??= forSetter ? new Covariance.fromMember(getMember(membersBuilder), @@ -976,6 +1048,7 @@ class SourceFieldMember extends BuilderClassMember { } @override + // Coverage-ignore(suite): Not run. bool get isSourceDeclaration => true; @override @@ -983,10 +1056,13 @@ class SourceFieldMember extends BuilderClassMember { @override bool isSameDeclaration(ClassMember other) { - return other is SourceFieldMember && memberBuilder == other.memberBuilder; + return other is SourceFieldMember && + // Coverage-ignore(suite): Not run. + memberBuilder == other.memberBuilder; } } +// Coverage-ignore(suite): Not run. abstract class AbstractLateFieldEncoding implements FieldEncoding { final String name; final int fileOffset; @@ -1264,14 +1340,12 @@ abstract class AbstractLateFieldEncoding implements FieldEncoding { Member get readTarget => _lateGetter; @override - // Coverage-ignore(suite): Not run. Reference get readTargetReference => _lateGetter.reference; @override Member? get writeTarget => _lateSetter; @override - // Coverage-ignore(suite): Not run. Reference? get writeTargetReference => _lateSetter?.reference; @override @@ -1294,7 +1368,6 @@ abstract class AbstractLateFieldEncoding implements FieldEncoding { ..isExtensionMember = isExtensionMember; isInstanceMember = false; } else if (isExtensionTypeMember) { - // Coverage-ignore-block(suite): Not run. _field ..isStatic = fieldBuilder.isStatic ..isExtensionTypeMember = true; @@ -1399,6 +1472,7 @@ abstract class AbstractLateFieldEncoding implements FieldEncoding { mixin NonFinalLate on AbstractLateFieldEncoding { @override + // Coverage-ignore(suite): Not run. Statement _createSetterBody( CoreTypes coreTypes, String name, VariableDeclaration parameter) { assert(_type != null, "Type has not been computed for field $name."); @@ -1415,6 +1489,7 @@ mixin NonFinalLate on AbstractLateFieldEncoding { mixin LateWithoutInitializer on AbstractLateFieldEncoding { @override + // Coverage-ignore(suite): Not run. Statement _createGetterBody( CoreTypes coreTypes, String name, Expression? initializer) { assert(_type != null, "Type has not been computed for field $name."); @@ -1443,6 +1518,7 @@ mixin LateWithoutInitializer on AbstractLateFieldEncoding { } } +// Coverage-ignore(suite): Not run. class LateFieldWithoutInitializerEncoding extends AbstractLateFieldEncoding with NonFinalLate, LateWithoutInitializer { LateFieldWithoutInitializerEncoding( @@ -1463,6 +1539,7 @@ class LateFieldWithoutInitializerEncoding extends AbstractLateFieldEncoding required super.isSetStrategy}); } +// Coverage-ignore(suite): Not run. class LateFieldWithInitializerEncoding extends AbstractLateFieldEncoding with NonFinalLate { LateFieldWithInitializerEncoding( @@ -1514,6 +1591,7 @@ class LateFieldWithInitializerEncoding extends AbstractLateFieldEncoding } } +// Coverage-ignore(suite): Not run. class LateFinalFieldWithoutInitializerEncoding extends AbstractLateFieldEncoding with LateWithoutInitializer { LateFinalFieldWithoutInitializerEncoding( @@ -1551,6 +1629,7 @@ class LateFinalFieldWithoutInitializerEncoding extends AbstractLateFieldEncoding } } +// Coverage-ignore(suite): Not run. class LateFinalFieldWithInitializerEncoding extends AbstractLateFieldEncoding { LateFinalFieldWithInitializerEncoding( {required super.name, @@ -1591,7 +1670,6 @@ class LateFinalFieldWithInitializerEncoding extends AbstractLateFieldEncoding { null; @override - // Coverage-ignore(suite): Not run. Statement _createSetterBody( CoreTypes coreTypes, String name, VariableDeclaration parameter) => throw new UnsupportedError( @@ -1614,6 +1692,7 @@ class LateFinalFieldWithInitializerEncoding extends AbstractLateFieldEncoding { } } +// Coverage-ignore(suite): Not run. class _SynthesizedFieldClassMember implements ClassMember { final SourceFieldBuilder fieldBuilder; final _SynthesizedFieldMemberKind _kind; @@ -1683,7 +1762,6 @@ class _SynthesizedFieldClassMember implements ClassMember { DeclarationBuilder get declarationBuilder => fieldBuilder.declarationBuilder!; @override - // Coverage-ignore(suite): Not run. bool isObjectMember(ClassBuilder objectClass) { return declarationBuilder == objectClass; } @@ -1713,7 +1791,6 @@ class _SynthesizedFieldClassMember implements ClassMember { Name get name => _name; @override - // Coverage-ignore(suite): Not run. String get fullName { String suffix = isSetter ? "=" : ""; String className = declarationBuilder.fullNameForErrors; @@ -1739,7 +1816,6 @@ class _SynthesizedFieldClassMember implements ClassMember { bool get hasDeclarations => false; @override - // Coverage-ignore(suite): Not run. List get declarations => throw new UnsupportedError("$runtimeType.declarations"); @@ -1765,6 +1841,7 @@ class _SynthesizedFieldClassMember implements ClassMember { bool get isExtensionTypeMember => fieldBuilder.isExtensionTypeMember; } +// Coverage-ignore(suite): Not run. class AbstractOrExternalFieldEncoding implements FieldEncoding { final SourceFieldBuilder _fieldBuilder; final bool isAbstract; @@ -1935,7 +2012,6 @@ class AbstractOrExternalFieldEncoding implements FieldEncoding { 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; @@ -2010,7 +2086,6 @@ class AbstractOrExternalFieldEncoding implements FieldEncoding { } @override - // Coverage-ignore(suite): Not run. void setGenericCovariantImpl() { _setter!.function.positionalParameters.first.isCovariantByClass = true; } @@ -2036,14 +2111,12 @@ class AbstractOrExternalFieldEncoding implements FieldEncoding { Member get readTarget => _getter; @override - // Coverage-ignore(suite): Not run. Reference get readTargetReference => _getter.reference; @override Member? get writeTarget => _setter; @override - // Coverage-ignore(suite): Not run. Reference? get writeTargetReference => _setter?.reference; @override @@ -2098,6 +2171,7 @@ class AbstractOrExternalFieldEncoding implements FieldEncoding { } } +// Coverage-ignore(suite): Not run. /// The encoding of an extension type declaration representation field. class RepresentationFieldEncoding implements FieldEncoding { final SourceFieldBuilder _fieldBuilder; @@ -2134,10 +2208,7 @@ class RepresentationFieldEncoding implements FieldEncoding { @override void set type(DartType value) { - assert( - _type == null || - // Coverage-ignore(suite): Not run. - _type is InferredType, + assert(_type == null || _type is InferredType, "Type has already been computed for field ${_fieldBuilder.name}."); _type = value; if (value is! InferredType) { @@ -2146,7 +2217,6 @@ class RepresentationFieldEncoding implements FieldEncoding { } @override - // Coverage-ignore(suite): Not run. void createBodies(CoreTypes coreTypes, Expression? initializer) { // TODO(johnniwinther): Enable this assert. //assert(initializer != null); @@ -2198,19 +2268,15 @@ class RepresentationFieldEncoding implements FieldEncoding { Member get readTarget => _getter; @override - // Coverage-ignore(suite): Not run. Reference get readTargetReference => _getter.reference; @override - // Coverage-ignore(suite): Not run. Member? get writeTarget => null; @override - // Coverage-ignore(suite): Not run. Reference? get writeTargetReference => null; @override - // Coverage-ignore(suite): Not run. Iterable get exportedReferenceMembers => [_getter.reference]; @override @@ -2230,7 +2296,6 @@ class RepresentationFieldEncoding implements FieldEncoding { const []; @override - // Coverage-ignore(suite): Not run. void buildImplicitDefaultValue() { // Not needed. } diff --git a/pkg/front_end/lib/src/source/source_library_builder.dart b/pkg/front_end/lib/src/source/source_library_builder.dart index 0b046cd88797..85f0fb209247 100644 --- a/pkg/front_end/lib/src/source/source_library_builder.dart +++ b/pkg/front_end/lib/src/source/source_library_builder.dart @@ -70,7 +70,6 @@ import 'source_class_builder.dart' show SourceClassBuilder; import 'source_extension_builder.dart'; import 'source_extension_type_declaration_builder.dart'; import 'source_factory_builder.dart'; -import 'source_field_builder.dart'; import 'source_loader.dart' show CompilationPhaseForProblemReporting, SourceLoader; import 'source_member_builder.dart'; @@ -874,7 +873,7 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { while (memberIterator.moveNext()) { SourceMemberBuilder member = memberIterator.current; if (member.isStatic) continue; - if (member is SourceFieldBuilder) { + if (member.isField) { if (member.isSynthesized) continue; PropertyNonPromotabilityReason? reason = fieldPromotability.addField( classInfo, member, member.name, @@ -882,7 +881,7 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { isAbstract: member.isAbstract, isExternal: member.isExternal); if (reason != null) { - individualPropertyReasons[member.readTarget] = reason; + individualPropertyReasons[member.readTarget!] = reason; } } else if (member.isGetter) { if (member.isSynthetic) continue; @@ -1655,26 +1654,33 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { addProblem(message, fileOffset, noLength, fileUri, context: context); } - void checkTypesInField( - SourceFieldBuilder fieldBuilder, TypeEnvironment typeEnvironment) { + void checkTypesInField(TypeEnvironment typeEnvironment, + {required bool isInstanceMember, + required bool isLate, + required bool isExternal, + required bool hasInitializer, + required DartType fieldType, + required String name, + required int nameLength, + required int nameOffset, + required Uri fileUri}) { // Check that the field has an initializer if its type is potentially // non-nullable. // Only static and top-level fields are checked here. Instance fields are // checked elsewhere. - DartType fieldType = fieldBuilder.fieldType; - if (!fieldBuilder.isDeclarationInstanceMember && - !fieldBuilder.isLate && - !fieldBuilder.isExternal && + if (!isInstanceMember && + !isLate && + !isExternal && fieldType is! InvalidType && fieldType.isPotentiallyNonNullable && - !fieldBuilder.hasInitializer) { + !hasInitializer) { addProblem( templateFieldNonNullableWithoutInitializerError.withArguments( - fieldBuilder.name, fieldBuilder.fieldType), - fieldBuilder.fileOffset, - fieldBuilder.name.length, - fieldBuilder.fileUri); + name, fieldType), + nameOffset, + nameLength, + fileUri); } } @@ -2212,8 +2218,8 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { /// This class examines all the [Class]es in a library and determines which /// fields are promotable within that library. -class _FieldPromotability - extends FieldPromotability { +class _FieldPromotability extends FieldPromotability { @override Iterable getSuperclasses(Class class_, {required bool ignoreImplements}) { @@ -2253,7 +2259,7 @@ class FieldNonPromotabilityInfo { /// see [individualPropertyReasons]. final Map< String, - FieldNameNonPromotabilityInfo> fieldNameInfo; /// Map whose keys are the members that a property get might resolve to, and diff --git a/pkg/front_end/lib/src/source/source_member_builder.dart b/pkg/front_end/lib/src/source/source_member_builder.dart index 1f9ef7530be7..43a412c3a3ca 100644 --- a/pkg/front_end/lib/src/source/source_member_builder.dart +++ b/pkg/front_end/lib/src/source/source_member_builder.dart @@ -28,6 +28,14 @@ abstract class SourceMemberBuilder implements MemberBuilder { @override SourceLibraryBuilder get libraryBuilder; + @override + Uri get fileUri; + + bool get isFinal; + + // TODO(johnniwinther): Avoid this or define a clear semantics. + bool get isSynthesized; + /// Builds the core AST structures for this member as needed for the outline. void buildOutlineNodes(BuildNodesCallback f); diff --git a/pkg/front_end/lib/src/source/source_method_builder.dart b/pkg/front_end/lib/src/source/source_method_builder.dart index af9fad67d606..8b7ba28bfab7 100644 --- a/pkg/front_end/lib/src/source/source_method_builder.dart +++ b/pkg/front_end/lib/src/source/source_method_builder.dart @@ -118,6 +118,14 @@ class SourceMethodBuilder extends SourceMemberBuilderImpl @override bool get isAugment => _modifiers.isAugment; + @override + // Coverage-ignore(suite): Not run. + bool get isFinal => false; + + @override + // Coverage-ignore(suite): Not run. + bool get isSynthesized => false; + // TODO(johnniwinther): What is this supposed to return? @override // Coverage-ignore(suite): Not run. diff --git a/pkg/front_end/lib/src/source/source_property_builder.dart b/pkg/front_end/lib/src/source/source_property_builder.dart index 4d2482e7d173..fef0e3c3caea 100644 --- a/pkg/front_end/lib/src/source/source_property_builder.dart +++ b/pkg/front_end/lib/src/source/source_property_builder.dart @@ -2,8 +2,10 @@ // 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/metadata/expressions.dart' as shared; import 'package:kernel/ast.dart'; import 'package:kernel/class_hierarchy.dart'; +import 'package:kernel/reference_from_index.dart'; import 'package:kernel/type_algebra.dart'; import 'package:kernel/type_environment.dart'; @@ -14,6 +16,7 @@ import '../builder/builder.dart'; import '../builder/declaration_builders.dart'; import '../builder/formal_parameter_builder.dart'; import '../builder/metadata_builder.dart'; +import '../builder/property_builder.dart'; import '../builder/type_builder.dart'; import '../fragment/fragment.dart'; import '../kernel/augmentation_lowering.dart'; @@ -26,9 +29,11 @@ import 'name_scheme.dart'; import 'source_class_builder.dart'; import 'source_function_builder.dart'; import 'source_library_builder.dart'; +import 'source_loader.dart'; import 'source_member_builder.dart'; -class SourcePropertyBuilder extends SourceMemberBuilderImpl { +class SourcePropertyBuilder extends SourceMemberBuilderImpl + implements PropertyBuilder { @override final Uri fileUri; @@ -53,13 +58,13 @@ class SourcePropertyBuilder extends SourceMemberBuilderImpl { /// same name must be augmentations. // TODO(johnniwinther): Support setter and field declarations. // TODO(johnniwinther): Add [_augmentations] field. + FieldFragment? _introductoryField; GetterFragment? _introductoryGetable; SetterFragment? _introductorySetable; Modifiers _modifiers; - final Reference? _getterReference; - final Reference? _setterReference; + final PropertyReferences _references; final MemberName _memberName; @@ -89,12 +94,11 @@ class SourcePropertyBuilder extends SourceMemberBuilderImpl { required this.isStatic, required NameScheme nameScheme, required GetterFragment fragment, - required Reference? getterReference}) + required PropertyReferences references}) : _nameScheme = nameScheme, _introductoryGetable = fragment, _modifiers = fragment.modifiers, - _getterReference = getterReference ?? new Reference(), - _setterReference = null, + _references = references, _memberName = nameScheme.getDeclaredName(name); SourcePropertyBuilder.forSetter( @@ -106,12 +110,27 @@ class SourcePropertyBuilder extends SourceMemberBuilderImpl { required this.isStatic, required NameScheme nameScheme, required SetterFragment fragment, - required Reference? setterReference}) + required PropertyReferences references}) : _nameScheme = nameScheme, _introductorySetable = fragment, _modifiers = fragment.modifiers, - _getterReference = null, - _setterReference = setterReference ?? new Reference(), + _references = references, + _memberName = nameScheme.getDeclaredName(name); + + SourcePropertyBuilder.forField( + {required this.fileUri, + required this.fileOffset, + required this.name, + required this.libraryBuilder, + required this.declarationBuilder, + required this.isStatic, + required NameScheme nameScheme, + required FieldFragment fragment, + required PropertyReferences references}) + : _nameScheme = nameScheme, + _introductoryField = fragment, + _modifiers = fragment.modifiers, + _references = references, _memberName = nameScheme.getDeclaredName(name); @override @@ -133,20 +152,27 @@ class SourcePropertyBuilder extends SourceMemberBuilderImpl { @override bool get isAugment => _modifiers.isAugment; + @override + bool get isSynthesized => false; + // TODO(johnniwinther): What is this supposed to return? @override // Coverage-ignore(suite): Not run. Iterable get annotatables => [ if (readTarget != null) readTarget as Annotatable, - if (writeTarget != null) writeTarget as Annotatable + if (writeTarget != null && readTarget != writeTarget) + writeTarget as Annotatable ]; // TODO(johnniwinther): Remove this. This is only needed for detecting patches // and macro annotations and we should use the fragment directly once // augmentations are fragments. List? get metadata => - _introductoryGetable?.metadata ?? // Coverage-ignore(suite): Not run. - _introductorySetable?.metadata; + _introductoryGetable?.metadata ?? + _introductorySetable + // Coverage-ignore(suite): Not run. + ?.metadata ?? + _introductoryField?.metadata; @override void applyAugmentation(Builder augmentation) { @@ -344,11 +370,14 @@ class SourcePropertyBuilder extends SourceMemberBuilderImpl { @override void buildOutlineNodes(BuildNodesCallback f) { - _introductoryGetable?.buildOutlineNode(libraryBuilder, _nameScheme, f, - getterReference: _getterReference!, + _introductoryField?.buildOutlineNode( + libraryBuilder, _nameScheme, f, _references as FieldReference, + classTypeParameters: classBuilder?.cls.typeParameters); + _introductoryGetable?.buildOutlineNode( + libraryBuilder, _nameScheme, f, _references as GetterReference, classTypeParameters: classBuilder?.cls.typeParameters); - _introductorySetable?.buildOutlineNode(libraryBuilder, _nameScheme, f, - setterReference: _setterReference!, + _introductorySetable?.buildOutlineNode( + libraryBuilder, _nameScheme, f, _references as SetterReference, classTypeParameters: classBuilder?.cls.typeParameters); } @@ -360,6 +389,18 @@ class SourcePropertyBuilder extends SourceMemberBuilderImpl { if (!hasBuiltOutlineExpressions) { LookupScope parentScope = declarationBuilder?.scope ?? libraryBuilder.scope; + _introductoryField?.buildOutlineExpressions( + classHierarchy, + libraryBuilder, + declarationBuilder, + parentScope, + [ + readTarget as Annotatable, + if (writeTarget != null && readTarget != writeTarget) + writeTarget as Annotatable + ], + isClassInstanceMember: isClassInstanceMember, + createFileUriExpression: isAugmented); _introductoryGetable?.buildOutlineExpressions( classHierarchy, libraryBuilder, @@ -390,6 +431,8 @@ class SourcePropertyBuilder extends SourceMemberBuilderImpl { setterBuilder = nameSpace.lookupLocalMember(name, setter: true) as SourcePropertyBuilder?; } + _introductoryField?.checkTypes(library, typeEnvironment, setterBuilder, + isExternal: isExternal, isAbstract: isAbstract); _introductoryGetable?.checkTypes(library, typeEnvironment, setterBuilder, isExternal: isExternal, isAbstract: isAbstract); _introductorySetable?.checkTypes(library, typeEnvironment, @@ -412,6 +455,7 @@ class SourcePropertyBuilder extends SourceMemberBuilderImpl { void checkVariance( SourceClassBuilder sourceClassBuilder, TypeEnvironment typeEnvironment) { if (!isClassInstanceMember) return; + _introductoryField?.checkVariance(sourceClassBuilder, typeEnvironment); _introductoryGetable?.checkVariance(sourceClassBuilder, typeEnvironment); _introductorySetable?.checkVariance(sourceClassBuilder, typeEnvironment); List? getterAugmentations = _getterAugmentations; @@ -430,21 +474,24 @@ class SourcePropertyBuilder extends SourceMemberBuilderImpl { @override Iterable get exportedMemberReferences => [ - if (_getterReference != null) _getterReference, - if (_setterReference != null) _setterReference + ...?_introductoryField + ?.getExportedMemberReferences(_references as FieldReference), + ...?_introductoryGetable + ?.getExportedMemberReferences(_references as GetterReference), + ...?_introductorySetable + ?.getExportedMemberReferences(_references as SetterReference), ]; + // TODO(johnniwinther): Should fields and getters have an invoke target? @override - Member? get invokeTarget => null; + Member? get invokeTarget => readTarget; @override // Coverage-ignore(suite): Not run. - Reference? get invokeTargetReference => null; + Reference? get invokeTargetReference => readTargetReference; @override - // Coverage-ignore(suite): Not run. - bool get isAssignable => - throw new UnsupportedError('$runtimeType.isAssignable'); + bool get isAssignable => _introductoryField?.hasSetter ?? false; List? _localMembers; @@ -452,12 +499,14 @@ class SourcePropertyBuilder extends SourceMemberBuilderImpl { @override List get localMembers => _localMembers ??= [ + ...?_introductoryField?.localMembers, if (_introductoryGetable != null) new _GetterClassMember(this, _introductoryGetable!) ]; @override List get localSetters => _localSetters ??= [ + ...?_introductoryField?.localSetters, if (_introductorySetable != null && !isConflictingSetter) new _SetterClassMember(this, _introductorySetable!) ]; @@ -466,27 +515,33 @@ class SourcePropertyBuilder extends SourceMemberBuilderImpl { Name get memberName => _memberName.name; @override - Member? get readTarget => - isAugmenting ? _origin!.readTarget : _introductoryGetable?.readTarget; + Member? get readTarget => isAugmenting + ? _origin!.readTarget + : (_introductoryField?.readTarget ?? _introductoryGetable?.readTarget); @override // Coverage-ignore(suite): Not run. Reference? get readTargetReference => - isAugmenting ? _origin!.readTargetReference : _getterReference; + isAugmenting ? _origin!.readTargetReference : _references.getterReference; @override - Member? get writeTarget => - isAugmenting ? _origin!.writeTarget : _introductorySetable?.writeTarget; + Member? get writeTarget => isAugmenting + ? _origin!.writeTarget + : (_introductorySetable?.writeTarget ?? _introductoryField?.writeTarget); @override // Coverage-ignore(suite): Not run. - Reference? get writeTargetReference => - isAugmenting ? _origin!.writeTargetReference : _setterReference; + Reference? get writeTargetReference => isAugmenting + ? _origin!.writeTargetReference + : _references.setterReference; @override int computeDefaultTypes(ComputeDefaultTypeContext context, {required bool inErrorRecovery}) { int count = 0; + if (_introductoryField != null) { + count += _introductoryField!.computeDefaultTypes(context); + } if (_introductoryGetable != null) { count += _introductoryGetable!.computeDefaultTypes(context); } @@ -517,12 +572,20 @@ class SourcePropertyBuilder extends SourceMemberBuilderImpl { TypeBuilder? get returnTypeForTesting => _introductoryGetable?.returnType ?? _introductorySetable?.returnType; + // Coverage-ignore(suite): Not run. + TypeBuilder? get typeForTesting => _introductoryField?.type; + @override bool get isAugmenting => this != origin; @override bool get isProperty => true; + // TODO(johnniwinther): Remove this. Maybe replace with `hasField`, + // `hasGetter` and `hasSetter`? + @override + bool get isField => _introductoryField != null; + // TODO(johnniwinther): Remove this. Maybe replace with `hasGetter`? @override bool get isGetter => _introductoryGetable != null; @@ -534,7 +597,7 @@ class SourcePropertyBuilder extends SourceMemberBuilderImpl { bool _typeEnsured = false; Set? _getterOverrideDependencies; - void _registerGetterOverrideDependency(Set overriddenMembers) { + void registerGetterOverrideDependency(Set overriddenMembers) { assert( overriddenMembers.every((overriddenMember) => overriddenMember.declarationBuilder != classBuilder), @@ -545,7 +608,7 @@ class SourcePropertyBuilder extends SourceMemberBuilderImpl { Set? _setterOverrideDependencies; - void _registerSetterOverrideDependency(Set overriddenMembers) { + void registerSetterOverrideDependency(Set overriddenMembers) { assert( overriddenMembers.every((overriddenMember) => overriddenMember.declarationBuilder != classBuilder), @@ -554,13 +617,15 @@ class SourcePropertyBuilder extends SourceMemberBuilderImpl { _setterOverrideDependencies!.addAll(overriddenMembers); } - void _ensureTypes(ClassMembersBuilder membersBuilder) { + void ensureTypes(ClassMembersBuilder membersBuilder) { if (_typeEnsured) return; - _introductoryGetable?.ensureTypes(membersBuilder, - declarationBuilder as SourceClassBuilder, _getterOverrideDependencies); + _introductoryField?.ensureTypes(membersBuilder, _getterOverrideDependencies, + _setterOverrideDependencies); + _introductoryGetable?.ensureTypes( + membersBuilder, _getterOverrideDependencies); + _introductorySetable?.ensureTypes( + membersBuilder, _setterOverrideDependencies); _getterOverrideDependencies = null; - _introductorySetable?.ensureTypes(membersBuilder, - declarationBuilder as SourceClassBuilder, _setterOverrideDependencies); _setterOverrideDependencies = null; _typeEnsured = true; } @@ -602,6 +667,63 @@ class SourcePropertyBuilder extends SourceMemberBuilderImpl { } return setterType; } + + @override + DartType get fieldType { + return _introductoryField!.fieldType; + } + + @override + // Coverage-ignore(suite): Not run. + void set fieldType(DartType value) { + _introductoryField!.fieldType = value; + } + + @override + Initializer buildErroneousInitializer(Expression effect, Expression value, + {required int fileOffset}) { + return _introductoryField! + .buildErroneousInitializer(effect, value, fileOffset: fileOffset); + } + + @override + void buildImplicitDefaultValue() { + _introductoryField!.buildImplicitDefaultValue(); + } + + @override + Initializer buildImplicitInitializer() { + return _introductoryField!.buildImplicitInitializer(); + } + + @override + List buildInitializer(int fileOffset, Expression value, + {required bool isSynthetic}) { + return _introductoryField! + .buildInitializer(fileOffset, value, isSynthetic: isSynthetic); + } + + @override + bool get hasInitializer => _introductoryField!.hasInitializer; + + @override + bool get isExtensionTypeDeclaredInstanceField => + _introductoryField!.isExtensionTypeDeclaredInstanceField; + + @override + bool get isFinal => _introductoryField!.isFinal; + + @override + bool get isLate => _introductoryField!.isLate; + + @override + DartType inferType(ClassHierarchyBase hierarchy) { + return _introductoryField!.inferType(hierarchy); + } + + // Coverage-ignore(suite): Not run. + shared.Expression? get initializerExpression => + _introductoryField?.initializerExpression; } class _GetterClassMember implements ClassMember { @@ -674,7 +796,7 @@ class _GetterClassMember implements ClassMember { @override void inferType(ClassMembersBuilder membersBuilder) { - _builder._ensureTypes(membersBuilder); + _builder.ensureTypes(membersBuilder); } @override @@ -741,7 +863,7 @@ class _GetterClassMember implements ClassMember { @override void registerOverrideDependency(Set overriddenMembers) { - _builder._registerGetterOverrideDependency(overriddenMembers); + _builder.registerGetterOverrideDependency(overriddenMembers); } @override @@ -820,7 +942,7 @@ class _SetterClassMember implements ClassMember { @override void inferType(ClassMembersBuilder membersBuilder) { - _builder._ensureTypes(membersBuilder); + _builder.ensureTypes(membersBuilder); } @override @@ -886,9 +1008,332 @@ class _SetterClassMember implements ClassMember { @override void registerOverrideDependency(Set overriddenMembers) { - _builder._registerSetterOverrideDependency(overriddenMembers); + _builder.registerSetterOverrideDependency(overriddenMembers); } @override String toString() => '$runtimeType($fullName,forSetter=${forSetter})'; } + +abstract class PropertyReferences { + Reference? get getterReference; + Reference? get setterReference; +} + +class GetterReference extends PropertyReferences { + Reference? _getterReference; + + GetterReference._(this._getterReference); + + factory GetterReference( + String name, NameScheme nameScheme, IndexedContainer? indexedContainer, + {required bool isAugmentation}) { + Reference? procedureReference; + ProcedureKind kind = ProcedureKind.Getter; + if (indexedContainer != null && !isAugmentation) { + Name nameToLookup = nameScheme.getProcedureMemberName(kind, name).name; + procedureReference = indexedContainer.lookupGetterReference(nameToLookup); + } + return new GetterReference._(procedureReference); + } + + void registerReference(SourceLoader loader, Builder builder) { + if (_getterReference != null) { + loader.buildersCreatedWithReferences[_getterReference!] = builder; + } + } + + @override + Reference get getterReference => _getterReference ??= new Reference(); + + @override + // Coverage-ignore(suite): Not run. + Reference? get setterReference => null; +} + +class SetterReference extends PropertyReferences { + Reference? _setterReference; + + SetterReference._(this._setterReference); + + factory SetterReference( + String name, NameScheme nameScheme, IndexedContainer? indexedContainer, + {required bool isAugmentation}) { + Reference? procedureReference; + ProcedureKind kind = ProcedureKind.Setter; + if (indexedContainer != null && !isAugmentation) { + Name nameToLookup = nameScheme.getProcedureMemberName(kind, name).name; + if ((nameScheme.isExtensionMember || nameScheme.isExtensionTypeMember) && + nameScheme.isInstanceMember) { + // Extension (type) instance setters are encoded as methods. + procedureReference = + indexedContainer.lookupGetterReference(nameToLookup); + } else { + procedureReference = + indexedContainer.lookupSetterReference(nameToLookup); + } + } + return new SetterReference._(procedureReference); + } + + void registerReference(SourceLoader loader, Builder builder) { + if (_setterReference != null) { + loader.buildersCreatedWithReferences[_setterReference!] = builder; + } + } + + @override + // Coverage-ignore(suite): Not run. + Reference? get getterReference => null; + + @override + Reference get setterReference => _setterReference ??= new Reference(); +} + +abstract class FieldReference extends PropertyReferences { + factory FieldReference( + String name, NameScheme nameScheme, IndexedContainer? indexedContainer, + {required bool fieldIsLateWithLowering, required bool isExternal}) { + Reference? fieldReference; + Reference? fieldGetterReference; + Reference? fieldSetterReference; + Reference? lateIsSetFieldReference; + Reference? lateIsSetGetterReference; + Reference? lateIsSetSetterReference; + Reference? lateGetterReference; + Reference? lateSetterReference; + if (indexedContainer != null) { + if ((nameScheme.isExtensionMember || nameScheme.isExtensionTypeMember) && + nameScheme.isInstanceMember && + isExternal) { + /// An external extension (type) instance field is special. It is + /// treated as an external getter/setter pair and is therefore + /// encoded as a pair of top level methods using the extension + /// instance member naming convention. + fieldGetterReference = indexedContainer.lookupGetterReference( + nameScheme.getProcedureMemberName(ProcedureKind.Getter, name).name); + fieldSetterReference = indexedContainer.lookupGetterReference( + nameScheme.getProcedureMemberName(ProcedureKind.Setter, name).name); + } else if (nameScheme.isExtensionTypeMember && + nameScheme.isInstanceMember) { + Name nameToLookup = nameScheme + .getFieldMemberName(FieldNameType.RepresentationField, name, + isSynthesized: true) + .name; + fieldGetterReference = + indexedContainer.lookupGetterReference(nameToLookup); + } else { + Name nameToLookup = nameScheme + .getFieldMemberName(FieldNameType.Field, name, + isSynthesized: fieldIsLateWithLowering) + .name; + fieldReference = indexedContainer.lookupFieldReference(nameToLookup); + fieldGetterReference = + indexedContainer.lookupGetterReference(nameToLookup); + fieldSetterReference = + indexedContainer.lookupSetterReference(nameToLookup); + } + + if (fieldIsLateWithLowering) { + Name lateIsSetName = nameScheme + .getFieldMemberName(FieldNameType.IsSetField, name, + isSynthesized: fieldIsLateWithLowering) + .name; + lateIsSetFieldReference = + indexedContainer.lookupFieldReference(lateIsSetName); + lateIsSetGetterReference = + indexedContainer.lookupGetterReference(lateIsSetName); + lateIsSetSetterReference = + indexedContainer.lookupSetterReference(lateIsSetName); + lateGetterReference = indexedContainer.lookupGetterReference(nameScheme + .getFieldMemberName(FieldNameType.Getter, name, + isSynthesized: fieldIsLateWithLowering) + .name); + lateSetterReference = indexedContainer.lookupSetterReference(nameScheme + .getFieldMemberName(FieldNameType.Setter, name, + isSynthesized: fieldIsLateWithLowering) + .name); + } + } + if (fieldIsLateWithLowering) { + return new _LateFieldLoweringReference._( + fieldReference: fieldReference, + fieldGetterReference: fieldGetterReference, + fieldSetterReference: fieldSetterReference, + lateIsSetFieldReference: lateIsSetFieldReference, + lateIsSetGetterReference: lateIsSetGetterReference, + lateIsSetSetterReference: lateIsSetSetterReference, + lateGetterReference: lateGetterReference, + lateSetterReference: lateSetterReference); + } else { + return new _RegularFieldReference._( + fieldReference: fieldReference, + fieldGetterReference: fieldGetterReference, + fieldSetterReference: fieldSetterReference, + lateIsSetFieldReference: lateIsSetFieldReference, + lateIsSetGetterReference: lateIsSetGetterReference, + lateIsSetSetterReference: lateIsSetSetterReference, + lateGetterReference: lateGetterReference, + lateSetterReference: lateSetterReference); + } + } + + void registerReference(SourceLoader loader, Builder builder); + + Reference get fieldReference; + Reference get fieldGetterReference; + Reference get fieldSetterReference; + Reference get lateIsSetFieldReference; + Reference get lateIsSetGetterReference; + Reference get lateIsSetSetterReference; + Reference get lateGetterReference; + Reference get lateSetterReference; +} + +class _RegularFieldReference implements FieldReference { + Reference? _fieldReference; + Reference? _fieldGetterReference; + Reference? _fieldSetterReference; + Reference? _lateIsSetFieldReference; + Reference? _lateIsSetGetterReference; + Reference? _lateIsSetSetterReference; + Reference? _lateGetterReference; + Reference? _lateSetterReference; + + _RegularFieldReference._( + {required Reference? fieldReference, + required Reference? fieldGetterReference, + required Reference? fieldSetterReference, + required Reference? lateIsSetFieldReference, + required Reference? lateIsSetGetterReference, + required Reference? lateIsSetSetterReference, + required Reference? lateGetterReference, + required Reference? lateSetterReference}) + : _fieldReference = fieldReference, + _fieldGetterReference = fieldGetterReference, + _fieldSetterReference = fieldSetterReference, + _lateIsSetFieldReference = lateIsSetFieldReference, + _lateIsSetGetterReference = lateIsSetGetterReference, + _lateIsSetSetterReference = lateIsSetSetterReference, + _lateGetterReference = lateGetterReference, + _lateSetterReference = lateSetterReference; + + @override + void registerReference(SourceLoader loader, Builder builder) { + if (_fieldGetterReference != null) { + loader.buildersCreatedWithReferences[_fieldGetterReference!] = builder; + } + if (_fieldSetterReference != null) { + loader.buildersCreatedWithReferences[_fieldSetterReference!] = builder; + } + } + + @override + Reference get fieldReference => _fieldReference ??= new Reference(); + + @override + Reference get fieldGetterReference => + _fieldGetterReference ??= new Reference(); + + @override + Reference get fieldSetterReference => + _fieldSetterReference ??= new Reference(); + + @override + Reference get lateIsSetFieldReference => + _lateIsSetFieldReference ??= new Reference(); + + @override + Reference get lateIsSetGetterReference => + _lateIsSetGetterReference ??= new Reference(); + + @override + Reference get lateIsSetSetterReference => + _lateIsSetSetterReference ??= new Reference(); + + @override + Reference get lateGetterReference => _lateGetterReference ??= new Reference(); + + @override + Reference get lateSetterReference => _lateSetterReference ??= new Reference(); + + @override + Reference? get getterReference => fieldGetterReference; + + @override + Reference? get setterReference => fieldSetterReference; +} + +class _LateFieldLoweringReference implements FieldReference { + Reference? _fieldReference; + Reference? _fieldGetterReference; + Reference? _fieldSetterReference; + Reference? _lateIsSetFieldReference; + Reference? _lateIsSetGetterReference; + Reference? _lateIsSetSetterReference; + Reference? _lateGetterReference; + Reference? _lateSetterReference; + + _LateFieldLoweringReference._( + {required Reference? fieldReference, + required Reference? fieldGetterReference, + required Reference? fieldSetterReference, + required Reference? lateIsSetFieldReference, + required Reference? lateIsSetGetterReference, + required Reference? lateIsSetSetterReference, + required Reference? lateGetterReference, + required Reference? lateSetterReference}) + : _fieldReference = fieldReference, + _fieldGetterReference = fieldGetterReference, + _fieldSetterReference = fieldSetterReference, + _lateIsSetFieldReference = lateIsSetFieldReference, + _lateIsSetGetterReference = lateIsSetGetterReference, + _lateIsSetSetterReference = lateIsSetSetterReference, + _lateGetterReference = lateGetterReference, + _lateSetterReference = lateSetterReference; + + @override + void registerReference(SourceLoader loader, Builder builder) { + if (_fieldGetterReference != null) { + loader.buildersCreatedWithReferences[_fieldGetterReference!] = builder; + } + if (_fieldSetterReference != null) { + loader.buildersCreatedWithReferences[_fieldSetterReference!] = builder; + } + } + + @override + Reference get fieldReference => _fieldReference ??= new Reference(); + + @override + Reference get fieldGetterReference => + _fieldGetterReference ??= new Reference(); + + @override + Reference get fieldSetterReference => + _fieldSetterReference ??= new Reference(); + + @override + Reference get lateIsSetFieldReference => + _lateIsSetFieldReference ??= new Reference(); + + @override + Reference get lateIsSetGetterReference => + _lateIsSetGetterReference ??= new Reference(); + + @override + Reference get lateIsSetSetterReference => + _lateIsSetSetterReference ??= new Reference(); + + @override + Reference get lateGetterReference => _lateGetterReference ??= new Reference(); + + @override + Reference get lateSetterReference => _lateSetterReference ??= new Reference(); + + @override + Reference? get getterReference => lateGetterReference; + + @override + Reference? get setterReference => lateSetterReference; +} diff --git a/pkg/front_end/lib/src/source/synthetic_method_builder.dart b/pkg/front_end/lib/src/source/synthetic_method_builder.dart index 3e9689c8d383..093b352f3558 100644 --- a/pkg/front_end/lib/src/source/synthetic_method_builder.dart +++ b/pkg/front_end/lib/src/source/synthetic_method_builder.dart @@ -132,6 +132,14 @@ class SyntheticMethodBuilder extends SourceMemberBuilderImpl // Coverage-ignore(suite): Not run. bool get isProperty => false; + @override + // Coverage-ignore(suite): Not run. + bool get isFinal => false; + + @override + // Coverage-ignore(suite): Not run. + bool get isSynthesized => true; + @override late final List localMembers = [ new _SyntheticMethodClassMember(this) diff --git a/pkg/front_end/lib/src/source/type_parameter_scope_builder.dart b/pkg/front_end/lib/src/source/type_parameter_scope_builder.dart index 6bcba25c0a55..bc8b3d96303c 100644 --- a/pkg/front_end/lib/src/source/type_parameter_scope_builder.dart +++ b/pkg/front_end/lib/src/source/type_parameter_scope_builder.dart @@ -32,7 +32,6 @@ import 'source_enum_builder.dart'; import 'source_extension_builder.dart'; import 'source_extension_type_declaration_builder.dart'; import 'source_factory_builder.dart'; -import 'source_field_builder.dart'; import 'source_library_builder.dart'; import 'source_loader.dart'; import 'source_method_builder.dart'; @@ -1481,9 +1480,6 @@ void _computeBuildersFromFragments(String name, List fragments, final bool isInstanceMember = containerType != ContainerType.Library && !fragment.modifiers.isStatic; - final bool isExtensionMember = containerType == ContainerType.Extension; - final bool isExtensionTypeMember = - containerType == ContainerType.ExtensionType; NameScheme nameScheme = new NameScheme( isInstanceMember: isInstanceMember, @@ -1494,107 +1490,26 @@ void _computeBuildersFromFragments(String name, List fragments, : enclosingLibraryBuilder.libraryName); indexedContainer ??= indexedLibrary; - Reference? fieldReference; - Reference? fieldGetterReference; - Reference? fieldSetterReference; - Reference? lateIsSetFieldReference; - Reference? lateIsSetGetterReference; - Reference? lateIsSetSetterReference; - Reference? lateGetterReference; - Reference? lateSetterReference; - if (indexedContainer != null) { - if ((isExtensionMember || isExtensionTypeMember) && - isInstanceMember && - fragment.modifiers.isExternal) { - /// An external extension (type) instance field is special. It is - /// treated as an external getter/setter pair and is therefore - /// encoded as a pair of top level methods using the extension - /// instance member naming convention. - fieldGetterReference = indexedContainer!.lookupGetterReference( - nameScheme - .getProcedureMemberName(ProcedureKind.Getter, name) - .name); - fieldSetterReference = indexedContainer!.lookupGetterReference( - nameScheme - .getProcedureMemberName(ProcedureKind.Setter, name) - .name); - } else if (isExtensionTypeMember && isInstanceMember) { - Name nameToLookup = nameScheme - .getFieldMemberName(FieldNameType.RepresentationField, name, - isSynthesized: true) - .name; - fieldGetterReference = - indexedContainer!.lookupGetterReference(nameToLookup); - } else { - Name nameToLookup = nameScheme - .getFieldMemberName(FieldNameType.Field, name, - isSynthesized: fieldIsLateWithLowering) - .name; - fieldReference = - indexedContainer!.lookupFieldReference(nameToLookup); - fieldGetterReference = - indexedContainer!.lookupGetterReference(nameToLookup); - fieldSetterReference = - indexedContainer!.lookupSetterReference(nameToLookup); - } + FieldReference references = new FieldReference( + name, nameScheme, indexedContainer, + fieldIsLateWithLowering: fieldIsLateWithLowering, + isExternal: fragment.modifiers.isExternal); - if (fieldIsLateWithLowering) { - Name lateIsSetName = nameScheme - .getFieldMemberName(FieldNameType.IsSetField, name, - isSynthesized: fieldIsLateWithLowering) - .name; - lateIsSetFieldReference = - indexedContainer!.lookupFieldReference(lateIsSetName); - lateIsSetGetterReference = - indexedContainer!.lookupGetterReference(lateIsSetName); - lateIsSetSetterReference = - indexedContainer!.lookupSetterReference(lateIsSetName); - lateGetterReference = indexedContainer!.lookupGetterReference( - nameScheme - .getFieldMemberName(FieldNameType.Getter, name, - isSynthesized: fieldIsLateWithLowering) - .name); - lateSetterReference = indexedContainer!.lookupSetterReference( - nameScheme - .getFieldMemberName(FieldNameType.Setter, name, - isSynthesized: fieldIsLateWithLowering) - .name); - } - } - SourceFieldBuilder fieldBuilder = new SourceFieldBuilder( - metadata: fragment.metadata, - type: fragment.type, - name: name, - modifiers: fragment.modifiers, - isTopLevel: fragment.isTopLevel, - isPrimaryConstructorField: fragment.isPrimaryConstructorField, - libraryBuilder: enclosingLibraryBuilder, - declarationBuilder: declarationBuilder, - fileUri: fragment.fileUri, - nameOffset: fragment.nameOffset, - endOffset: fragment.endOffset, - nameScheme: nameScheme, - fieldReference: fieldReference, - fieldGetterReference: fieldGetterReference, - fieldSetterReference: fieldSetterReference, - lateIsSetFieldReference: lateIsSetFieldReference, - lateIsSetGetterReference: lateIsSetGetterReference, - lateIsSetSetterReference: lateIsSetSetterReference, - lateGetterReference: lateGetterReference, - lateSetterReference: lateSetterReference, - initializerToken: fragment.initializerToken, - constInitializerToken: fragment.constInitializerToken); - fragment.builder = fieldBuilder; - builders.add(new _AddBuilder(fragment.name, fieldBuilder, + SourcePropertyBuilder propertyBuilder = + new SourcePropertyBuilder.forField( + fileUri: fragment.fileUri, + fileOffset: fragment.nameOffset, + name: name, + libraryBuilder: enclosingLibraryBuilder, + declarationBuilder: declarationBuilder, + isStatic: fragment.modifiers.isStatic, + nameScheme: nameScheme, + fragment: fragment, + references: references); + fragment.builder = propertyBuilder; + builders.add(new _AddBuilder(fragment.name, propertyBuilder, fragment.fileUri, fragment.nameOffset)); - if (fieldGetterReference != null) { - loader.buildersCreatedWithReferences[fieldGetterReference] = - fieldBuilder; - } - if (fieldSetterReference != null) { - loader.buildersCreatedWithReferences[fieldSetterReference] = - fieldBuilder; - } + references.registerReference(loader, propertyBuilder); case GetterFragment(): String name = fragment.name; final bool isInstanceMember = containerType != ContainerType.Library && @@ -1604,7 +1519,7 @@ void _computeBuildersFromFragments(String name, List fragments, List? typeParameters, List? formals ) = _createTypeParametersAndFormals( - declarationBuilder, null, null, unboundNominalParameters, + declarationBuilder, unboundNominalParameters, isInstanceMember: isInstanceMember, fileUri: fragment.fileUri, nameOffset: fragment.nameOffset); @@ -1621,19 +1536,15 @@ void _computeBuildersFromFragments(String name, List fragments, ? new LibraryName(indexedLibrary.library.reference) : enclosingLibraryBuilder.libraryName); - Reference? procedureReference; indexedContainer ??= indexedLibrary; bool isAugmentation = enclosingLibraryBuilder.isAugmenting && fragment.modifiers.isAugment; - ProcedureKind kind = ProcedureKind.Getter; - if (indexedContainer != null && !isAugmentation) { - Name nameToLookup = - nameScheme.getProcedureMemberName(kind, name).name; - procedureReference = - indexedContainer!.lookupGetterReference(nameToLookup); - } + GetterReference references = new GetterReference( + name, nameScheme, indexedContainer, + isAugmentation: isAugmentation); + SourcePropertyBuilder propertyBuilder = new SourcePropertyBuilder.forGetter( fileUri: fragment.fileUri, @@ -1644,14 +1555,11 @@ void _computeBuildersFromFragments(String name, List fragments, isStatic: fragment.modifiers.isStatic, fragment: fragment, nameScheme: nameScheme, - getterReference: procedureReference); + references: references); fragment.setBuilder(propertyBuilder, typeParameters, formals); builders.add(new _AddBuilder(fragment.name, propertyBuilder, fragment.fileUri, fragment.nameOffset)); - if (procedureReference != null) { - loader.buildersCreatedWithReferences[procedureReference] = - propertyBuilder; - } + references.registerReference(loader, propertyBuilder); case SetterFragment(): String name = fragment.name; final bool isInstanceMember = containerType != ContainerType.Library && @@ -1661,7 +1569,7 @@ void _computeBuildersFromFragments(String name, List fragments, List? typeParameters, List? formals ) = _createTypeParametersAndFormals( - declarationBuilder, null, null, unboundNominalParameters, + declarationBuilder, unboundNominalParameters, isInstanceMember: isInstanceMember, fileUri: fragment.fileUri, nameOffset: fragment.nameOffset); @@ -1670,10 +1578,6 @@ void _computeBuildersFromFragments(String name, List fragments, problemReporting, typeParameters, ownerName: name, allowNameConflict: true); - final bool isExtensionMember = containerType == ContainerType.Extension; - final bool isExtensionTypeMember = - containerType == ContainerType.ExtensionType; - NameScheme nameScheme = new NameScheme( containerName: containerName, containerType: containerType, @@ -1682,26 +1586,15 @@ void _computeBuildersFromFragments(String name, List fragments, ? new LibraryName(indexedLibrary.library.reference) : enclosingLibraryBuilder.libraryName); - Reference? procedureReference; indexedContainer ??= indexedLibrary; bool isAugmentation = enclosingLibraryBuilder.isAugmenting && fragment.modifiers.isAugment; - ProcedureKind kind = ProcedureKind.Setter; - if (indexedContainer != null && !isAugmentation) { - Name nameToLookup = - nameScheme.getProcedureMemberName(kind, name).name; - if ((isExtensionMember || isExtensionTypeMember) && - isInstanceMember) { - // Extension (type) instance setters are encoded as methods. - procedureReference = - indexedContainer!.lookupGetterReference(nameToLookup); - } else { - procedureReference = - indexedContainer!.lookupSetterReference(nameToLookup); - } - } + SetterReference references = new SetterReference( + name, nameScheme, indexedContainer, + isAugmentation: isAugmentation); + SourcePropertyBuilder propertyBuilder = new SourcePropertyBuilder.forSetter( fileUri: fragment.fileUri, @@ -1712,14 +1605,11 @@ void _computeBuildersFromFragments(String name, List fragments, isStatic: fragment.modifiers.isStatic, fragment: fragment, nameScheme: nameScheme, - setterReference: procedureReference); + references: references); fragment.setBuilder(propertyBuilder, typeParameters, formals); builders.add(new _AddBuilder(fragment.name, propertyBuilder, fragment.fileUri, fragment.nameOffset)); - if (procedureReference != null) { - loader.buildersCreatedWithReferences[procedureReference] = - propertyBuilder; - } + references.registerReference(loader, propertyBuilder); if (conflictingSetter) { propertyBuilder.isConflictingSetter = true; } @@ -1732,7 +1622,7 @@ void _computeBuildersFromFragments(String name, List fragments, List? typeParameters, List? formals ) = _createTypeParametersAndFormals( - declarationBuilder, null, null, unboundNominalParameters, + declarationBuilder, unboundNominalParameters, isInstanceMember: isInstanceMember, fileUri: fragment.fileUri, nameOffset: fragment.nameOffset); @@ -2605,14 +2495,13 @@ bool isDuplicatedDeclaration(Builder? existing, Builder other) { ( List? typeParameters, List? formals -) _createTypeParametersAndFormals( - DeclarationBuilder? declarationBuilder, - List? typeParameters, - List? formals, +) _createTypeParametersAndFormals(DeclarationBuilder? declarationBuilder, List _unboundNominalVariables, {required bool isInstanceMember, required Uri fileUri, required int nameOffset}) { + List? typeParameters; + List? formals; if (isInstanceMember) { switch (declarationBuilder) { case ExtensionBuilder(): @@ -2624,13 +2513,7 @@ bool isDuplicatedDeclaration(Builder? existing, Builder other) { InstanceTypeParameterAccessState.Allowed); if (nominalVariableCopy != null) { - if (typeParameters != null) { - // Coverage-ignore-block(suite): Not run. - typeParameters = nominalVariableCopy.newParameterBuilders - ..addAll(typeParameters); - } else { - typeParameters = nominalVariableCopy.newParameterBuilders; - } + typeParameters = nominalVariableCopy.newParameterBuilders; } TypeBuilder thisType = declarationBuilder.onType; @@ -2647,10 +2530,6 @@ bool isDuplicatedDeclaration(Builder? existing, Builder other) { isExtensionThis: true, hasImmediatelyDeclaredInitializer: false) ]; - if (formals != null) { - // Coverage-ignore-block(suite): Not run. - synthesizedFormals.addAll(formals); - } formals = synthesizedFormals; case ExtensionTypeDeclarationBuilder(): NominalParameterCopy? nominalVariableCopy = @@ -2661,13 +2540,7 @@ bool isDuplicatedDeclaration(Builder? existing, Builder other) { InstanceTypeParameterAccessState.Allowed); if (nominalVariableCopy != null) { - if (typeParameters != null) { - // Coverage-ignore-block(suite): Not run. - typeParameters = nominalVariableCopy.newParameterBuilders - ..addAll(typeParameters); - } else { - typeParameters = nominalVariableCopy.newParameterBuilders; - } + typeParameters = nominalVariableCopy.newParameterBuilders; } TypeBuilder thisType = @@ -2699,10 +2572,6 @@ bool isDuplicatedDeclaration(Builder? existing, Builder other) { isExtensionThis: true, hasImmediatelyDeclaredInitializer: false) ]; - if (formals != null) { - // Coverage-ignore-block(suite): Not run. - synthesizedFormals.addAll(formals); - } formals = synthesizedFormals; case ClassFragment(): case MixinFragment(): diff --git a/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart b/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart index 2927dddb92c1..6c87506cd357 100644 --- a/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart +++ b/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart @@ -38,7 +38,6 @@ import '../kernel/internal_ast.dart'; import '../kernel/kernel_helper.dart'; import '../kernel/type_algorithms.dart' show hasAnyTypeParameters; import '../source/source_constructor_builder.dart'; -import '../source/source_field_builder.dart'; import '../source/source_library_builder.dart' show FieldNonPromotabilityInfo, SourceLibraryBuilder; import '../source/source_member_builder.dart'; @@ -4416,16 +4415,16 @@ class _WhyNotPromotedVisitor // libraries, so just don't generate a context message. return const []; } - FieldNameNonPromotabilityInfo? fieldNameInfo = fieldNonPromotabilityInfo.fieldNameInfo[reason.propertyName]; List messages = []; if (fieldNameInfo != null) { - for (SourceFieldBuilder field in fieldNameInfo.conflictingFields) { + for (SourceMemberBuilder field in fieldNameInfo.conflictingFields) { messages.add(templateFieldNotPromotedBecauseConflictingField .withArguments( reason.propertyName, - field.readTarget.enclosingClass!.name, + field.readTarget!.enclosingClass!.name, NonPromotionDocumentationLink.conflictingNonPromotableField.url) .withLocation(field.fileUri, field.fileOffset, noLength)); } @@ -4435,7 +4434,7 @@ class _WhyNotPromotedVisitor reason.propertyName, getter.readTarget!.enclosingClass!.name, NonPromotionDocumentationLink.conflictingGetter.url) - .withLocation(getter.fileUri!, getter.fileOffset, noLength)); + .withLocation(getter.fileUri, getter.fileOffset, noLength)); } for (Class nsmClass in fieldNameInfo.conflictingNsmClasses) { messages.add(templateFieldNotPromotedBecauseConflictingNsmForwarder diff --git a/pkg/front_end/test/coverage_suite_expected.dart b/pkg/front_end/test/coverage_suite_expected.dart index aea19d973fd4..6f7e1234f7c9 100644 --- a/pkg/front_end/test/coverage_suite_expected.dart +++ b/pkg/front_end/test/coverage_suite_expected.dart @@ -208,9 +208,9 @@ const Map _expect = { hitCount: 260, missCount: 0, ), - // 99.38931297709924%. + // 99.38837920489296%. "package:front_end/src/base/scope.dart": ( - hitCount: 651, + hitCount: 650, missCount: 4, ), // 100.0%. @@ -245,7 +245,7 @@ const Map _expect = { ), // 100.0%. "package:front_end/src/builder/builder_mixins.dart": ( - hitCount: 44, + hitCount: 45, missCount: 0, ), // 100.0%. @@ -290,7 +290,7 @@ const Map _expect = { ), // 100.0%. "package:front_end/src/builder/formal_parameter_builder.dart": ( - hitCount: 169, + hitCount: 170, missCount: 0, ), // 100.0%. @@ -325,7 +325,7 @@ const Map _expect = { ), // 100.0%. "package:front_end/src/builder/member_builder.dart": ( - hitCount: 97, + hitCount: 89, missCount: 0, ), // 100.0%. @@ -505,12 +505,27 @@ const Map _expect = { ), // 100.0%. "package:front_end/src/fragment/field.dart": ( - hitCount: 22, + hitCount: 300, + missCount: 0, + ), + // 100.0%. + "package:front_end/src/fragment/field/body_builder_context.dart": ( + hitCount: 30, + missCount: 0, + ), + // 100.0%. + "package:front_end/src/fragment/field/class_member.dart": ( + hitCount: 157, + missCount: 0, + ), + // 100.0%. + "package:front_end/src/fragment/field/encoding.dart": ( + hitCount: 995, missCount: 0, ), // 100.0%. "package:front_end/src/fragment/getter.dart": ( - hitCount: 533, + hitCount: 541, missCount: 0, ), // 100.0%. @@ -535,7 +550,7 @@ const Map _expect = { ), // 100.0%. "package:front_end/src/fragment/setter.dart": ( - hitCount: 553, + hitCount: 561, missCount: 0, ), // 100.0%. @@ -560,12 +575,12 @@ const Map _expect = { ), // 100.0%. "package:front_end/src/kernel/body_builder.dart": ( - hitCount: 7180, + hitCount: 7182, missCount: 0, ), // 100.0%. "package:front_end/src/kernel/body_builder_context.dart": ( - hitCount: 343, + hitCount: 324, missCount: 0, ), // 100.0%. @@ -620,7 +635,7 @@ const Map _expect = { ), // 100.0%. "package:front_end/src/kernel/expression_generator.dart": ( - hitCount: 2519, + hitCount: 2522, missCount: 0, ), // 100.0%. @@ -640,7 +655,7 @@ const Map _expect = { ), // 100.0%. "package:front_end/src/kernel/hierarchy/class_member.dart": ( - hitCount: 386, + hitCount: 389, missCount: 0, ), // 100.0%. @@ -680,7 +695,7 @@ const Map _expect = { ), // 100.0%. "package:front_end/src/kernel/implicit_field_type.dart": ( - hitCount: 93, + hitCount: 97, missCount: 0, ), // 100.0%. @@ -710,7 +725,7 @@ const Map _expect = { ), // 100.0%. "package:front_end/src/kernel/kernel_target.dart": ( - hitCount: 1078, + hitCount: 1076, missCount: 0, ), // 100.0%. @@ -850,7 +865,7 @@ const Map _expect = { ), // 100.0%. "package:front_end/src/source/diet_listener.dart": ( - hitCount: 659, + hitCount: 660, missCount: 0, ), // 100.0%. @@ -865,7 +880,7 @@ const Map _expect = { ), // 100.0%. "package:front_end/src/source/offset_map.dart": ( - hitCount: 151, + hitCount: 150, missCount: 0, ), // 100.0%. @@ -890,7 +905,7 @@ const Map _expect = { ), // 100.0%. "package:front_end/src/source/source_class_builder.dart": ( - hitCount: 1282, + hitCount: 1276, missCount: 0, ), // 100.0%. @@ -916,7 +931,7 @@ const Map _expect = { // 100.0%. "package:front_end/src/source/source_extension_type_declaration_builder.dart": ( - hitCount: 508, + hitCount: 504, missCount: 0, ), // 100.0%. @@ -926,7 +941,7 @@ const Map _expect = { ), // 100.0%. "package:front_end/src/source/source_field_builder.dart": ( - hitCount: 1269, + hitCount: 268, missCount: 0, ), // 100.0%. @@ -936,7 +951,7 @@ const Map _expect = { ), // 100.0%. "package:front_end/src/source/source_library_builder.dart": ( - hitCount: 1265, + hitCount: 1254, missCount: 0, ), // 100.0%. @@ -956,7 +971,7 @@ const Map _expect = { ), // 100.0%. "package:front_end/src/source/source_property_builder.dart": ( - hitCount: 540, + hitCount: 769, missCount: 0, ), // 100.0%. @@ -976,7 +991,7 @@ const Map _expect = { ), // 100.0%. "package:front_end/src/source/type_parameter_scope_builder.dart": ( - hitCount: 1533, + hitCount: 1489, missCount: 0, ), // 100.0%. diff --git a/pkg/front_end/test/macros/application/macro_application_test.dart b/pkg/front_end/test/macros/application/macro_application_test.dart index 4c297b94f7da..16dd38ab1b64 100644 --- a/pkg/front_end/test/macros/application/macro_application_test.dart +++ b/pkg/front_end/test/macros/application/macro_application_test.dart @@ -11,6 +11,7 @@ import 'package:front_end/src/api_prototype/compiler_options.dart'; import 'package:front_end/src/api_prototype/experimental_flags.dart'; import 'package:front_end/src/builder/field_builder.dart'; import 'package:front_end/src/builder/member_builder.dart'; +import 'package:front_end/src/builder/property_builder.dart'; import 'package:front_end/src/kernel/macro/macro.dart'; import 'package:front_end/src/kernel/macro/offset_checker.dart'; import 'package:front_end/src/macros/macro_serializer.dart'; @@ -125,6 +126,9 @@ bool _isMember(MemberBuilder memberBuilder, Member member) { if (memberBuilder is FieldBuilder) { // Only show annotations for the field or getter. return memberBuilder.readTarget == member; + } else if (memberBuilder is PropertyBuilder && memberBuilder.isField) { + // Only show annotations for the field or getter. + return memberBuilder.readTarget == member; } else if (member is Procedure && member.isSetter) { return memberBuilder.writeTarget == member; } else if (member is Procedure && member.isGetter) { diff --git a/pkg/front_end/test/testing/suite.dart b/pkg/front_end/test/testing/suite.dart index 861e58c1decd..891f3f093548 100644 --- a/pkg/front_end/test/testing/suite.dart +++ b/pkg/front_end/test/testing/suite.dart @@ -1128,7 +1128,8 @@ class FuzzCompiles a.libraries[i], b.libraries[i], strategy: const Strategy()); if (!result.isEquivalent) { - print(result.toString()); + print('Original component and new component are not equivalent:\n' + '$result'); return false; } }