| // 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 PrimaryConstructorFieldDeclaration |
| with FieldDeclarationMixin, FieldFragmentDeclarationMixin |
| implements |
| FieldDeclaration, |
| FieldFragmentDeclaration, |
| GetterDeclaration, |
| SetterDeclaration, |
| Inferable, |
| InferredTypeListener { |
| final PrimaryConstructorFieldFragment _fragment; |
| |
| late final FieldEncoding _encoding; |
| |
| @override |
| bool hasBodyBeenBuilt = false; |
| |
| new(this._fragment) { |
| _fragment.declaration = this; |
| } |
| |
| @override |
| SourcePropertyBuilder get builder => _fragment.builder; |
| |
| @override |
| FieldQuality get fieldQuality => FieldQuality.Concrete; |
| |
| @override |
| DartType get fieldType => _encoding.type; |
| |
| @override |
| // Coverage-ignore(suite): Not run. |
| DartType get fieldTypeInternal => _encoding.type; |
| |
| @override |
| void set fieldTypeInternal(DartType value) { |
| _encoding.type = value; |
| } |
| |
| @override |
| Uri get fileUri => _fragment.fileUri; |
| |
| @override |
| GetterQuality get getterQuality => GetterQuality.Implicit; |
| |
| @override |
| bool get hasInitializer => false; |
| |
| @override |
| bool get hasSetter => _fragment.hasSetter; |
| |
| @override |
| // Coverage-ignore(suite): Not run. |
| shared.Expression? get initializerExpression => null; |
| |
| @override |
| bool get isConst => false; |
| |
| @override |
| // Coverage-ignore(suite): Not run. |
| bool get isEnumElement => false; |
| |
| @override |
| bool get isInvalidField => false; |
| |
| @override |
| bool get isFinal => _fragment.modifiers.isFinal; |
| |
| @override |
| bool get isLate => false; |
| |
| @override |
| bool get isStatic => false; |
| |
| @override |
| List<ClassMember> get localMembers => _encoding.localMembers; |
| |
| @override |
| List<ClassMember> get localSetters => _encoding.localSetters; |
| |
| @override |
| // Coverage-ignore(suite): Not run. |
| List<MetadataBuilder>? get metadata => _fragment.metadata; |
| |
| @override |
| int get nameOffset => _fragment.nameOffset; |
| |
| @override |
| Member get readTarget => _encoding.readTarget; |
| |
| @override |
| SetterQuality get setterQuality => |
| !hasSetter ? SetterQuality.Absent : SetterQuality.Implicit; |
| |
| @override |
| TypeBuilder get type => _fragment.type; |
| |
| @override |
| // Coverage-ignore(suite): Not run. |
| UriOffsetLength get uriOffset => _fragment.uriOffset; |
| |
| @override |
| Member? get writeTarget => _encoding.writeTarget; |
| |
| @override |
| // Coverage-ignore(suite): Not run. |
| void buildBody( |
| CoreTypes coreTypes, |
| Expression? initializer, { |
| required ScopeProviderInfo? scopeProviderInfo, |
| }) { |
| assert(!hasBodyBeenBuilt, "Body has already been built for $this."); |
| hasBodyBeenBuilt = true; |
| _encoding.createBodies( |
| coreTypes, |
| initializer, |
| scopeProviderInfo: scopeProviderInfo, |
| ); |
| } |
| |
| @override |
| void buildFieldOutlineExpressions({ |
| required ClassHierarchy classHierarchy, |
| required SourceLibraryBuilder libraryBuilder, |
| required DeclarationBuilder? declarationBuilder, |
| required List<Annotatable> annotatables, |
| required Uri annotatablesFileUri, |
| required bool forConstantConstructor, |
| }) { |
| BodyBuilderContext bodyBuilderContext = createBodyBuilderContext(); |
| for (Annotatable annotatable in annotatables) { |
| buildMetadataForOutlineExpressions( |
| libraryBuilder: libraryBuilder, |
| extensionScope: _fragment.enclosingCompilationUnit.extensionScope, |
| scope: _fragment.enclosingScope, |
| bodyBuilderContext: bodyBuilderContext, |
| annotatable: annotatable, |
| annotatableFileUri: annotatablesFileUri, |
| metadata: _fragment.metadata, |
| annotationsFileUri: _fragment.fileUri, |
| ); |
| } |
| } |
| |
| @override |
| void buildFieldOutlineNode( |
| SourceLibraryBuilder libraryBuilder, |
| NameScheme nameScheme, |
| BuildNodesCallback f, |
| PropertyReferences references, { |
| required List<TypeParameter>? classTypeParameters, |
| }) { |
| _encoding.buildOutlineNode( |
| libraryBuilder, |
| nameScheme, |
| references, |
| isAbstractOrExternal: false, |
| classTypeParameters: classTypeParameters, |
| ); |
| if (type is! InferableTypeBuilder) { |
| fieldType = type.build(libraryBuilder, TypeUse.fieldType); |
| } |
| _encoding.registerMembers(f); |
| } |
| |
| @override |
| void buildGetterOutlineExpressions({ |
| required ClassHierarchy classHierarchy, |
| required SourceLibraryBuilder libraryBuilder, |
| required DeclarationBuilder? declarationBuilder, |
| required SourcePropertyBuilder propertyBuilder, |
| required Annotatable annotatable, |
| required Uri annotatableFileUri, |
| }) {} |
| |
| @override |
| void buildGetterOutlineNode({ |
| required SourceLibraryBuilder libraryBuilder, |
| required NameScheme nameScheme, |
| required BuildNodesCallback f, |
| required PropertyReferences? references, |
| required List<TypeParameter>? classTypeParameters, |
| }) {} |
| |
| @override |
| // Coverage-ignore(suite): Not run. |
| void buildImplicitDefaultValue() { |
| _encoding.buildImplicitDefaultValue(); |
| } |
| |
| @override |
| Initializer buildImplicitInitializer() { |
| return _encoding.buildImplicitInitializer(); |
| } |
| |
| @override |
| List<InternalInitializer> buildInitializer( |
| int fileOffset, |
| Expression value, { |
| required bool isSynthetic, |
| }) { |
| return _encoding.createInitializer( |
| fileOffset, |
| value, |
| isSynthetic: isSynthetic, |
| ); |
| } |
| |
| @override |
| void buildSetterOutlineExpressions({ |
| required ClassHierarchy classHierarchy, |
| required SourceLibraryBuilder libraryBuilder, |
| required DeclarationBuilder? declarationBuilder, |
| required SourcePropertyBuilder propertyBuilder, |
| required Annotatable annotatable, |
| required Uri annotatableFileUri, |
| }) {} |
| |
| @override |
| void buildSetterOutlineNode({ |
| required SourceLibraryBuilder libraryBuilder, |
| required ProblemReporting problemReporting, |
| required NameScheme nameScheme, |
| required BuildNodesCallback f, |
| required PropertyReferences? references, |
| required List<TypeParameter>? classTypeParameters, |
| }) {} |
| |
| @override |
| void checkFieldTypes( |
| ProblemReporting problemReporting, |
| TypeEnvironment typeEnvironment, |
| SourcePropertyBuilder? setterBuilder, |
| ) { |
| problemReporting.checkTypesInField( |
| typeEnvironment: typeEnvironment, |
| isInstanceMember: builder.isDeclarationInstanceMember, |
| isLate: isLate, |
| isExternal: false, |
| hasInitializer: hasInitializer, |
| fieldType: fieldType, |
| name: _fragment.name, |
| nameLength: _fragment.name.length, |
| nameOffset: nameOffset, |
| fileUri: fileUri, |
| ); |
| } |
| |
| @override |
| void checkFieldVariance( |
| SourceClassBuilder sourceClassBuilder, |
| TypeEnvironment typeEnvironment, |
| ) { |
| sourceClassBuilder.checkVarianceInField( |
| typeEnvironment, |
| fieldType: fieldType, |
| isInstanceMember: !isStatic, |
| hasSetter: hasSetter, |
| isCovariantByDeclaration: false, |
| fileUri: fileUri, |
| fileOffset: nameOffset, |
| ); |
| } |
| |
| @override |
| void checkGetterTypes( |
| ProblemReporting problemReporting, |
| LibraryFeatures libraryFeatures, |
| TypeEnvironment typeEnvironment, |
| SourcePropertyBuilder? setterBuilder, |
| ) {} |
| |
| @override |
| void checkGetterVariance( |
| SourceClassBuilder sourceClassBuilder, |
| TypeEnvironment typeEnvironment, |
| ) {} |
| |
| @override |
| void checkSetterTypes( |
| ProblemReporting problemReporting, |
| TypeEnvironment typeEnvironment, |
| ) {} |
| |
| @override |
| void checkSetterVariance( |
| SourceClassBuilder sourceClassBuilder, |
| TypeEnvironment typeEnvironment, |
| ) {} |
| |
| @override |
| int computeFieldDefaultTypes(ComputeDefaultTypeContext context) { |
| if (type is! OmittedTypeBuilder) { |
| context.reportInboundReferenceIssuesForType(type); |
| context.recursivelyReportGenericFunctionTypesAsBoundsForType(type); |
| } |
| return 0; |
| } |
| |
| @override |
| int computeGetterDefaultTypes(ComputeDefaultTypeContext context) { |
| return 0; |
| } |
| |
| @override |
| int computeSetterDefaultTypes(ComputeDefaultTypeContext context) { |
| return 0; |
| } |
| |
| @override |
| BodyBuilderContext createBodyBuilderContext() { |
| return new FieldFragmentBodyBuilderContext( |
| builder, |
| this, |
| isLateField: false, |
| isAbstractField: false, |
| isExternalField: false, |
| nameOffset: _fragment.nameOffset, |
| nameLength: _fragment.name.length, |
| isConst: false, |
| ); |
| } |
| |
| @override |
| void createFieldEncoding(SourcePropertyBuilder builder) { |
| _fragment.builder = builder; |
| |
| SourceLibraryBuilder libraryBuilder = builder.libraryBuilder; |
| |
| bool isExtensionTypeMember = builder.isExtensionTypeMember; |
| |
| if (isExtensionTypeMember) { |
| _encoding = new RepresentationFieldEncoding(_fragment); |
| } else { |
| _encoding = new PrimaryConstructorFieldEncoding(_fragment); |
| } |
| |
| Token? defaultValueToken = _fragment.takeDefaultValueToken(); |
| type.registerInferredTypeListener(this); |
| if (type is InferableTypeBuilder) { |
| // 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( |
| libraryBuilder: libraryBuilder, |
| typeBuilder: type, |
| inferType: inferType, |
| computeType: _computeInferredType, |
| fileUri: fileUri, |
| name: _fragment.name, |
| nameOffset: nameOffset, |
| nameLength: _fragment.name.length, |
| token: defaultValueToken, |
| ); |
| type.registerInferable(this); |
| } |
| } |
| |
| @override |
| void createGetterEncoding( |
| ProblemReporting problemReporting, |
| SourcePropertyBuilder builder, |
| PropertyEncodingStrategy encodingStrategy, |
| TypeParameterFactory typeParameterFactory, |
| ) {} |
| |
| @override |
| void createSetterEncoding( |
| ProblemReporting problemReporting, |
| SourcePropertyBuilder builder, |
| PropertyEncodingStrategy encodingStrategy, |
| TypeParameterFactory typeParameterFactory, |
| ) {} |
| |
| @override |
| void ensureGetterTypes({ |
| required SourceLibraryBuilder libraryBuilder, |
| required DeclarationBuilder? declarationBuilder, |
| required ClassMembersBuilder membersBuilder, |
| required Set<ClassMember>? getterOverrideDependencies, |
| }) {} |
| |
| @override |
| void ensureSetterTypes({ |
| required SourceLibraryBuilder libraryBuilder, |
| required DeclarationBuilder? declarationBuilder, |
| required ClassMembersBuilder membersBuilder, |
| required Set<ClassMember>? setterOverrideDependencies, |
| }) {} |
| |
| @override |
| void ensureTypes( |
| ClassMembersBuilder membersBuilder, |
| Set<ClassMember>? getterOverrideDependencies, |
| Set<ClassMember>? setterOverrideDependencies, |
| ) { |
| if (getterOverrideDependencies != null || |
| setterOverrideDependencies != null) { |
| SourceClassBuilder classBuilder = |
| builder.declarationBuilder as SourceClassBuilder; |
| membersBuilder.inferFieldType( |
| classBuilder, |
| type, |
| [...?getterOverrideDependencies, ...?setterOverrideDependencies], |
| name: _fragment.name, |
| fileUri: fileUri, |
| nameOffset: nameOffset, |
| nameLength: _fragment.name.length, |
| isAssignable: hasSetter, |
| ); |
| } else { |
| // Coverage-ignore-block(suite): Not run. |
| type.build( |
| builder.libraryBuilder, |
| TypeUse.fieldType, |
| hierarchy: membersBuilder.hierarchyBuilder, |
| ); |
| } |
| } |
| |
| @override |
| // Coverage-ignore(suite): Not run. |
| Iterable<Reference> getExportedGetterReferences( |
| PropertyReferences references, |
| ) { |
| return [references.getterReference]; |
| } |
| |
| @override |
| // Coverage-ignore(suite): Not run. |
| Iterable<Reference> getExportedSetterReferences( |
| PropertyReferences references, |
| ) { |
| return hasSetter ? [references.setterReference] : const []; |
| } |
| |
| @override |
| // Coverage-ignore(suite): Not run. |
| void registerSuperCall() { |
| _encoding.registerSuperCall(); |
| } |
| |
| @override |
| void setCovariantByClassInternal() { |
| _encoding.setCovariantByClass(); |
| } |
| |
| (DartType, Expression?, ScopeProviderInfo?) _computeInferredType( |
| ClassHierarchyBase classHierarchy, |
| Token? token, |
| ) { |
| SourceLibraryBuilder libraryBuilder = builder.libraryBuilder; |
| if (token != null) { |
| LookupScope scope = _fragment.enclosingScope; |
| InferredFieldInitializer inferredFieldInitializer = libraryBuilder.loader |
| .createResolver() |
| .buildFieldInitializer( |
| libraryBuilder: libraryBuilder, |
| fileUri: fileUri, |
| extensionScope: _fragment.enclosingCompilationUnit.extensionScope, |
| scope: scope, |
| inferenceDataForTesting: builder |
| .dataForTesting |
| // Coverage-ignore(suite): Not run. |
| ?.inferenceData, |
| bodyBuilderContext: createBodyBuilderContext(), |
| startToken: token, |
| isLate: false, |
| inferenceDefaultType: inferenceDefaultType, |
| ); |
| return ( |
| inferredFieldInitializer.expressionInferenceResult.inferredType, |
| inferredFieldInitializer.expressionInferenceResult.expression, |
| inferredFieldInitializer.scopeProviderInfo, |
| ); |
| } else { |
| assert(inferenceDefaultType == InferenceDefaultType.NullableObject); |
| return (classHierarchy.coreTypes.objectNullableRawType, null, null); |
| } |
| } |
| |
| @override |
| InferenceDefaultType get inferenceDefaultType => |
| InferenceDefaultType.NullableObject; |
| |
| @override |
| Initializer takePrimaryConstructorFieldInitializer() { |
| throw new UnsupportedError( |
| '$runtimeType.takePrimaryConstructorFieldInitializer()', |
| ); |
| } |
| } |
| |
| class PrimaryConstructorFieldFragment implements Fragment { |
| @override |
| final String name; |
| |
| final Uri fileUri; |
| |
| final int nameOffset; |
| |
| final List<MetadataBuilder>? metadata; |
| |
| final Modifiers modifiers; |
| |
| final TypeBuilder type; |
| |
| final LookupScope enclosingScope; |
| |
| final DeclarationFragment enclosingDeclaration; |
| final LibraryFragment enclosingCompilationUnit; |
| |
| Token? _defaultValueToken; |
| |
| SourcePropertyBuilder? _builder; |
| PrimaryConstructorFieldDeclaration? _declaration; |
| |
| @override |
| late final UriOffsetLength uriOffset = new UriOffsetLength( |
| fileUri, |
| nameOffset, |
| name.length, |
| ); |
| |
| new({ |
| required this.name, |
| required this.fileUri, |
| required this.nameOffset, |
| required this.metadata, |
| required this.modifiers, |
| required this.type, |
| required this.enclosingScope, |
| required this.enclosingDeclaration, |
| required this.enclosingCompilationUnit, |
| required Token? defaultValueToken, |
| }) : _defaultValueToken = defaultValueToken; |
| |
| @override |
| SourcePropertyBuilder get builder { |
| assert(_builder != null, "Builder has not been computed for $this."); |
| return _builder!; |
| } |
| |
| void set builder(SourcePropertyBuilder value) { |
| assert(_builder == null, "Builder has already been computed for $this."); |
| _builder = value; |
| } |
| |
| // Coverage-ignore(suite): Not run. |
| PrimaryConstructorFieldDeclaration get declaration { |
| assert( |
| _declaration != null, |
| "Declaration has not been computed for $this.", |
| ); |
| return _declaration!; |
| } |
| |
| void set declaration(PrimaryConstructorFieldDeclaration value) { |
| assert( |
| _declaration == null, |
| "Declaration has already been computed for $this.", |
| ); |
| _declaration = value; |
| } |
| |
| bool get hasSetter => !modifiers.isFinal; |
| |
| /// Returns the [_defaultValueToken] field and clears it. |
| /// |
| /// This is used to transfer ownership of the token to the receiver. Tokens |
| /// need to be cleared during the outline phase to avoid holding the token |
| /// stream in memory. |
| Token? takeDefaultValueToken() { |
| Token? value = _defaultValueToken; |
| // Ensure that we don't hold on to the token. |
| _defaultValueToken = null; |
| return value; |
| } |
| } |