e30cd0322c
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>
420 lines
12 KiB
Dart
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;
|
|
}
|