blob: 67acc768203a346bfef5ca5fb60fb7af43d98657 [file] [log] [blame]
// 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:_fe_analyzer_shared/src/metadata/expressions.dart' as shared;
import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' show Token;
import 'package:kernel/ast.dart';
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/core_types.dart';
import 'package:kernel/type_environment.dart';
import '../../base/constant_context.dart';
import '../../base/messages.dart';
import '../../base/problems.dart';
import '../../base/scope.dart';
import '../../base/uri_offset.dart';
import '../../builder/declaration_builders.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';
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/late_lowering.dart' as late_lowering;
import '../../kernel/macro/metadata.dart';
import '../../kernel/type_algorithms.dart';
import '../../source/name_scheme.dart';
import '../../source/source_class_builder.dart';
import '../../source/source_library_builder.dart';
import '../../source/source_member_builder.dart';
import '../../source/source_property_builder.dart';
import '../../source/type_parameter_factory.dart';
import '../../type_inference/inference_helper.dart';
import '../../type_inference/type_inference_engine.dart';
import '../../type_inference/type_inferrer.dart';
import '../fragment.dart';
import '../getter/declaration.dart';
import '../setter/declaration.dart';
/// Common interface for fragments that can declare a field.
abstract class FieldDeclaration {
UriOffsetLength? get uriOffset;
FieldQuality get fieldQuality;
/// The metadata declared on this fragment.
List<MetadataBuilder>? get metadata;
/// Builds the core AST structures for this field declaration as needed for
/// the outline.
void buildFieldOutlineNode(
SourceLibraryBuilder libraryBuilder,
NameScheme nameScheme,
BuildNodesCallback f,
PropertyReferences references, {
required List<TypeParameter>? classTypeParameters,
});
void buildFieldOutlineExpressions({
required ClassHierarchy classHierarchy,
required SourceLibraryBuilder libraryBuilder,
required DeclarationBuilder? declarationBuilder,
required List<Annotatable> annotatables,
required Uri annotatablesFileUri,
required bool isClassInstanceMember,
});
int computeFieldDefaultTypes(ComputeDefaultTypeContext context);
void createFieldEncoding(SourcePropertyBuilder builder);
void checkFieldTypes(
SourceLibraryBuilder libraryBuilder,
TypeEnvironment typeEnvironment,
SourcePropertyBuilder? setterBuilder,
);
/// Checks the variance of type parameters [sourceClassBuilder] used in the
/// type of this field declaration.
void checkFieldVariance(
SourceClassBuilder sourceClassBuilder,
TypeEnvironment typeEnvironment,
);
/// Return `true` if the declaration introduces a setter.
bool get hasSetter;
/// Return `true` if the declaration has an initializer.
bool get hasInitializer;
/// Return `true` if the declaration is final.
bool get isFinal;
/// Return `true` if the declaration is late.
bool get isLate;
/// Return `true` if the declaration is in instance field declared in an
/// extension type.
bool get isExtensionTypeDeclaredInstanceField;
/// Returns `true` if this field is declared by an enum element.
bool get isEnumElement;
/// Returns `true` if the declaration is const.
bool get isConst;
/// The [DartType] of this field declaration.
abstract DartType fieldType;
/// Creates the [Initializer] for the invalid initialization of this field.
///
/// This is only used for instance fields.
Initializer buildErroneousInitializer(
Expression effect,
Expression value, {
required int fileOffset,
});
/// Creates the AST node for this field as the default initializer.
///
/// This is only used for instance fields.
void buildImplicitDefaultValue();
/// Creates the [Initializer] for the implicit initialization of this field
/// in a constructor.
///
/// This is only used for instance fields.
Initializer buildImplicitInitializer();
/// Builds the [Initializer]s for each field used to encode this field
/// using the [fileOffset] for the created nodes and [value] as the initial
/// field value.
///
/// This is only used for instance fields.
List<Initializer> buildInitializer(
int fileOffset,
Expression value, {
required bool isSynthetic,
});
/// Ensures that the type of this field declaration has been computed.
void ensureTypes(
ClassMembersBuilder membersBuilder,
Set<ClassMember>? getterOverrideDependencies,
Set<ClassMember>? setterOverrideDependencies,
);
/// Infers the type of this field declaration.
DartType inferType(ClassHierarchyBase hierarchy);
shared.Expression? get initializerExpression;
}
class RegularFieldDeclaration
with FieldDeclarationMixin
implements
FieldDeclaration,
FieldFragmentDeclaration,
GetterDeclaration,
SetterDeclaration,
Inferable,
InferredTypeListener {
final FieldFragment _fragment;
late final FieldEncoding _encoding;
shared.Expression? _initializerExpression;
/// 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;
RegularFieldDeclaration(this._fragment) {
_fragment.declaration = this;
}
@override
UriOffsetLength get uriOffset => _fragment.uriOffset;
@override
SourcePropertyBuilder get builder => _fragment.builder;
@override
FieldQuality get fieldQuality => _fragment.modifiers.isAbstract
? FieldQuality.Abstract
: _fragment.modifiers.isExternal
? FieldQuality.External
: FieldQuality.Concrete;
@override
DartType get fieldType => _encoding.type;
@override
Uri get fileUri => _fragment.fileUri;
@override
GetterQuality get getterQuality => _fragment.modifiers.isAbstract
? GetterQuality.ImplicitAbstract
: _fragment.modifiers.isExternal
? GetterQuality.ImplicitExternal
: GetterQuality.Implicit;
@override
bool get hasInitializer => _fragment.modifiers.hasInitializer;
@override
bool get hasSetter => _fragment.hasSetter;
@override
// Coverage-ignore(suite): Not run.
shared.Expression? get initializerExpression => _initializerExpression;
@override
bool get isConst => _fragment.modifiers.isConst;
@override
bool get isEnumElement => false;
@override
bool get isExtensionTypeDeclaredInstanceField =>
builder.isExtensionTypeInstanceMember;
@override
bool get isFinal => _fragment.modifiers.isFinal;
@override
bool get isLate => _fragment.modifiers.isLate;
@override
bool get isStatic =>
_fragment.modifiers.isStatic || builder.declarationBuilder == null;
@override
List<ClassMember> get localMembers => _encoding.localMembers;
@override
List<ClassMember> get localSetters => _encoding.localSetters;
@override
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
: _fragment.modifiers.isAbstract
? SetterQuality.ImplicitAbstract
: _fragment.modifiers.isExternal
? SetterQuality.ImplicitExternal
: SetterQuality.Implicit;
@override
TypeBuilder get type => _fragment.type;
@override
Member? get writeTarget => _encoding.writeTarget;
@override
// Coverage-ignore(suite): Not run.
DartType get fieldTypeInternal => _encoding.type;
@override
void set fieldTypeInternal(DartType value) {
_encoding.type = value;
}
/// 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 (!_fragment.modifiers.hasInitializer &&
initializer != null &&
initializer is! NullLiteral &&
// Coverage-ignore(suite): Not run.
!_fragment.modifiers.isConst &&
// Coverage-ignore(suite): Not run.
!_fragment.modifiers.isFinal) {
internalProblem(
codeInternalProblemAlreadyInitialized,
nameOffset,
fileUri,
);
}
_encoding.createBodies(coreTypes, initializer);
}
@override
Initializer buildErroneousInitializer(
Expression effect,
Expression value, {
required int fileOffset,
}) {
return _encoding.buildErroneousInitializer(
effect,
value,
fileOffset: fileOffset,
);
}
@override
void buildFieldInitializer(
InferenceHelper helper,
TypeInferrer typeInferrer,
CoreTypes coreTypes,
Expression? initializer,
) {
if (initializer != null) {
if (!hasBodyBeenBuilt) {
initializer = typeInferrer
.inferFieldInitializer(helper, fieldType, initializer)
.expression;
buildBody(coreTypes, initializer);
}
} else if (!hasBodyBeenBuilt) {
buildBody(coreTypes, null);
}
}
@override
void buildImplicitDefaultValue() {
_encoding.buildImplicitDefaultValue();
}
@override
Initializer buildImplicitInitializer() {
return _encoding.buildImplicitInitializer();
}
@override
List<Initializer> buildInitializer(
int fileOffset,
Expression value, {
required bool isSynthetic,
}) {
return _encoding.createInitializer(
fileOffset,
value,
isSynthetic: isSynthetic,
);
}
@override
void buildFieldOutlineExpressions({
required ClassHierarchy classHierarchy,
required SourceLibraryBuilder libraryBuilder,
required DeclarationBuilder? declarationBuilder,
required List<Annotatable> annotatables,
required Uri annotatablesFileUri,
required bool isClassInstanceMember,
}) {
BodyBuilderContext bodyBuilderContext = createBodyBuilderContext();
for (Annotatable annotatable in annotatables) {
buildMetadataForOutlineExpressions(
libraryBuilder: libraryBuilder,
scope: _fragment.enclosingScope,
bodyBuilderContext: bodyBuilderContext,
annotatable: annotatable,
annotatableFileUri: annotatablesFileUri,
metadata: metadata,
);
}
// 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.
Token? token = _fragment.constInitializerToken;
if ((_fragment.modifiers.isConst ||
(isFinal &&
isClassInstanceMember &&
(declarationBuilder as SourceClassBuilder)
.declaresConstConstructor)) &&
token != null) {
LookupScope scope = _fragment.enclosingScope;
BodyBuilder bodyBuilder = libraryBuilder.loader
.createBodyBuilderForOutlineExpression(
libraryBuilder,
createBodyBuilderContext(),
scope,
fileUri,
);
bodyBuilder.constantContext = _fragment.modifiers.isConst
? ConstantContext.inferred
: ConstantContext.required;
Expression initializer = bodyBuilder.typeInferrer
.inferFieldInitializer(
bodyBuilder,
fieldType,
bodyBuilder.parseFieldInitializer(token),
)
.expression;
buildBody(classHierarchy.coreTypes, initializer);
bodyBuilder.performBacklogComputations();
if (computeSharedExpressionForTesting) {
// Coverage-ignore-block(suite): Not run.
_initializerExpression = parseFieldInitializer(
libraryBuilder.loader,
token,
libraryBuilder.importUri,
fileUri,
scope,
);
}
}
}
@override
void buildFieldOutlineNode(
SourceLibraryBuilder libraryBuilder,
NameScheme nameScheme,
BuildNodesCallback f,
PropertyReferences references, {
required List<TypeParameter>? classTypeParameters,
}) {
_encoding.buildOutlineNode(
libraryBuilder,
nameScheme,
references,
isAbstractOrExternal:
_fragment.modifiers.isAbstract || _fragment.modifiers.isExternal,
classTypeParameters: classTypeParameters,
);
if (type is! InferableTypeBuilder) {
fieldType = type.build(libraryBuilder, TypeUse.fieldType);
}
_encoding.registerMembers(f);
}
@override
void checkFieldTypes(
SourceLibraryBuilder libraryBuilder,
TypeEnvironment typeEnvironment,
SourcePropertyBuilder? setterBuilder,
) {
libraryBuilder.checkTypesInField(
typeEnvironment,
isInstanceMember: builder.isDeclarationInstanceMember,
isLate: isLate,
isExternal: _fragment.modifiers.isExternal,
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: _fragment.modifiers.isCovariant,
fileUri: fileUri,
fileOffset: nameOffset,
);
}
@override
int computeFieldDefaultTypes(ComputeDefaultTypeContext context) {
if (type is! OmittedTypeBuilder) {
context.reportInboundReferenceIssuesForType(type);
context.recursivelyReportGenericFunctionTypesAsBoundsForType(type);
}
return 0;
}
@override
BodyBuilderContext createBodyBuilderContext() {
return new FieldFragmentBodyBuilderContext(
builder,
this,
isLateField: _fragment.modifiers.isLate,
isAbstractField: _fragment.modifiers.isAbstract,
isExternalField: _fragment.modifiers.isExternal,
nameOffset: _fragment.nameOffset,
nameLength: _fragment.name.length,
isConst: _fragment.modifiers.isConst,
);
}
@override
void createFieldEncoding(SourcePropertyBuilder builder) {
_fragment.builder = builder;
SourceLibraryBuilder libraryBuilder = builder.libraryBuilder;
bool isAbstract = _fragment.modifiers.isAbstract;
bool isExternal = _fragment.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(
_fragment,
isExtensionInstanceMember: isExtensionMember && isInstanceMember,
isExtensionTypeInstanceMember:
isExtensionTypeMember && isInstanceMember,
isAbstract: isAbstract,
isExternal: isExternal,
);
} else if (isExtensionTypeMember && isInstanceMember) {
// Field on a extension type. Encode as abstract.
// TODO(johnniwinther): Should we have an erroneous flag on such
// members?
_encoding = new AbstractOrExternalFieldEncoding(
_fragment,
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(
_fragment,
isSetStrategy: isSetStrategy,
);
} else {
_encoding = new LateFieldWithInitializerEncoding(
_fragment,
isSetStrategy: isSetStrategy,
);
}
} else {
if (isFinal) {
_encoding = new LateFinalFieldWithoutInitializerEncoding(
_fragment,
isSetStrategy: isSetStrategy,
);
} else {
_encoding = new LateFieldWithoutInitializerEncoding(
_fragment,
isSetStrategy: isSetStrategy,
);
}
}
} else if (libraryBuilder
.loader
.target
.backendTarget
.useStaticFieldLowering &&
!isInstanceMember &&
!_fragment.modifiers.isConst &&
hasInitializer) {
if (isFinal) {
_encoding = new LateFinalFieldWithInitializerEncoding(
_fragment,
isSetStrategy: isSetStrategy,
);
} else {
_encoding = new LateFieldWithInitializerEncoding(
_fragment,
isSetStrategy: isSetStrategy,
);
}
} else {
_encoding = new RegularFieldEncoding(_fragment, isEnumElement: false);
}
type.registerInferredTypeListener(this);
Token? token = _fragment.initializerToken;
if (type is InferableTypeBuilder) {
if (!_fragment.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(
libraryBuilder: libraryBuilder,
typeBuilder: type,
inferType: inferType,
computeType: _computeInferredType,
fileUri: fileUri,
name: _fragment.name,
nameOffset: nameOffset,
nameLength: _fragment.name.length,
token: token,
);
type.registerInferable(this);
}
}
}
@override
void ensureTypes(
ClassMembersBuilder membersBuilder,
Set<ClassMember>? getterOverrideDependencies,
Set<ClassMember>? setterOverrideDependencies,
) {
if (getterOverrideDependencies != null ||
setterOverrideDependencies != null) {
membersBuilder.inferFieldType(
builder.declarationBuilder as SourceClassBuilder,
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
void registerSuperCall() {
_encoding.registerSuperCall();
}
DartType _computeInferredType(
ClassHierarchyBase classHierarchy,
Token? token,
) {
DartType? inferredType;
SourceLibraryBuilder libraryBuilder = builder.libraryBuilder;
DeclarationBuilder? declarationBuilder = builder.declarationBuilder;
if (token != null) {
InterfaceType? enclosingClassThisType =
declarationBuilder is SourceClassBuilder
? libraryBuilder.loader.typeInferenceEngine.coreTypes
.thisInterfaceType(
declarationBuilder.cls,
libraryBuilder.library.nonNullable,
)
: null;
LookupScope scope = _fragment.enclosingScope;
TypeInferrer typeInferrer = libraryBuilder.loader.typeInferenceEngine
.createTopLevelTypeInferrer(
fileUri,
enclosingClassThisType,
libraryBuilder,
scope,
builder
.dataForTesting
// Coverage-ignore(suite): Not run.
?.inferenceData,
);
BodyBuilderContext bodyBuilderContext = createBodyBuilderContext();
BodyBuilder bodyBuilder = libraryBuilder.loader.createBodyBuilderForField(
libraryBuilder,
bodyBuilderContext,
scope,
typeInferrer,
fileUri,
);
bodyBuilder.constantContext = _fragment.modifiers.isConst
? ConstantContext.inferred
: ConstantContext.none;
bodyBuilder.inFieldInitializer = true;
bodyBuilder.inLateFieldInitializer = _fragment.modifiers.isLate;
Expression initializer = bodyBuilder.parseFieldInitializer(token);
inferredType = typeInferrer.inferImplicitFieldType(
bodyBuilder,
initializer,
);
} else {
inferredType = const DynamicType();
}
return inferredType;
}
@override
void setCovariantByClassInternal() {
_encoding.setCovariantByClass();
}
@override
void buildGetterOutlineExpressions({
required ClassHierarchy classHierarchy,
required SourceLibraryBuilder libraryBuilder,
required DeclarationBuilder? declarationBuilder,
required SourcePropertyBuilder propertyBuilder,
required Annotatable annotatable,
required Uri annotatableFileUri,
required bool isClassInstanceMember,
}) {}
@override
void buildGetterOutlineNode({
required SourceLibraryBuilder libraryBuilder,
required NameScheme nameScheme,
required BuildNodesCallback f,
required PropertyReferences? references,
required List<TypeParameter>? classTypeParameters,
}) {}
@override
void buildSetterOutlineExpressions({
required ClassHierarchy classHierarchy,
required SourceLibraryBuilder libraryBuilder,
required DeclarationBuilder? declarationBuilder,
required SourcePropertyBuilder propertyBuilder,
required Annotatable annotatable,
required Uri annotatableFileUri,
required bool isClassInstanceMember,
}) {}
@override
void buildSetterOutlineNode({
required SourceLibraryBuilder libraryBuilder,
required NameScheme nameScheme,
required BuildNodesCallback f,
required PropertyReferences? references,
required List<TypeParameter>? classTypeParameters,
}) {}
@override
void checkGetterTypes(
SourceLibraryBuilder libraryBuilder,
TypeEnvironment typeEnvironment,
SourcePropertyBuilder? setterBuilder,
) {}
@override
void checkGetterVariance(
SourceClassBuilder sourceClassBuilder,
TypeEnvironment typeEnvironment,
) {}
@override
void checkSetterTypes(
SourceLibraryBuilder libraryBuilder,
TypeEnvironment typeEnvironment,
) {}
@override
void checkSetterVariance(
SourceClassBuilder sourceClassBuilder,
TypeEnvironment typeEnvironment,
) {}
@override
int computeGetterDefaultTypes(ComputeDefaultTypeContext context) {
return 0;
}
@override
int computeSetterDefaultTypes(ComputeDefaultTypeContext context) {
return 0;
}
@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
Iterable<Reference> getExportedGetterReferences(
PropertyReferences references,
) {
return [references.getterReference];
}
@override
Iterable<Reference> getExportedSetterReferences(
PropertyReferences references,
) {
return hasSetter ? [references.setterReference] : const [];
}
}
mixin FieldDeclarationMixin
implements FieldDeclaration, Inferable, InferredTypeListener {
Uri get fileUri;
int get nameOffset;
SourcePropertyBuilder get builder;
@override
bool get isConst;
/// The [TypeBuilder] for the declared type of this field declaration.
TypeBuilder get type;
void setCovariantByClassInternal();
abstract DartType fieldTypeInternal;
@override
void onInferredType(DartType type) {
fieldType = type;
}
@override
void inferTypes(ClassHierarchyBase hierarchy) {
inferType(hierarchy);
}
@override
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)) {
setCovariantByClassInternal();
}
}
}
return fieldType;
},
);
}
@override
// Coverage-ignore(suite): Not run.
DartType get fieldType => fieldTypeInternal;
@override
void set fieldType(DartType value) {
fieldTypeInternal = value;
DeclarationBuilder? declarationBuilder = builder.declarationBuilder;
// TODO(johnniwinther): Should this be `hasSetter`?
if (!isFinal && !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)) {
setCovariantByClassInternal();
}
}
}
}
}
abstract class FieldFragmentDeclaration {
bool get isStatic;
void buildFieldInitializer(
InferenceHelper helper,
TypeInferrer typeInferrer,
CoreTypes coreTypes,
Expression? initializer,
);
BodyBuilderContext createBodyBuilderContext();
/// Registers that a `super` call has occurred in the initializer of this
/// field.
void registerSuperCall();
}