Files
sdk/pkg/front_end/lib/src/fragment/setter/declaration.dart
T
Johnni Winther e30cd0322c [cfe][Contexts] Split VariableDeclaration and VariableStatement
This separates VariableDeclaration from Statement. VariableDeclaration no longer implements Statement and variable declared in a block or in a for-statement are now wrapped by a VariableStatement.

Currently there are two VariableStatement implementations; LegacyVariableStatement for variables in the current model, called LegacyVariable, and VariableInitialization for variables used in the new, still experimental, encoding that supports scope computation.

This CL is a step towards realigning the AST nodes to the new model in which each kind of variable has its own distinct subclass. (LocalVariable, PositionalParameter, NamedParameter, SyntheticVariable, etc.)

Note that it is not the intent to use VariableStatement in ForStatement going forward but that will be handled in a follow-up.

TEST=existing.

Change-Id: I5b309cd62c9b138f95b74fb054686edffa49a393
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/502681
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Reviewed-by: Nicholas Shahan <nshahan@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
2026-05-18 05:49:28 -07:00

420 lines
12 KiB
Dart

// 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:front_end/src/codes/diagnostic.dart' as diag;
import 'package:kernel/ast.dart';
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/type_environment.dart';
import '../../base/compiler_context.dart';
import '../../base/local_scope.dart';
import '../../base/messages.dart';
import '../../base/scope.dart';
import '../../base/uri_offset.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 '../../kernel/body_builder_context.dart';
import '../../kernel/external_ast_helper.dart' as extern;
import '../../kernel/hierarchy/class_member.dart';
import '../../kernel/hierarchy/members_builder.dart';
import '../../kernel/type_algorithms.dart';
import '../../source/check_helper.dart';
import '../../source/name_scheme.dart';
import '../../source/source_class_builder.dart';
import '../../source/source_library_builder.dart';
import '../../source/source_loader.dart';
import '../../source/source_member_builder.dart';
import '../../source/source_property_builder.dart';
import '../../source/stack_listener_impl.dart' show AsyncModifier;
import '../../source/type_parameter_factory.dart';
import '../../type_inference/type_schema.dart';
import '../fragment.dart';
import 'body_builder_context.dart';
import 'encoding.dart';
/// Interface for a setter declaration aspect of a [SourcePropertyBuilder].
abstract class SetterDeclaration {
Uri get fileUri;
UriOffsetLength get uriOffset;
List<MetadataBuilder>? get metadata;
SetterQuality get setterQuality;
Member? get writeTarget;
void buildSetterOutlineExpressions({
required ClassHierarchy classHierarchy,
required SourceLibraryBuilder libraryBuilder,
required DeclarationBuilder? declarationBuilder,
required SourcePropertyBuilder propertyBuilder,
required Annotatable annotatable,
required Uri annotatableFileUri,
});
void buildSetterOutlineNode({
required SourceLibraryBuilder libraryBuilder,
required ProblemReporting problemReporting,
required NameScheme nameScheme,
required BuildNodesCallback f,
required PropertyReferences? references,
required List<TypeParameter>? classTypeParameters,
});
void checkSetterTypes(
ProblemReporting problemReporting,
TypeEnvironment typeEnvironment,
);
void checkSetterVariance(
SourceClassBuilder sourceClassBuilder,
TypeEnvironment typeEnvironment,
);
int computeSetterDefaultTypes(ComputeDefaultTypeContext context);
void createSetterEncoding(
ProblemReporting problemReporting,
SourcePropertyBuilder builder,
PropertyEncodingStrategy encodingStrategy,
TypeParameterFactory typeParameterFactory,
);
void ensureSetterTypes({
required SourceLibraryBuilder libraryBuilder,
required DeclarationBuilder? declarationBuilder,
required ClassMembersBuilder membersBuilder,
required Set<ClassMember>? setterOverrideDependencies,
});
Iterable<Reference> getExportedSetterReferences(
PropertyReferences references,
);
List<ClassMember> get localSetters;
}
class RegularSetterDeclaration
implements SetterDeclaration, SetterFragmentDeclaration {
final SetterFragment _fragment;
late final SetterEncoding _encoding;
RegularSetterDeclaration(this._fragment) {
_fragment.declaration = this;
}
@override
UriOffsetLength get uriOffset => _fragment.uriOffset;
@override
// Coverage-ignore(suite): Not run.
Uri get fileUri => _fragment.fileUri;
@override
List<FormalParameterBuilder>? get formals => _encoding.formals;
@override
bool get isNoSuchMethodForwarder => _encoding.isNoSuchMethodForwarder;
@override
// Coverage-ignore(suite): Not run.
bool get isAbstract => _fragment.modifiers.isAbstract;
@override
bool get isExternal => _fragment.modifiers.isExternal;
@override
// Coverage-ignore(suite): Not run.
List<MetadataBuilder>? get metadata => _fragment.metadata;
@override
// Coverage-ignore(suite): Not run.
String get name => _fragment.name;
@override
int get nameOffset => _fragment.nameOffset;
@override
TypeBuilder get returnType => _fragment.returnType;
@override
SetterQuality get setterQuality => _fragment.modifiers.isAbstract
? SetterQuality.Abstract
: _fragment.modifiers.isExternal
? SetterQuality.External
: SetterQuality.Concrete;
@override
List<TypeParameter>? get thisTypeParameters => _encoding.thisTypeParameters;
@override
VariableDeclaration? get thisVariable => _encoding.thisVariable;
@override
Procedure get writeTarget => _encoding.writeTarget;
@override
void becomeNative(SourceLoader loader) {
_encoding.becomeNative(loader);
}
@override
void buildSetterOutlineExpressions({
required ClassHierarchy classHierarchy,
required SourceLibraryBuilder libraryBuilder,
required DeclarationBuilder? declarationBuilder,
required SourcePropertyBuilder propertyBuilder,
required Annotatable annotatable,
required Uri annotatableFileUri,
}) {
_encoding.buildOutlineExpressions(
classHierarchy: classHierarchy,
libraryBuilder: libraryBuilder,
declarationBuilder: declarationBuilder,
propertyBuilder: propertyBuilder,
bodyBuilderContext: createBodyBuilderContext(propertyBuilder),
annotatable: annotatable,
annotatableFileUri: annotatableFileUri,
);
}
@override
void buildSetterOutlineNode({
required SourceLibraryBuilder libraryBuilder,
required ProblemReporting problemReporting,
required NameScheme nameScheme,
required BuildNodesCallback f,
required PropertyReferences? references,
required List<TypeParameter>? classTypeParameters,
}) {
_encoding.buildOutlineNode(
libraryBuilder: libraryBuilder,
problemReporting: problemReporting,
nameScheme: nameScheme,
f: f,
references: references,
isAbstractOrExternal:
_fragment.modifiers.isAbstract || _fragment.modifiers.isExternal,
classTypeParameters: classTypeParameters,
);
}
@override
void checkSetterTypes(
ProblemReporting problemReporting,
TypeEnvironment typeEnvironment,
) {
_encoding.checkTypes(
problemReporting,
typeEnvironment,
isAbstract: _fragment.modifiers.isAbstract,
isExternal: _fragment.modifiers.isExternal,
);
}
@override
void checkSetterVariance(
SourceClassBuilder sourceClassBuilder,
TypeEnvironment typeEnvironment,
) {
_encoding.checkVariance(sourceClassBuilder, typeEnvironment);
}
@override
int computeSetterDefaultTypes(ComputeDefaultTypeContext context) {
return _encoding.computeDefaultTypes(context);
}
@override
BodyBuilderContext createBodyBuilderContext(
SourcePropertyBuilder propertyBuilder,
) {
return new SetterBodyBuilderContext(
propertyBuilder,
this,
propertyBuilder.libraryBuilder,
propertyBuilder.declarationBuilder,
isDeclarationInstanceMember: propertyBuilder.isDeclarationInstanceMember,
);
}
@override
void createSetterEncoding(
ProblemReporting problemReporting,
SourcePropertyBuilder builder,
PropertyEncodingStrategy encodingStrategy,
TypeParameterFactory typeParameterFactory,
) {
_fragment.builder = builder;
typeParameterFactory.createNominalParameterBuilders(
_fragment.declaredTypeParameters,
);
_encoding = encodingStrategy.createSetterEncoding(
builder,
_fragment,
typeParameterFactory,
);
_fragment.typeParameterNameSpace.addTypeParameters(
problemReporting,
_encoding.clonedAndDeclaredTypeParameters,
ownerName: _fragment.name,
allowNameConflict: true,
);
}
@override
LocalScope createFormalParameterScope(LookupScope typeParameterScope) {
return _encoding.createFormalParameterScope(typeParameterScope);
}
@override
void ensureSetterTypes({
required SourceLibraryBuilder libraryBuilder,
required DeclarationBuilder? declarationBuilder,
required ClassMembersBuilder membersBuilder,
required Set<ClassMember>? setterOverrideDependencies,
}) {
if (setterOverrideDependencies != null) {
membersBuilder.inferSetterType(
declarationBuilder as SourceClassBuilder,
_fragment.declaredFormals,
setterOverrideDependencies,
name: _fragment.name,
fileUri: _fragment.fileUri,
nameOffset: _fragment.nameOffset,
nameLength: _fragment.name.length,
isClosureContextLoweringEnabled: libraryBuilder
.loader
.target
.backendTarget
.isConstructorTearOffLoweringEnabled,
);
}
_encoding.ensureTypes(libraryBuilder, membersBuilder.hierarchyBuilder);
}
@override
Iterable<Reference> getExportedSetterReferences(
PropertyReferences references,
) => [references.setterReference];
@override
List<ClassMember> get localSetters => [
new SetterClassMember(_fragment.builder),
];
@override
void registerFunctionBody({
required CompilerContext compilerContext,
required ProblemReporting problemReporting,
required Statement? body,
required Scope? scope,
required AsyncModifier asyncModifier,
required DartType? emittedValueType,
required VariableDeclaration? thisVariable,
}) {
List<FormalParameterBuilder>? declaredFormals = _fragment.declaredFormals;
if (declaredFormals == null ||
declaredFormals.length != 1 ||
declaredFormals.single.isOptionalPositional) {
int fileOffset = _fragment.formalsOffset;
if (body == null) {
body = extern.createEmptyStatement(fileOffset: fileOffset);
}
if (declaredFormals != null) {
// Illegal parameters were removed by the function builder.
// Add them as local variable to put them in scope of the body.
List<Statement> statements = <Statement>[];
for (FormalParameterBuilder parameter in declaredFormals) {
statements.add(extern.createVariableStatement(parameter.variable));
}
statements.add(body);
body = extern.createBlock(statements, fileOffset: fileOffset);
}
body = extern.createBlock([
extern.createExpressionStatement(
problemReporting.buildProblem(
compilerContext: compilerContext,
message: diag.setterWithWrongNumberOfFormals,
fileUri: _fragment.fileUri,
fileOffset: fileOffset,
length: noLength,
),
),
body,
], fileOffset: fileOffset);
}
assert(
asyncModifier.kind == _fragment.asyncModifier.kind,
"Unexpected change in async modifier on $this from "
"${_fragment.asyncModifier} to ${asyncModifier.kind}.",
);
_encoding.registerFunctionBody(
body: body,
// TODO(cstefantsova): Update scope to handle the insertion of parameters
// as locals above.
scope: scope,
asyncModifier: asyncModifier,
emittedValueType: emittedValueType,
thisVariable: thisVariable,
);
}
@override
DartType get returnTypeContext {
final bool isReturnTypeUndeclared =
returnType is OmittedTypeBuilder &&
// Coverage-ignore(suite): Not run.
_encoding.function.returnType is DynamicType;
return isReturnTypeUndeclared
? const UnknownType()
: _encoding.function.returnType;
}
}
/// Interface for using a [SetterFragment] to create a [BodyBuilderContext].
abstract class SetterFragmentDeclaration {
List<FormalParameterBuilder>? get formals;
bool get isNoSuchMethodForwarder;
bool get isAbstract;
bool get isExternal;
String get name;
int get nameOffset;
TypeBuilder get returnType;
List<TypeParameter>? get thisTypeParameters;
VariableDeclaration? get thisVariable;
void becomeNative(SourceLoader loader);
BodyBuilderContext createBodyBuilderContext(
SourcePropertyBuilder propertyBuilder,
);
LocalScope createFormalParameterScope(LookupScope typeParameterScope);
void registerFunctionBody({
required CompilerContext compilerContext,
required ProblemReporting problemReporting,
required Statement? body,
required Scope? scope,
required AsyncModifier asyncModifier,
required DartType? emittedValueType,
required VariableDeclaration? thisVariable,
});
DartType get returnTypeContext;
}