blob: bd375afd603c839c3cec2a69b30ef09291e84682 [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:_fe_analyzer_shared/src/scanner/token.dart' show Token;
import 'package:kernel/ast.dart';
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/type_algebra.dart';
import 'package:kernel/type_environment.dart';
import '../../base/constant_context.dart';
import '../../base/identifiers.dart';
import '../../base/local_scope.dart';
import '../../base/messages.dart';
import '../../base/name_space.dart';
import '../../base/scope.dart';
import '../../builder/constructor_builder.dart';
import '../../builder/declaration_builders.dart';
import '../../builder/formal_parameter_builder.dart';
import '../../builder/member_builder.dart';
import '../../builder/metadata_builder.dart';
import '../../builder/omitted_type_builder.dart';
import '../../builder/type_builder.dart';
import '../../builder/variable_builder.dart';
import '../../kernel/body_builder.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_class_builder.dart';
import '../../source/source_constructor_builder.dart';
import '../../source/source_extension_type_declaration_builder.dart';
import '../../source/source_function_builder.dart';
import '../../source/source_library_builder.dart';
import '../../source/source_loader.dart';
import '../../source/source_member_builder.dart';
import '../../source/source_type_parameter_builder.dart';
import '../../source/type_parameter_factory.dart';
import '../fragment.dart';
import 'encoding.dart';
/// Interface for the constructor declaration aspect of a
/// [SourceConstructorBuilder].
///
/// If a constructor is augmented, it will have multiple
/// [ConstructorDeclaration]s on a single [SourceConstructorBuilder].
abstract class ConstructorDeclaration {
Uri get fileUri;
List<MetadataBuilder>? get metadata;
FunctionNode get function;
bool get hasParameters;
List<Initializer> get initializers;
void createEncoding({
required ProblemReporting problemReporting,
required SourceLoader loader,
required DeclarationBuilder declarationBuilder,
required SourceConstructorBuilder constructorBuilder,
required TypeParameterFactory typeParameterFactory,
required ConstructorEncodingStrategy encodingStrategy,
});
void buildOutlineNodes(
BuildNodesCallback f, {
required SourceConstructorBuilder constructorBuilder,
required SourceLibraryBuilder libraryBuilder,
required NameScheme nameScheme,
required ConstructorReferences? constructorReferences,
required List<DelayedDefaultValueCloner> delayedDefaultValueCloners,
});
void buildOutlineExpressions({
required Iterable<Annotatable> annotatables,
required Uri annotatablesFileUri,
required SourceLibraryBuilder libraryBuilder,
required DeclarationBuilder declarationBuilder,
required SourceConstructorBuilder constructorBuilder,
required ClassHierarchy classHierarchy,
required List<DelayedDefaultValueCloner> delayedDefaultValueCloners,
});
void checkTypes(SourceLibraryBuilder libraryBuilder, NameSpace nameSpace,
TypeEnvironment typeEnvironment);
int computeDefaultTypes(ComputeDefaultTypeContext context,
{required bool inErrorRecovery});
void prepareInitializers();
void prependInitializer(Initializer initializer);
Substitution computeFieldTypeSubstitution(
DeclarationBuilder declarationBuilder);
void buildBody();
bool get isExternal;
bool get isRedirecting;
void addSuperParameterDefaultValueCloners(
SourceLibraryBuilder libraryBuilder,
DeclarationBuilder declarationBuilder,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners);
void inferFormalTypes(
SourceLibraryBuilder libraryBuilder,
DeclarationBuilder declarationBuilder,
SourceConstructorBuilder constructorBuilder,
ClassHierarchyBase hierarchy,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners);
/// Mark the constructor as erroneous.
///
/// This is used during the compilation phase to set the appropriate flag on
/// the input AST node. The flag helps the verifier to skip apriori erroneous
/// members and to avoid reporting cascading errors.
void markAsErroneous();
}
mixin _ConstructorDeclarationMixin
implements ConstructorDeclaration, ConstructorFragmentDeclaration {
bool get _hasSuperInitializingFormals;
LookupScope get _typeParameterScope;
abstract Token? _beginInitializers;
List<SourceNominalParameterBuilder>? get _typeParameters;
@override
bool get hasParameters => formals != null;
@override
FormalParameterBuilder? getFormal(Identifier identifier) {
if (formals != null) {
List<FormalParameterBuilder> formals = this.formals!;
for (int i = 0; i < formals.length; i++) {
FormalParameterBuilder formal = formals[i];
if (formal.isWildcard &&
identifier.name == '_' &&
formal.fileOffset == identifier.nameOffset) {
return formal;
}
if (formal.name == identifier.name &&
formal.fileOffset == identifier.nameOffset) {
return formal;
}
}
// Coverage-ignore(suite): Not run.
// If we have any formals we should find the one we're looking for.
assert(false, "$identifier not found in $formals");
}
return null;
}
@override
LocalScope computeFormalParameterInitializerScope(LocalScope parent) {
// From
// [dartLangSpec.tex](../../../../../../docs/language/dartLangSpec.tex) at
// revision 94b23d3b125e9d246e07a2b43b61740759a0dace:
//
// When the formal parameter list of a non-redirecting generative
// constructor contains any initializing formals, a new scope is
// introduced, the _formal parameter initializer scope_, which is the
// current scope of the initializer list of the constructor, and which is
// enclosed in the scope where the constructor is declared. Each
// initializing formal in the formal parameter list introduces a final
// local variable into the formal parameter initializer scope, but not into
// the formal parameter scope; every other formal parameter introduces a
// local variable into both the formal parameter scope and the formal
// parameter initializer scope.
if (formals == null) return parent;
Map<String, VariableBuilder> local = {};
for (FormalParameterBuilder formal in formals!) {
// Wildcard initializing formal parameters do not introduce a local
// variable in the initializer list.
if (formal.isWildcard) continue;
local[formal.name] = formal.forFormalParameterInitializerScope();
}
return parent.createNestedFixedScope(
debugName: "formal parameter initializer",
kind: ScopeKind.initializers,
local: local);
}
@override
void inferFormalTypes(
SourceLibraryBuilder libraryBuilder,
DeclarationBuilder declarationBuilder,
SourceConstructorBuilder constructorBuilder,
ClassHierarchyBase hierarchy,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
if (formals != null) {
libraryBuilder.loader.withUriForCrashReporting(fileUri, fileOffset, () {
for (FormalParameterBuilder formal in formals!) {
if (formal.type is InferableTypeBuilder) {
if (formal.isInitializingFormal) {
formal.finalizeInitializingFormal(
declarationBuilder, constructorBuilder, hierarchy);
}
}
}
_inferSuperInitializingFormals(libraryBuilder, declarationBuilder,
constructorBuilder, hierarchy, delayedDefaultValueCloners);
});
}
}
void _inferSuperInitializingFormals(
SourceLibraryBuilder libraryBuilder,
DeclarationBuilder declarationBuilder,
SourceConstructorBuilder constructorBuilder,
ClassHierarchyBase hierarchy,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
if (_hasSuperInitializingFormals) {
List<Initializer>? initializers;
Token? beginInitializers = this._beginInitializers;
if (beginInitializers != null) {
BodyBuilder bodyBuilder = libraryBuilder.loader
.createBodyBuilderForOutlineExpression(
libraryBuilder,
createBodyBuilderContext(constructorBuilder),
_typeParameterScope,
fileUri);
if (isConst) {
bodyBuilder.constantContext = ConstantContext.required;
}
initializers = bodyBuilder.parseInitializers(beginInitializers,
doFinishConstructor: false);
}
_finalizeSuperInitializingFormals(libraryBuilder, declarationBuilder,
hierarchy, delayedDefaultValueCloners, initializers);
}
}
void _finalizeSuperInitializingFormals(
SourceLibraryBuilder libraryBuilder,
DeclarationBuilder declarationBuilder,
ClassHierarchyBase hierarchy,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners,
List<Initializer>? initializers) {
if (formals == null) return;
if (!_hasSuperInitializingFormals) return;
void performRecoveryForErroneousCase() {
for (FormalParameterBuilder formal in formals!) {
if (formal.isSuperInitializingFormal) {
TypeBuilder type = formal.type;
if (type is InferableTypeBuilder) {
type.registerInferredType(const InvalidType());
}
}
}
}
ConstructorBuilder? superTargetBuilder = _computeSuperTargetBuilder(
libraryBuilder, declarationBuilder, initializers);
if (superTargetBuilder is SourceConstructorBuilder) {
superTargetBuilder.inferFormalTypes(hierarchy);
}
Member superTarget;
FunctionNode? superConstructorFunction;
if (superTargetBuilder != null) {
superTarget = superTargetBuilder.invokeTarget;
superConstructorFunction = superTargetBuilder.function;
} else {
assert(libraryBuilder.loader.assertProblemReportedElsewhere(
"${this.runtimeType}.finalizeSuperInitializingFormals: "
"Can't compute super target.",
expectedPhase: CompilationPhaseForProblemReporting.bodyBuilding));
// Perform a simple recovery.
return performRecoveryForErroneousCase();
}
SourceClassBuilder classBuilder = declarationBuilder as SourceClassBuilder;
List<DartType?> positionalSuperFormalType = [];
List<bool> positionalSuperFormalHasInitializer = [];
Map<String, DartType?> namedSuperFormalType = {};
Map<String, bool> namedSuperFormalHasInitializer = {};
for (VariableDeclaration formal
in superConstructorFunction.positionalParameters) {
positionalSuperFormalType.add(formal.type);
positionalSuperFormalHasInitializer.add(formal.hasDeclaredInitializer);
}
for (VariableDeclaration formal
in superConstructorFunction.namedParameters) {
namedSuperFormalType[formal.name!] = formal.type;
namedSuperFormalHasInitializer[formal.name!] =
formal.hasDeclaredInitializer;
}
int superInitializingFormalIndex = -1;
List<int?>? positionalSuperParameters;
List<String>? namedSuperParameters;
Supertype? supertype = hierarchy.getClassAsInstanceOf(
classBuilder.cls, superTarget.enclosingClass!);
assert(supertype != null);
Map<TypeParameter, DartType> substitution =
new Map<TypeParameter, DartType>.fromIterables(
supertype!.classNode.typeParameters, supertype.typeArguments);
for (int formalIndex = 0; formalIndex < formals!.length; formalIndex++) {
FormalParameterBuilder formal = formals![formalIndex];
if (formal.isSuperInitializingFormal) {
superInitializingFormalIndex++;
bool hasImmediatelyDeclaredInitializer =
formal.hasImmediatelyDeclaredInitializer;
DartType? correspondingSuperFormalType;
if (formal.isPositional) {
assert(positionalSuperFormalHasInitializer.length ==
positionalSuperFormalType.length);
if (superInitializingFormalIndex <
positionalSuperFormalHasInitializer.length) {
if (formal.isOptional) {
formal.hasDeclaredInitializer =
hasImmediatelyDeclaredInitializer ||
positionalSuperFormalHasInitializer[
superInitializingFormalIndex];
}
correspondingSuperFormalType =
positionalSuperFormalType[superInitializingFormalIndex];
if (!hasImmediatelyDeclaredInitializer &&
!formal.isRequiredPositional) {
(positionalSuperParameters ??= <int?>[]).add(formalIndex);
} else {
(positionalSuperParameters ??= <int?>[]).add(null);
}
} else {
assert(libraryBuilder.loader.assertProblemReportedElsewhere(
"${this.runtimeType}"
".finalizeSuperInitializingFormals: "
"Super initializer count is greater than the count of "
"positional formals in the super constructor.",
expectedPhase:
CompilationPhaseForProblemReporting.bodyBuilding));
}
} else {
if (namedSuperFormalHasInitializer[formal.name] != null) {
if (formal.isOptional) {
formal.hasDeclaredInitializer =
hasImmediatelyDeclaredInitializer ||
namedSuperFormalHasInitializer[formal.name]!;
}
correspondingSuperFormalType = namedSuperFormalType[formal.name];
if (!hasImmediatelyDeclaredInitializer && !formal.isRequiredNamed) {
(namedSuperParameters ??= <String>[]).add(formal.name);
}
} else {
// TODO(cstefantsova): Report an error.
}
}
if (formal.type is InferableTypeBuilder) {
DartType? type = correspondingSuperFormalType;
if (substitution.isNotEmpty && type != null) {
type = substitute(type, substitution);
}
formal.type.registerInferredType(type ?? const DynamicType());
}
formal.variable!.hasDeclaredInitializer = formal.hasDeclaredInitializer;
}
}
if (positionalSuperParameters != null || namedSuperParameters != null) {
_addSuperParameterDefaultValueCloners(
libraryBuilder: libraryBuilder,
delayedDefaultValueCloners: delayedDefaultValueCloners,
superTarget: superTarget,
positionalSuperParameters: positionalSuperParameters,
namedSuperParameters: namedSuperParameters);
}
}
void _addSuperParameterDefaultValueCloners(
{required List<DelayedDefaultValueCloner> delayedDefaultValueCloners,
required Member superTarget,
required List<int?>? positionalSuperParameters,
required List<String>? namedSuperParameters,
required SourceLibraryBuilder libraryBuilder});
ConstructorBuilder? _computeSuperTargetBuilder(
SourceLibraryBuilder libraryBuilder,
DeclarationBuilder declarationBuilder,
List<Initializer>? initializers) {
if (declarationBuilder is! SourceClassBuilder) {
return null;
}
SourceClassBuilder classBuilder = declarationBuilder;
Member superTarget;
ClassBuilder superclassBuilder;
TypeBuilder? supertype = classBuilder.supertypeBuilder;
TypeDeclarationBuilder? supertypeDeclaration =
supertype?.computeUnaliasedDeclaration(isUsedAsClass: false);
if (supertypeDeclaration is ClassBuilder) {
superclassBuilder = supertypeDeclaration;
} else {
assert(libraryBuilder.loader.assertProblemReportedElsewhere(
"${this.runtimeType}._computeSuperTargetBuilder: "
"Unaliased 'declaration' isn't a ClassBuilder.",
expectedPhase: CompilationPhaseForProblemReporting.outline));
return null;
}
if (initializers != null &&
initializers.isNotEmpty &&
initializers.last is SuperInitializer) {
superTarget = (initializers.last as SuperInitializer).target;
} else {
MemberBuilder? memberBuilder = superclassBuilder.findConstructorOrFactory(
"", fileOffset, fileUri, libraryBuilder);
if (memberBuilder is ConstructorBuilder) {
superTarget = memberBuilder.invokeTarget;
} else {
assert(libraryBuilder.loader.assertProblemReportedElsewhere(
"${this.runtimeType}._computeSuperTargetBuilder: "
"Can't find the implied unnamed constructor in the superclass.",
expectedPhase: CompilationPhaseForProblemReporting.bodyBuilding));
return null;
}
}
MemberBuilder? constructorBuilder =
superclassBuilder.findConstructorOrFactory(
superTarget.name.text, fileOffset, fileUri, libraryBuilder);
if (constructorBuilder is ConstructorBuilder) {
return constructorBuilder;
} else {
// Coverage-ignore-block(suite): Not run.
assert(libraryBuilder.loader.assertProblemReportedElsewhere(
"${this.runtimeType}._computeSuperTargetBuilder: "
"Can't find a constructor with name '${superTarget.name.text}' in "
"the superclass.",
expectedPhase: CompilationPhaseForProblemReporting.outline));
return null;
}
}
@override
void addSuperParameterDefaultValueCloners(
SourceLibraryBuilder libraryBuilder,
DeclarationBuilder declarationBuilder,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
if (_beginInitializers != null && initializers.isNotEmpty) {
// If the initializers aren't built yet, we can't compute the super
// target. The synthetic initializers should be excluded, since they can
// be built separately from formal field initializers.
bool allInitializersAreSynthetic = true;
for (Initializer initializer in initializers) {
if (!initializer.isSynthetic) {
allInitializersAreSynthetic = false;
break;
}
}
if (!allInitializersAreSynthetic) {
ConstructorBuilder? superTargetBuilder = _computeSuperTargetBuilder(
libraryBuilder, declarationBuilder, initializers);
if (superTargetBuilder is SourceConstructorBuilder) {
superTargetBuilder
.addSuperParameterDefaultValueCloners(delayedDefaultValueCloners);
}
}
}
}
@override
LocalScope computeFormalParameterScope(LookupScope parent) {
if (formals == null) return new FormalParameterScope(parent: parent);
Map<String, VariableBuilder> local = {};
for (FormalParameterBuilder formal in formals!) {
if (formal.isWildcard) {
continue;
}
if (!formal.isInitializingFormal && !formal.isSuperInitializingFormal) {
local[formal.name] = formal;
}
}
return new FormalParameterScope(local: local, parent: parent);
}
void _buildConstructorForOutlineExpressions(
SourceLibraryBuilder libraryBuilder,
SourceConstructorBuilder constructorBuilder) {
if (_beginInitializers != null) {
final LocalScope? formalParameterScope;
if (isConst) {
// We're going to fully build the constructor so we need scopes.
formalParameterScope = computeFormalParameterInitializerScope(
computeFormalParameterScope(_typeParameterScope));
} else {
formalParameterScope = null;
}
BodyBuilder bodyBuilder = libraryBuilder.loader
.createBodyBuilderForOutlineExpression(
libraryBuilder,
createBodyBuilderContext(constructorBuilder),
_typeParameterScope,
fileUri,
formalParameterScope: formalParameterScope);
if (isConst) {
bodyBuilder.constantContext = ConstantContext.required;
}
constructorBuilder.inferFormalTypes(bodyBuilder.hierarchy);
bodyBuilder.parseInitializers(_beginInitializers!,
doFinishConstructor: isConst);
bodyBuilder.performBacklogComputations();
}
}
void _buildOutlineExpressions(SourceLibraryBuilder libraryBuilder,
SourceConstructorBuilder constructorBuilder) {
if (isConst || _hasSuperInitializingFormals) {
// For modular compilation purposes we need to include initializers
// for const constructors into the outline.
_buildConstructorForOutlineExpressions(
libraryBuilder, constructorBuilder);
buildBody();
}
}
void _buildMetadataForOutlineExpressions({
required Iterable<Annotatable> annotatables,
required Uri annotatablesFileUri,
required SourceLibraryBuilder libraryBuilder,
required DeclarationBuilder declarationBuilder,
required SourceConstructorBuilder constructorBuilder,
required BodyBuilderContext bodyBuilderContext,
required ClassHierarchy classHierarchy,
});
void _buildTypeParametersAndFormalsForOutlineExpressions({
required SourceLibraryBuilder libraryBuilder,
required DeclarationBuilder declarationBuilder,
required BodyBuilderContext bodyBuilderContext,
required ClassHierarchy classHierarchy,
});
@override
void buildOutlineExpressions({
required Iterable<Annotatable> annotatables,
required Uri annotatablesFileUri,
required SourceLibraryBuilder libraryBuilder,
required DeclarationBuilder declarationBuilder,
required SourceConstructorBuilder constructorBuilder,
required ClassHierarchy classHierarchy,
required List<DelayedDefaultValueCloner> delayedDefaultValueCloners,
}) {
formals?.infer(classHierarchy);
BodyBuilderContext bodyBuilderContext =
createBodyBuilderContext(constructorBuilder);
_buildMetadataForOutlineExpressions(
annotatables: annotatables,
annotatablesFileUri: annotatablesFileUri,
libraryBuilder: libraryBuilder,
declarationBuilder: declarationBuilder,
constructorBuilder: constructorBuilder,
bodyBuilderContext: bodyBuilderContext,
classHierarchy: classHierarchy);
_buildTypeParametersAndFormalsForOutlineExpressions(
libraryBuilder: libraryBuilder,
declarationBuilder: declarationBuilder,
bodyBuilderContext: bodyBuilderContext,
classHierarchy: classHierarchy);
_buildOutlineExpressions(libraryBuilder, constructorBuilder);
addSuperParameterDefaultValueCloners(
libraryBuilder, declarationBuilder, delayedDefaultValueCloners);
_beginInitializers = null;
}
@override
void checkTypes(SourceLibraryBuilder libraryBuilder, NameSpace nameSpace,
TypeEnvironment typeEnvironment) {
libraryBuilder.checkInitializersInFormals(formals, typeEnvironment,
isAbstract: false, isExternal: 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(formals);
return count;
}
}
mixin _ConstructorEncodingMixin
implements
ConstructorDeclaration,
_ConstructorDeclarationMixin,
ConstructorFragmentDeclaration {
ConstructorEncoding get _encoding;
String? get _nativeMethodName;
@override
late final bool _hasSuperInitializingFormals =
formals?.any((formal) => formal.isSuperInitializingFormal) ?? false;
@override
FunctionNode get function => _encoding.function;
@override
List<Initializer> get initializers => _encoding.initializers;
@override
bool get isRedirecting => _encoding.isRedirecting;
@override
void prepareInitializers() {
_encoding.prepareInitializers();
}
@override
void prependInitializer(Initializer initializer) {
_encoding.prependInitializer(initializer);
}
@override
VariableDeclaration getFormalParameter(int index) {
return _encoding.getFormalParameter(index);
}
@override
VariableDeclaration? getTearOffParameter(int index) {
return _encoding.getTearOffParameter(index);
}
@override
void markAsErroneous() {
_encoding.markAsErroneous();
}
@override
VariableDeclaration? get thisVariable => _encoding.thisVariable;
@override
List<TypeParameter>? get thisTypeParameters => _encoding.thisTypeParameters;
@override
void registerFunctionBody(Statement value) {
_encoding.registerFunctionBody(value);
}
@override
void registerNoBodyConstructor() {
_encoding.registerNoBodyConstructor();
}
@override
void buildBody() {
_encoding.buildBody();
}
@override
void _addSuperParameterDefaultValueCloners(
{required List<DelayedDefaultValueCloner> delayedDefaultValueCloners,
required Member superTarget,
required List<int?>? positionalSuperParameters,
required List<String>? namedSuperParameters,
required SourceLibraryBuilder libraryBuilder}) {
_encoding.addSuperParameterDefaultValueCloners(
delayedDefaultValueCloners: delayedDefaultValueCloners,
superTarget: superTarget,
positionalSuperParameters: positionalSuperParameters,
namedSuperParameters: namedSuperParameters,
libraryBuilder: libraryBuilder);
}
@override
Substitution computeFieldTypeSubstitution(
DeclarationBuilder declarationBuilder) {
return _encoding.computeFieldTypeSubstitution(
declarationBuilder, _typeParameters);
}
@override
void becomeNative(SourceLoader loader) {
_encoding.becomeNative(loader, _nativeMethodName!);
}
}
mixin _RegularConstructorDeclarationMixin
implements
_ConstructorDeclarationMixin,
_ConstructorEncodingMixin,
InferredTypeListener {
void _buildTypeParametersAndFormals({
required SourceLibraryBuilder libraryBuilder,
required DeclarationBuilder declarationBuilder,
required BodyBuilderContext bodyBuilderContext,
required ClassHierarchy classHierarchy,
required LookupScope typeParameterScope,
}) {
if (_typeParameters != null) {
for (int i = 0; i < _typeParameters!.length; i++) {
_typeParameters![i].buildOutlineExpressions(
libraryBuilder, bodyBuilderContext, classHierarchy);
}
}
if (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 formals!) {
formal.buildOutlineExpressions(libraryBuilder, declarationBuilder,
scope: typeParameterScope, buildDefaultValue: true);
}
}
}
@override
BodyBuilderContext createBodyBuilderContext(
SourceConstructorBuilder constructorBuilder) {
return _encoding.createBodyBuilderContext(constructorBuilder, this);
}
@override
void onInferredType(DartType type) {
function.returnType = type;
}
void _registerInferable(Inferable inferable) {
returnType.registerInferredTypeListener(this);
if (formals != null) {
for (FormalParameterBuilder formal in formals!) {
if (formal.isInitializingFormal || formal.isSuperInitializingFormal) {
formal.type.registerInferable(inferable);
}
}
}
}
}
class RegularConstructorDeclaration
with
_ConstructorDeclarationMixin,
_ConstructorEncodingMixin,
_RegularConstructorDeclarationMixin
implements ConstructorDeclaration, ConstructorFragmentDeclaration {
final ConstructorFragment _fragment;
@override
late final ConstructorEncoding _encoding;
late final List<FormalParameterBuilder>? _formals;
@override
late final List<SourceNominalParameterBuilder>? _typeParameters;
@override
Token? _beginInitializers;
RegularConstructorDeclaration(this._fragment)
: _beginInitializers = _fragment.beginInitializers {
_fragment.declaration = this;
}
@override
String? get _nativeMethodName => _fragment.nativeMethodName;
@override
// Coverage-ignore(suite): Not run.
bool get isNative => _fragment.nativeMethodName != null;
@override
LookupScope get _typeParameterScope => _fragment.typeParameterScope;
@override
// Coverage-ignore(suite): Not run.
List<MetadataBuilder>? get metadata => _fragment.metadata;
@override
OmittedTypeBuilder get returnType => _fragment.returnType;
@override
bool get isConst => _fragment.modifiers.isConst;
@override
bool get isExternal => _fragment.modifiers.isExternal;
@override
int get fileOffset => _fragment.fullNameOffset;
@override
Uri get fileUri => _fragment.fileUri;
@override
void createEncoding({
required ProblemReporting problemReporting,
required SourceLoader loader,
required DeclarationBuilder declarationBuilder,
required SourceConstructorBuilder constructorBuilder,
required TypeParameterFactory typeParameterFactory,
required ConstructorEncodingStrategy encodingStrategy,
}) {
_fragment.builder = constructorBuilder;
_typeParameters = encodingStrategy.createTypeParameters(
declarationBuilder: declarationBuilder,
declarationTypeParameterFragments:
_fragment.enclosingDeclaration.typeParameters,
typeParameters: typeParameterFactory
.createNominalParameterBuilders(_fragment.typeParameters),
typeParameterFactory: typeParameterFactory);
_fragment.typeParameterNameSpace.addTypeParameters(
problemReporting, _typeParameters,
ownerName: _fragment.name, allowNameConflict: true);
_formals = encodingStrategy.createFormals(
loader: loader,
formals: _fragment.formals,
fileUri: _fragment.fileUri,
fileOffset: _fragment.fullNameOffset);
_encoding = encodingStrategy.createEncoding(
isExternal: _fragment.modifiers.isExternal);
_registerInferable(constructorBuilder);
}
@override
List<FormalParameterBuilder>? get formals => _formals;
@override
void buildOutlineNodes(BuildNodesCallback f,
{required SourceConstructorBuilder constructorBuilder,
required SourceLibraryBuilder libraryBuilder,
required NameScheme nameScheme,
required ConstructorReferences? constructorReferences,
required List<DelayedDefaultValueCloner> delayedDefaultValueCloners}) {
_encoding.buildOutlineNodes(f,
constructorBuilder: constructorBuilder,
libraryBuilder: libraryBuilder,
declarationBuilder: constructorBuilder.declarationBuilder,
name: _fragment.name,
nameScheme: nameScheme,
constructorReferences: constructorReferences,
fileUri: _fragment.fileUri,
startOffset: _fragment.startOffset,
fileOffset: _fragment.fullNameOffset,
endOffset: _fragment.endOffset,
isSynthetic: false,
forAbstractClassOrEnumOrMixin: _fragment.forAbstractClassOrMixin,
formalsOffset: _fragment.formalsOffset,
isConst: _fragment.modifiers.isConst,
returnType: returnType,
typeParameters: _typeParameters,
formals: formals,
delayedDefaultValueCloners: delayedDefaultValueCloners);
}
@override
void _buildMetadataForOutlineExpressions(
{required Iterable<Annotatable> annotatables,
required Uri annotatablesFileUri,
required SourceLibraryBuilder libraryBuilder,
required DeclarationBuilder declarationBuilder,
required SourceConstructorBuilder constructorBuilder,
required BodyBuilderContext bodyBuilderContext,
required ClassHierarchy classHierarchy}) {
for (Annotatable annotatable in annotatables) {
MetadataBuilder.buildAnnotations(
annotatable: annotatable,
annotatableFileUri: annotatablesFileUri,
metadata: _fragment.metadata,
bodyBuilderContext: bodyBuilderContext,
libraryBuilder: libraryBuilder,
scope: _fragment.enclosingScope);
}
}
@override
void _buildTypeParametersAndFormalsForOutlineExpressions(
{required SourceLibraryBuilder libraryBuilder,
required DeclarationBuilder declarationBuilder,
required BodyBuilderContext bodyBuilderContext,
required ClassHierarchy classHierarchy}) {
_buildTypeParametersAndFormals(
libraryBuilder: libraryBuilder,
declarationBuilder: declarationBuilder,
bodyBuilderContext: bodyBuilderContext,
classHierarchy: classHierarchy,
typeParameterScope: _fragment.typeParameterScope);
}
}
class DefaultEnumConstructorDeclaration
with
_ConstructorDeclarationMixin,
_ConstructorEncodingMixin,
_RegularConstructorDeclarationMixin
implements ConstructorDeclaration {
@override
final Uri fileUri;
@override
final int fileOffset;
@override
final OmittedTypeBuilder returnType;
@override
final List<FormalParameterBuilder> formals;
@override
late final ConstructorEncoding _encoding;
/// The scope in which to build the formal parameters.
final LookupScope _lookupScope;
@override
Token? _beginInitializers;
DefaultEnumConstructorDeclaration(
{required this.returnType,
required this.formals,
required Uri fileUri,
required int fileOffset,
required LookupScope lookupScope})
: fileUri = fileUri,
fileOffset = fileOffset,
_lookupScope = lookupScope,
// Trick the constructor to be built during the outline phase.
// TODO(johnniwinther): Avoid relying on [beginInitializers] to
// ensure building constructors creation during the outline phase.
_beginInitializers = new Token.eof(-1);
@override
void createEncoding({
required ProblemReporting problemReporting,
required SourceLoader loader,
required DeclarationBuilder declarationBuilder,
required SourceConstructorBuilder constructorBuilder,
required TypeParameterFactory typeParameterFactory,
required ConstructorEncodingStrategy encodingStrategy,
}) {
_encoding = encodingStrategy.createEncoding(isExternal: false);
_registerInferable(constructorBuilder);
}
@override
void becomeNative(SourceLoader loader) {
throw new UnsupportedError("$runtimeType.becomeNative()");
}
@override
// Coverage-ignore(suite): Not run.
bool get isNative => false;
@override
LookupScope get _typeParameterScope => _lookupScope;
@override
// Coverage-ignore(suite): Not run.
List<MetadataBuilder>? get metadata => null;
@override
List<SourceNominalParameterBuilder>? get _typeParameters => null;
@override
bool get isConst => true;
@override
bool get isExternal => false;
@override
void buildOutlineNodes(BuildNodesCallback f,
{required SourceConstructorBuilder constructorBuilder,
required SourceLibraryBuilder libraryBuilder,
required NameScheme nameScheme,
required ConstructorReferences? constructorReferences,
required List<DelayedDefaultValueCloner> delayedDefaultValueCloners}) {
_encoding.buildOutlineNodes(f,
constructorBuilder: constructorBuilder,
libraryBuilder: libraryBuilder,
declarationBuilder: constructorBuilder.declarationBuilder,
name: '',
nameScheme: nameScheme,
constructorReferences: constructorReferences,
fileUri: fileUri,
startOffset: fileOffset,
fileOffset: fileOffset,
formalsOffset: fileOffset,
endOffset: fileOffset,
isSynthetic: true,
forAbstractClassOrEnumOrMixin: true,
isConst: true,
returnType: returnType,
typeParameters: _typeParameters,
formals: formals,
delayedDefaultValueCloners: delayedDefaultValueCloners);
}
@override
void _buildMetadataForOutlineExpressions(
{required Iterable<Annotatable> annotatables,
required Uri annotatablesFileUri,
required SourceLibraryBuilder libraryBuilder,
required DeclarationBuilder declarationBuilder,
required SourceConstructorBuilder constructorBuilder,
required BodyBuilderContext bodyBuilderContext,
required ClassHierarchy classHierarchy}) {
// There is no metadata on a default enum constructor.
}
@override
void _buildTypeParametersAndFormalsForOutlineExpressions(
{required SourceLibraryBuilder libraryBuilder,
required DeclarationBuilder declarationBuilder,
required BodyBuilderContext bodyBuilderContext,
required ClassHierarchy classHierarchy}) {
_buildTypeParametersAndFormals(
libraryBuilder: libraryBuilder,
declarationBuilder: declarationBuilder,
bodyBuilderContext: bodyBuilderContext,
classHierarchy: classHierarchy,
typeParameterScope: _lookupScope);
}
@override
// Coverage-ignore(suite): Not run.
String? get _nativeMethodName => null;
}
class PrimaryConstructorDeclaration
with _ConstructorDeclarationMixin, _ConstructorEncodingMixin
implements
ConstructorDeclaration,
ConstructorFragmentDeclaration,
InferredTypeListener {
final PrimaryConstructorFragment _fragment;
late final List<FormalParameterBuilder>? _formals;
@override
late final List<SourceNominalParameterBuilder>? _typeParameters;
@override
late final ConstructorEncoding _encoding;
@override
Token? _beginInitializers;
PrimaryConstructorDeclaration(this._fragment)
: _beginInitializers = _fragment.beginInitializers {
_fragment.declaration = this;
}
@override
// Coverage-ignore(suite): Not run.
String? get _nativeMethodName => null;
@override
// Coverage-ignore(suite): Not run.
bool get isNative => false;
@override
void createEncoding({
required ProblemReporting problemReporting,
required SourceLoader loader,
required DeclarationBuilder declarationBuilder,
required SourceConstructorBuilder constructorBuilder,
required TypeParameterFactory typeParameterFactory,
required ConstructorEncodingStrategy encodingStrategy,
}) {
_fragment.builder = constructorBuilder;
_typeParameters = encodingStrategy.createTypeParameters(
declarationBuilder: declarationBuilder,
declarationTypeParameterFragments:
_fragment.enclosingDeclaration.typeParameters,
typeParameters: null,
typeParameterFactory: typeParameterFactory);
_fragment.typeParameterNameSpace.addTypeParameters(
problemReporting, _typeParameters,
ownerName: _fragment.name, allowNameConflict: true);
_formals = encodingStrategy.createFormals(
loader: loader,
formals: _fragment.formals,
fileUri: _fragment.fileUri,
fileOffset: _fragment.fileOffset);
_encoding = encodingStrategy.createEncoding(
isExternal: _fragment.modifiers.isExternal);
_registerInferable(constructorBuilder);
}
void _buildTypeParametersAndFormals({
required SourceLibraryBuilder libraryBuilder,
required DeclarationBuilder declarationBuilder,
required BodyBuilderContext bodyBuilderContext,
required ClassHierarchy classHierarchy,
required LookupScope typeParameterScope,
}) {
if (_typeParameters != null) {
for (int i = 0; i < _typeParameters!.length; i++) {
_typeParameters![i].buildOutlineExpressions(
libraryBuilder, bodyBuilderContext, classHierarchy);
}
}
if (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 formals!) {
formal.buildOutlineExpressions(libraryBuilder, declarationBuilder,
scope: typeParameterScope, buildDefaultValue: true);
}
}
}
@override
BodyBuilderContext createBodyBuilderContext(
SourceConstructorBuilder constructorBuilder) {
return _encoding.createBodyBuilderContext(constructorBuilder, this);
}
@override
void onInferredType(DartType type) {
function.returnType = type;
}
void _registerInferable(Inferable inferable) {
returnType.registerInferredTypeListener(this);
if (formals != null) {
for (FormalParameterBuilder formal in formals!) {
if (formal.isInitializingFormal ||
// Coverage-ignore(suite): Not run.
formal.isSuperInitializingFormal) {
formal.type.registerInferable(inferable);
}
}
}
}
@override
LookupScope get _typeParameterScope => _fragment.typeParameterScope;
@override
// Coverage-ignore(suite): Not run.
List<MetadataBuilder>? get metadata => null;
@override
OmittedTypeBuilder get returnType => _fragment.returnType;
@override
List<FormalParameterBuilder>? get formals => _formals;
@override
bool get isConst => _fragment.modifiers.isConst;
@override
bool get isExternal => _fragment.modifiers.isExternal;
@override
void buildOutlineNodes(BuildNodesCallback f,
{required SourceConstructorBuilder constructorBuilder,
required SourceLibraryBuilder libraryBuilder,
required NameScheme nameScheme,
required ConstructorReferences? constructorReferences,
required List<DelayedDefaultValueCloner> delayedDefaultValueCloners}) {
_encoding.buildOutlineNodes(f,
constructorBuilder: constructorBuilder,
libraryBuilder: libraryBuilder,
declarationBuilder: constructorBuilder.declarationBuilder
as SourceExtensionTypeDeclarationBuilder,
name: _fragment.name,
nameScheme: nameScheme,
constructorReferences: constructorReferences,
fileUri: _fragment.fileUri,
fileOffset: _fragment.fileOffset,
startOffset: _fragment.startOffset,
formalsOffset: _fragment.formalsOffset,
// TODO(johnniwinther): Provide `endOffset`.
endOffset: _fragment.formalsOffset,
forAbstractClassOrEnumOrMixin: _fragment.forAbstractClassOrMixin,
isConst: _fragment.modifiers.isConst,
isSynthetic: false,
returnType: returnType,
typeParameters: _typeParameters,
formals: formals,
delayedDefaultValueCloners: delayedDefaultValueCloners);
}
@override
void _buildMetadataForOutlineExpressions(
{required Iterable<Annotatable> annotatables,
required Uri annotatablesFileUri,
required SourceLibraryBuilder libraryBuilder,
required DeclarationBuilder declarationBuilder,
required SourceConstructorBuilder constructorBuilder,
required BodyBuilderContext bodyBuilderContext,
required ClassHierarchy classHierarchy}) {
// There is no metadata on a primary constructor.
}
@override
void _buildTypeParametersAndFormalsForOutlineExpressions(
{required SourceLibraryBuilder libraryBuilder,
required DeclarationBuilder declarationBuilder,
required BodyBuilderContext bodyBuilderContext,
required ClassHierarchy classHierarchy}) {
_buildTypeParametersAndFormals(
libraryBuilder: libraryBuilder,
declarationBuilder: declarationBuilder,
bodyBuilderContext: bodyBuilderContext,
classHierarchy: classHierarchy,
typeParameterScope: _fragment.typeParameterScope);
}
@override
int get fileOffset => _fragment.fileOffset;
@override
Uri get fileUri => _fragment.fileUri;
}
/// Interface for using a [ConstructorFragment] or [PrimaryConstructorFragment]
/// to create a [BodyBuilderContext].
abstract class ConstructorFragmentDeclaration {
int get fileOffset;
OmittedTypeBuilder get returnType;
List<FormalParameterBuilder>? get formals;
BodyBuilderContext createBodyBuilderContext(
SourceConstructorBuilder constructorBuilder);
FunctionNode get function;
void registerFunctionBody(Statement value);
void registerNoBodyConstructor();
VariableDeclaration? get thisVariable;
List<TypeParameter>? get thisTypeParameters;
void becomeNative(SourceLoader loader);
/// Returns the [VariableDeclaration] for the [index]th formal parameter
/// declared in the constructor.
///
/// The synthetic parameters of enum constructor are *not* included, so index
/// 0 zero of an enum constructor is the first user defined parameter.
VariableDeclaration getFormalParameter(int index);
/// Returns the [VariableDeclaration] for the tear off, if any, of the
/// [index]th formal parameter declared in the constructor.
VariableDeclaration? getTearOffParameter(int index);
FormalParameterBuilder? getFormal(Identifier identifier);
LocalScope computeFormalParameterScope(LookupScope parent);
LocalScope computeFormalParameterInitializerScope(LocalScope parent);
bool get isConst;
bool get isExternal;
bool get isNative;
}
mixin _SyntheticConstructorDeclarationMixin implements ConstructorDeclaration {
Constructor get _constructor;
Procedure? get _constructorTearOff;
@override
// Coverage-ignore(suite): Not run.
Uri get fileUri => _constructor.fileUri;
@override
FunctionNode get function => _constructor.function;
@override
// Coverage-ignore(suite): Not run.
bool get hasParameters =>
_constructor.function.positionalParameters.isNotEmpty ||
_constructor.function.namedParameters.isNotEmpty;
@override
bool get isExternal => false;
@override
bool get isRedirecting {
for (Initializer initializer in _constructor.initializers) {
if (initializer is RedirectingInitializer) {
return true;
}
}
return false;
}
@override
// Coverage-ignore(suite): Not run.
void markAsErroneous() {
_constructor.isErroneous = true;
}
@override
// Coverage-ignore(suite): Not run.
List<MetadataBuilder>? get metadata => null;
@override
void checkTypes(SourceLibraryBuilder libraryBuilder, NameSpace nameSpace,
TypeEnvironment typeEnvironment) {}
@override
// Coverage-ignore(suite): Not run.
int computeDefaultTypes(ComputeDefaultTypeContext context,
{required bool inErrorRecovery}) {
assert(false, "Unexpected call to $runtimeType.computeDefaultType");
return 0;
}
@override
void buildBody() {}
@override
void buildOutlineNodes(BuildNodesCallback f,
{required SourceConstructorBuilder constructorBuilder,
required SourceLibraryBuilder libraryBuilder,
required NameScheme nameScheme,
required ConstructorReferences? constructorReferences,
required List<DelayedDefaultValueCloner> delayedDefaultValueCloners}) {
f(
member: _constructor,
tearOff: _constructorTearOff,
kind: BuiltMemberKind.Constructor);
}
@override
List<Initializer> get initializers {
throw new UnsupportedError("Unexpected call to $runtimeType.initializers");
}
@override
void prepareInitializers() {
throw new UnsupportedError(
"Unexpected call to $runtimeType.prepareInitializers");
}
@override
void prependInitializer(Initializer initializer) {
throw new UnsupportedError(
"Unexpected call to $runtimeType.prependInitializer");
}
@override
// Coverage-ignore(suite): Not run.
Substitution computeFieldTypeSubstitution(
DeclarationBuilder declarationBuilder) {
return Substitution.empty;
}
}
class DefaultConstructorDeclaration
with _SyntheticConstructorDeclarationMixin
implements ConstructorDeclaration {
@override
final Constructor _constructor;
@override
final Procedure? _constructorTearOff;
DefaultConstructorDeclaration({
required Constructor constructor,
required Procedure? constructorTearOff,
}) : this._constructor = constructor,
this._constructorTearOff = constructorTearOff;
@override
// Coverage-ignore(suite): Not run.
void createEncoding({
required ProblemReporting problemReporting,
required SourceLoader loader,
required DeclarationBuilder declarationBuilder,
required SourceConstructorBuilder constructorBuilder,
required TypeParameterFactory typeParameterFactory,
required ConstructorEncodingStrategy encodingStrategy,
}) {}
@override
void addSuperParameterDefaultValueCloners(
SourceLibraryBuilder libraryBuilder,
DeclarationBuilder declarationBuilder,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {}
@override
void buildOutlineExpressions(
{required Iterable<Annotatable> annotatables,
required Uri annotatablesFileUri,
required SourceLibraryBuilder libraryBuilder,
required DeclarationBuilder declarationBuilder,
required SourceConstructorBuilder constructorBuilder,
required ClassHierarchy classHierarchy,
required List<DelayedDefaultValueCloner> delayedDefaultValueCloners}) {}
@override
void inferFormalTypes(
SourceLibraryBuilder libraryBuilder,
DeclarationBuilder declarationBuilder,
SourceConstructorBuilder constructorBuilder,
ClassHierarchyBase hierarchy,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {}
}
class ForwardingConstructorDeclaration
with _SyntheticConstructorDeclarationMixin
implements ConstructorDeclaration {
@override
final Constructor _constructor;
@override
final Procedure? _constructorTearOff;
/// The constructor from which this synthesized constructor is defined.
///
/// This defines the parameter structure and the default values of this
/// constructor.
///
/// The [_immediatelyDefiningConstructor] might itself a synthesized
/// constructor and [_effectivelyDefiningConstructor] can be used to find
/// the constructor that effectively defines this constructor.
MemberBuilder? _immediatelyDefiningConstructor;
DelayedDefaultValueCloner? _delayedDefaultValueCloner;
TypeDependency? _typeDependency;
ForwardingConstructorDeclaration({
required Constructor constructor,
required Procedure? constructorTearOff,
required MemberBuilder definingConstructor,
required DelayedDefaultValueCloner delayedDefaultValueCloner,
required TypeDependency? typeDependency,
}) : _constructor = constructor,
_constructorTearOff = constructorTearOff,
_immediatelyDefiningConstructor = definingConstructor,
_delayedDefaultValueCloner = delayedDefaultValueCloner,
_typeDependency = typeDependency;
@override
// Coverage-ignore(suite): Not run.
void createEncoding({
required ProblemReporting problemReporting,
required SourceLoader loader,
required DeclarationBuilder declarationBuilder,
required SourceConstructorBuilder constructorBuilder,
required TypeParameterFactory typeParameterFactory,
required ConstructorEncodingStrategy encodingStrategy,
}) {}
@override
void addSuperParameterDefaultValueCloners(
SourceLibraryBuilder libraryBuilder,
DeclarationBuilder declarationBuilder,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
MemberBuilder? origin = _immediatelyDefiningConstructor;
if (origin is SourceConstructorBuilder) {
origin.addSuperParameterDefaultValueCloners(delayedDefaultValueCloners);
}
if (_delayedDefaultValueCloner != null) {
// For constant constructors default values are computed and cloned part
// of the outline expression and we there set `isOutlineNode` to `true`
// below.
//
// For non-constant constructors default values are cloned as part of the
// full compilation using `KernelTarget._delayedDefaultValueCloners`.
delayedDefaultValueCloners
.add(_delayedDefaultValueCloner!..isOutlineNode = true);
_delayedDefaultValueCloner = null;
}
}
@override
void buildOutlineExpressions({
required Iterable<Annotatable> annotatables,
required Uri annotatablesFileUri,
required SourceLibraryBuilder libraryBuilder,
required DeclarationBuilder declarationBuilder,
required SourceConstructorBuilder constructorBuilder,
required ClassHierarchy classHierarchy,
required List<DelayedDefaultValueCloner> delayedDefaultValueCloners,
}) {
if (_immediatelyDefiningConstructor != null) {
// Ensure that default value expressions have been created for [_origin].
// If [_origin] is from a source library, we need to build the default
// values and initializers first.
MemberBuilder origin = _immediatelyDefiningConstructor!;
if (origin is SourceConstructorBuilder) {
origin.buildOutlineExpressions(
classHierarchy, delayedDefaultValueCloners);
}
addSuperParameterDefaultValueCloners(
libraryBuilder, declarationBuilder, delayedDefaultValueCloners);
_immediatelyDefiningConstructor = null;
}
}
@override
void inferFormalTypes(
SourceLibraryBuilder libraryBuilder,
DeclarationBuilder declarationBuilder,
SourceConstructorBuilder constructorBuilder,
ClassHierarchyBase hierarchy,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
if (_immediatelyDefiningConstructor is SourceConstructorBuilder) {
(_immediatelyDefiningConstructor as SourceConstructorBuilder)
.inferFormalTypes(hierarchy);
}
if (_typeDependency != null) {
_typeDependency!.copyInferred();
_typeDependency = null;
}
}
}