blob: b1ac1ae2f202206b00e4598360836de290585aca [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/messages.dart';
import '../../base/name_space.dart';
import '../../builder/constructor_reference_builder.dart';
import '../../builder/declaration_builders.dart';
import '../../builder/formal_parameter_builder.dart';
import '../../builder/function_signature.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/check_helper.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 '../../source/type_parameter_factory.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;
FunctionSignature get signature;
Iterable<MetadataBuilder>? get metadata;
Procedure get procedure;
ConstructorReferenceBuilder? get redirectionTarget;
void createEncoding({
required ProblemReporting problemReporting,
required DeclarationBuilder declarationBuilder,
required SourceFactoryBuilder factoryBuilder,
required TypeParameterFactory typeParameterFactory,
required FactoryEncodingStrategy encodingStrategy,
});
void buildOutlineExpressions({
required Iterable<Annotatable> annotatables,
required Uri annotatablesFileUri,
required SourceLibraryBuilder libraryBuilder,
required SourceFactoryBuilder factoryBuilder,
required ClassHierarchy classHierarchy,
required List<DelayedDefaultValueCloner> delayedDefaultValueCloners,
});
void buildOutlineNodes({
required SourceLibraryBuilder libraryBuilder,
required SourceFactoryBuilder factoryBuilder,
required BuildNodesCallback f,
required NameScheme nameScheme,
required FactoryReferences? factoryReferences,
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,
});
/// If this is an erroneous redirecting factory, return the corresponding
/// error message. Returns `null` otherwise.
///
/// This is computed as part of [checkRedirectingFactory].
String? get redirectingFactoryTargetErrorMessage;
void checkTypes(
ProblemReporting problemReporting,
NameSpace nameSpace,
TypeEnvironment typeEnvironment,
);
int computeDefaultTypes(
ComputeDefaultTypeContext context, {
required bool inErrorRecovery,
});
void inferRedirectionTarget({
required SourceLibraryBuilder libraryBuilder,
required SourceFactoryBuilder factoryBuilder,
required ClassHierarchy classHierarchy,
required List<DelayedDefaultValueCloner> delayedDefaultValueCloners,
});
void resolveRedirectingFactory({
required SourceLibraryBuilder libraryBuilder,
});
bool get isRedirectingFactory;
}
class FactoryDeclarationImpl
implements FactoryDeclaration, FactoryFragmentDeclaration {
final FactoryFragment _fragment;
late final List<SourceNominalParameterBuilder>? _typeParameters;
late final TypeBuilder _returnType;
late final FactoryEncoding _encoding;
FactoryDeclarationImpl(this._fragment) {
_fragment.declaration = this;
}
@override
void createEncoding({
required ProblemReporting problemReporting,
required DeclarationBuilder declarationBuilder,
required SourceFactoryBuilder factoryBuilder,
required TypeParameterFactory typeParameterFactory,
required FactoryEncodingStrategy encodingStrategy,
}) {
_fragment.builder = factoryBuilder;
var (typeParameters, returnType) = encodingStrategy
.createTypeParametersAndReturnType(
declarationBuilder: declarationBuilder,
declarationTypeParameterFragments:
_fragment.enclosingDeclaration.typeParameters,
typeParameterFactory: typeParameterFactory,
fullName: _fragment.constructorName.fullName,
fileUri: _fragment.fileUri,
fullNameOffset: _fragment.constructorName.fullNameOffset,
fullNameLength: _fragment.constructorName.fullNameLength,
);
_typeParameters = typeParameters;
_returnType = returnType;
_fragment.typeParameterNameSpace.addTypeParameters(
problemReporting,
typeParameters,
ownerName: _fragment.name,
allowNameConflict: true,
);
_encoding = new FactoryEncoding(
_fragment,
typeParameters: typeParameters,
returnType: returnType,
redirectionTarget: _fragment.redirectionTarget,
);
}
@override
TypeBuilder get returnType => _returnType;
@override
int get fileOffset => _fragment.fullNameOffset;
@override
// Coverage-ignore(suite): Not run.
Uri get fileUri => _fragment.fileUri;
@override
bool get isRedirectingFactory => _fragment.redirectionTarget != null;
@override
List<FormalParameterBuilder>? get formals => _fragment.formals;
@override
FunctionSignature get signature => _encoding.signature;
@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
void becomeNative(SourceLoader loader) {
loader.addNativeAnnotation(procedure, _fragment.nativeMethodName!);
_encoding.becomeNative(loader);
}
@override
void buildOutlineExpressions({
required Iterable<Annotatable> annotatables,
required Uri annotatablesFileUri,
required SourceLibraryBuilder libraryBuilder,
required SourceFactoryBuilder factoryBuilder,
required ClassHierarchy classHierarchy,
required List<DelayedDefaultValueCloner> delayedDefaultValueCloners,
}) {
_fragment.formals?.infer(classHierarchy);
BodyBuilderContext bodyBuilderContext = createBodyBuilderContext(
factoryBuilder,
);
for (Annotatable annotatable in annotatables) {
MetadataBuilder.buildAnnotations(
annotatable: annotatable,
annotatableFileUri: annotatablesFileUri,
metadata: _fragment.metadata,
annotationsFileUri: _fragment.fileUri,
bodyBuilderContext: bodyBuilderContext,
libraryBuilder: libraryBuilder,
extensionScope: _fragment.enclosingCompilationUnit.extensionScope,
scope: _fragment.enclosingScope,
);
}
if (_typeParameters != null) {
for (int i = 0; i < _typeParameters.length; i++) {
_typeParameters[i].buildOutlineExpressions(
libraryBuilder,
bodyBuilderContext,
classHierarchy,
);
}
}
if (_fragment.formals != null) {
for (FormalParameterBuilder formal in _fragment.formals!) {
formal.buildOutlineExpressions(
libraryBuilder: libraryBuilder,
declarationBuilder: factoryBuilder.declarationBuilder,
memberBuilder: factoryBuilder,
extensionScope: _fragment.enclosingCompilationUnit.extensionScope,
scope: _fragment.typeParameterScope,
);
}
}
_encoding.buildOutlineExpressions(
delayedDefaultValueCloners: delayedDefaultValueCloners,
);
}
@override
void buildOutlineNodes({
required SourceLibraryBuilder libraryBuilder,
required SourceFactoryBuilder factoryBuilder,
required BuildNodesCallback f,
required NameScheme nameScheme,
required FactoryReferences? factoryReferences,
required bool isConst,
}) {
_encoding.buildOutlineNodes(
libraryBuilder: libraryBuilder,
factoryBuilder: factoryBuilder,
f: f,
name: _fragment.name,
nameScheme: nameScheme,
factoryReferences: factoryReferences,
isConst: isConst,
);
}
@override
void checkRedirectingFactory({
required SourceLibraryBuilder libraryBuilder,
required SourceFactoryBuilder factoryBuilder,
required TypeEnvironment typeEnvironment,
}) {
_encoding.checkRedirectingFactory(
libraryBuilder: libraryBuilder,
factoryBuilder: factoryBuilder,
typeEnvironment: typeEnvironment,
);
}
@override
String? get redirectingFactoryTargetErrorMessage =>
_encoding.redirectingFactoryTargetErrorMessage;
@override
void checkTypes(
ProblemReporting problemReporting,
NameSpace nameSpace,
TypeEnvironment typeEnvironment,
) {
if (_fragment.redirectionTarget != null) {
// Default values are not required on redirecting factory constructors so
// we don't call [checkInitializersInFormals].
} else {
problemReporting.checkInitializersInFormals(
formals: _fragment.formals,
typeEnvironment: 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
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 registerFunctionBody({
required Statement? body,
required Scope? scope,
required AsyncMarker asyncMarker,
required DartType? emittedValueType,
}) {
_encoding.registerFunctionBody(
body: body,
scope: scope,
asyncMarker: asyncMarker,
emittedValueType: emittedValueType,
);
}
@override
DartType get returnTypeContext {
return _encoding.returnTypeContext;
}
}
/// Interface for using a [FactoryFragment] to create a [BodyBuilderContext].
abstract class FactoryFragmentDeclaration {
int get fileOffset;
List<FormalParameterBuilder>? get formals;
bool get isExternal;
bool get isNative;
ConstructorReferenceBuilder? get redirectionTarget;
TypeBuilder get returnType;
void becomeNative(SourceLoader loader);
BodyBuilderContext createBodyBuilderContext(
SourceFactoryBuilder factoryBuilder,
);
/// 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 registerFunctionBody({
required Statement? body,
required Scope? scope,
required AsyncMarker asyncMarker,
required DartType? emittedValueType,
});
DartType get returnTypeContext;
}