| // 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); |
| } |