blob: ddcc9b57d415604dbdba8caeffccb0fe5a1f4781 [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:kernel/ast.dart';
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/type_environment.dart';
import '../../base/identifiers.dart';
import '../../base/name_space.dart';
import '../../builder/constructor_reference_builder.dart';
import '../../builder/formal_parameter_builder.dart';
import '../../builder/metadata_builder.dart';
import '../../builder/type_builder.dart';
import '../../fragment/fragment.dart';
import '../../kernel/body_builder_context.dart';
import '../../kernel/kernel_helper.dart';
import '../../kernel/type_algorithms.dart';
import '../../source/name_scheme.dart';
import '../../source/source_factory_builder.dart';
import '../../source/source_function_builder.dart';
import '../../source/source_library_builder.dart' show SourceLibraryBuilder;
import '../../source/source_loader.dart' show SourceLoader;
import '../../source/source_member_builder.dart';
import '../../source/source_type_parameter_builder.dart';
import 'body_builder_context.dart';
import 'encoding.dart';
/// Interface for the factory declaration aspect of a [SourceFactoryBuilder].
///
/// If a factory is augmented, it will have multiple
/// [FactoryDeclaration]s on a single [SourceFactoryBuilder].
abstract class FactoryDeclaration {
Uri get fileUri;
FunctionNode get function;
Iterable<MetadataBuilder>? get metadata;
Procedure get procedure;
ConstructorReferenceBuilder? get redirectionTarget;
Procedure? get tearOff;
void buildOutlineExpressions(
{required SourceLibraryBuilder libraryBuilder,
required SourceFactoryBuilder factoryBuilder,
required ClassHierarchy classHierarchy,
required List<DelayedDefaultValueCloner> delayedDefaultValueCloners,
required bool createFileUriExpression});
void buildOutlineNodes(
{required SourceLibraryBuilder libraryBuilder,
required SourceFactoryBuilder factoryBuilder,
required BuildNodesCallback f,
required bool isConst});
/// Checks this factory builder if it is for a redirecting factory.
void checkRedirectingFactory(
{required SourceLibraryBuilder libraryBuilder,
required SourceFactoryBuilder factoryBuilder,
required TypeEnvironment typeEnvironment});
void checkTypes(SourceLibraryBuilder library, NameSpace nameSpace,
TypeEnvironment typeEnvironment);
int computeDefaultTypes(ComputeDefaultTypeContext context,
{required bool inErrorRecovery});
void createNode({
required String name,
required SourceLibraryBuilder libraryBuilder,
required NameScheme nameScheme,
required Reference? procedureReference,
required Reference? tearOffReference,
});
void inferRedirectionTarget(
{required SourceLibraryBuilder libraryBuilder,
required SourceFactoryBuilder factoryBuilder,
required ClassHierarchy classHierarchy,
required List<DelayedDefaultValueCloner> delayedDefaultValueCloners});
void resolveRedirectingFactory(
{required SourceLibraryBuilder libraryBuilder});
}
class FactoryDeclarationImpl
implements FactoryDeclaration, FactoryFragmentDeclaration {
final FactoryFragment _fragment;
final List<SourceNominalParameterBuilder>? typeParameters;
@override
final TypeBuilder returnType;
final FactoryEncoding _encoding;
FactoryDeclarationImpl(this._fragment,
{required this.typeParameters, required this.returnType})
: _encoding = new FactoryEncoding(_fragment,
typeParameters: typeParameters,
returnType: returnType,
redirectionTarget: _fragment.redirectionTarget) {
_fragment.declaration = this;
}
@override
int get fileOffset => _fragment.fullNameOffset;
@override
Uri get fileUri => _fragment.fileUri;
@override
// Coverage-ignore(suite): Not run.
List<FormalParameterBuilder>? get formals => _fragment.formals;
@override
FunctionNode get function => _encoding.function;
@override
bool get isExternal => _fragment.modifiers.isExternal;
@override
// Coverage-ignore(suite): Not run.
bool get isNative => _encoding.isNative;
@override
// Coverage-ignore(suite): Not run.
Iterable<MetadataBuilder>? get metadata => _fragment.metadata;
@override
Procedure get procedure => _encoding.procedure;
@override
ConstructorReferenceBuilder? get redirectionTarget {
return _fragment.redirectionTarget;
}
@override
Procedure? get tearOff => _encoding.tearOff;
@override
void becomeNative(SourceLoader loader) {
loader.addNativeAnnotation(procedure, _fragment.nativeMethodName!);
_encoding.becomeNative(loader);
}
@override
void buildOutlineExpressions(
{required SourceLibraryBuilder libraryBuilder,
required SourceFactoryBuilder factoryBuilder,
required ClassHierarchy classHierarchy,
required List<DelayedDefaultValueCloner> delayedDefaultValueCloners,
required bool createFileUriExpression}) {
_fragment.formals?.infer(classHierarchy);
BodyBuilderContext bodyBuilderContext =
createBodyBuilderContext(factoryBuilder);
for (Annotatable annotatable in factoryBuilder.annotatables) {
MetadataBuilder.buildAnnotations(
annotatable,
_fragment.metadata,
bodyBuilderContext,
libraryBuilder,
_fragment.fileUri,
_fragment.enclosingScope,
createFileUriExpression: createFileUriExpression);
}
if (typeParameters != null) {
for (int i = 0; i < typeParameters!.length; i++) {
typeParameters![i].buildOutlineExpressions(
libraryBuilder, bodyBuilderContext, classHierarchy);
}
}
if (_fragment.formals != null) {
// For const constructors we need to include default parameter values
// into the outline. For all other formals we need to call
// buildOutlineExpressions to clear initializerToken to prevent
// consuming too much memory.
for (FormalParameterBuilder formal in _fragment.formals!) {
formal.buildOutlineExpressions(
libraryBuilder, factoryBuilder.declarationBuilder,
scope: _fragment.typeParameterScope,
buildDefaultValue: FormalParameterBuilder
.needsDefaultValuesBuiltAsOutlineExpressions(factoryBuilder));
}
}
_encoding.buildOutlineExpressions(
delayedDefaultValueCloners: delayedDefaultValueCloners);
}
@override
void buildOutlineNodes(
{required SourceLibraryBuilder libraryBuilder,
required SourceFactoryBuilder factoryBuilder,
required BuildNodesCallback f,
required bool isConst}) {
_encoding.buildOutlineNodes(
libraryBuilder: libraryBuilder,
factoryBuilder: factoryBuilder,
f: f,
isConst: isConst);
}
@override
void checkRedirectingFactory(
{required SourceLibraryBuilder libraryBuilder,
required SourceFactoryBuilder factoryBuilder,
required TypeEnvironment typeEnvironment}) {
_encoding.checkRedirectingFactory(
libraryBuilder: libraryBuilder,
factoryBuilder: factoryBuilder,
typeEnvironment: typeEnvironment);
}
@override
void checkTypes(SourceLibraryBuilder library, NameSpace nameSpace,
TypeEnvironment typeEnvironment) {
if (_fragment.redirectionTarget != null) {
// Default values are not required on redirecting factory constructors so
// we don't call [checkInitializersInFormals].
} else {
library.checkInitializersInFormals(_fragment.formals, typeEnvironment,
isAbstract: _fragment.modifiers.isAbstract,
isExternal: _fragment.modifiers.isExternal);
}
}
@override
int computeDefaultTypes(ComputeDefaultTypeContext context,
{required bool inErrorRecovery}) {
int count = context.computeDefaultTypesForVariables(typeParameters,
// Type parameters are inherited from the enclosing declaration, so if
// it has issues, so do the constructors.
inErrorRecovery: inErrorRecovery);
context.reportGenericFunctionTypesForFormals(_fragment.formals);
return count;
}
@override
BodyBuilderContext createBodyBuilderContext(
SourceFactoryBuilder factoryBuilder) {
return new FactoryBodyBuilderContext(
factoryBuilder, this, _encoding.procedure);
}
@override
void createNode({
required String name,
required SourceLibraryBuilder libraryBuilder,
required NameScheme nameScheme,
required Reference? procedureReference,
required Reference? tearOffReference,
}) {
_encoding.createNode(
name: name,
libraryBuilder: libraryBuilder,
nameScheme: nameScheme,
procedureReference: procedureReference,
tearOffReference: tearOffReference);
}
@override
FormalParameterBuilder? getFormal(Identifier identifier) {
return _encoding.getFormal(identifier);
}
@override
VariableDeclaration getFormalParameter(int index) =>
_fragment.formals![index].variable!;
@override
VariableDeclaration? getTearOffParameter(int index) {
return _encoding.getTearOffParameter(index);
}
@override
void inferRedirectionTarget(
{required SourceLibraryBuilder libraryBuilder,
required SourceFactoryBuilder factoryBuilder,
required ClassHierarchy classHierarchy,
required List<DelayedDefaultValueCloner> delayedDefaultValueCloners}) {
BodyBuilderContext bodyBuilderContext =
createBodyBuilderContext(factoryBuilder);
_encoding.inferRedirectionTarget(
libraryBuilder: libraryBuilder,
declarationBuilder: factoryBuilder.declarationBuilder,
bodyBuilderContext: bodyBuilderContext,
classHierarchy: classHierarchy,
delayedDefaultValueCloners: delayedDefaultValueCloners);
}
@override
void resolveRedirectingFactory(
{required SourceLibraryBuilder libraryBuilder}) {
_encoding.resolveRedirectingFactory(libraryBuilder: libraryBuilder);
}
@override
void setAsyncModifier(AsyncMarker newModifier) {
_encoding.asyncModifier = newModifier;
}
@override
void setBody(Statement value) {
_encoding.setBody(value);
}
}
/// Interface for using a [FactoryFragment] to create a [BodyBuilderContext].
abstract class FactoryFragmentDeclaration {
int get fileOffset;
List<FormalParameterBuilder>? get formals;
FunctionNode get function;
bool get isExternal;
bool get isNative;
ConstructorReferenceBuilder? get redirectionTarget;
TypeBuilder get returnType;
void becomeNative(SourceLoader loader);
BodyBuilderContext createBodyBuilderContext(
SourceFactoryBuilder factoryBuilder);
FormalParameterBuilder? getFormal(Identifier identifier);
/// Returns the [index]th parameter of this function.
///
/// The index is the syntactical index, including both positional and named
/// parameter in the order they are declared, and excluding the synthesized
/// this parameter on extension instance members.
VariableDeclaration getFormalParameter(int index);
/// If this is an extension instance method or constructor with lowering
/// enabled, the tear off parameter corresponding to the [index]th parameter
/// on the instance method or constructor is returned.
///
/// This is used to update the default value for the closure parameter when
/// it has been computed for the original parameter.
VariableDeclaration? getTearOffParameter(int index);
void setAsyncModifier(AsyncMarker newModifier);
void setBody(Statement value);
}