blob: 33aa5d1ad1aed633e24ce2f3f0c1af1af98c6fe3 [file] [log] [blame]
// Copyright (c) 2021, 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/fasta/kernel/kernel_api.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/type_algebra.dart';
import '../builder/member_builder.dart';
import '../source/source_library_builder.dart';
/// Creates the synthesized name to use for the lowering of a generative
/// constructor by the given [constructorName] in [library].
Name constructorTearOffName(String constructorName, Library library) {
return new Name(
'_#${constructorName.isEmpty ? 'new' : constructorName}#tearOff',
library);
}
/// Creates the [Procedure] for the lowering of a generative constructor of
/// the given [name] in [compilationUnit].
///
/// If constructor tear off lowering is not enabled, `null` is returned.
Procedure? createConstructorTearOffProcedure(
String name, SourceLibraryBuilder compilationUnit, int fileOffset,
{required bool forAbstractClassOrEnum}) {
if (!forAbstractClassOrEnum &&
compilationUnit
.loader.target.backendTarget.isConstructorTearOffLoweringEnabled) {
return new Procedure(constructorTearOffName(name, compilationUnit.library),
ProcedureKind.Method, new FunctionNode(null),
fileUri: compilationUnit.fileUri, isStatic: true)
..startFileOffset = fileOffset
..fileOffset = fileOffset
..fileEndOffset = fileOffset
..isNonNullableByDefault = compilationUnit.isNonNullableByDefault;
}
return null;
}
/// Creates the parameters and body for [tearOff] based on [constructor].
void buildConstructorTearOffProcedure(
Procedure tearOff,
Constructor constructor,
Class enclosingClass,
SourceLibraryBuilder libraryBuilder) {
int fileOffset = tearOff.fileOffset;
List<TypeParameter> classTypeParameters = enclosingClass.typeParameters;
List<TypeParameter> typeParameters;
List<DartType> typeArguments;
Substitution substitution = Substitution.empty;
if (classTypeParameters.isNotEmpty) {
FreshTypeParameters freshTypeParameters =
getFreshTypeParameters(classTypeParameters);
typeParameters = freshTypeParameters.freshTypeParameters;
typeArguments = freshTypeParameters.freshTypeArguments;
substitution = freshTypeParameters.substitution;
tearOff.function.typeParameters.addAll(typeParameters);
setParents(typeParameters, tearOff.function);
} else {
typeParameters = [];
typeArguments = [];
substitution = Substitution.empty;
}
List<Expression> positionalArguments = [];
for (VariableDeclaration constructorParameter
in constructor.function.positionalParameters) {
VariableDeclaration tearOffParameter = new VariableDeclaration(
constructorParameter.name,
type: substitution.substituteType(constructorParameter.type))
..fileOffset = constructorParameter.fileOffset;
tearOff.function.positionalParameters.add(tearOffParameter);
positionalArguments
.add(new VariableGet(tearOffParameter)..fileOffset = fileOffset);
tearOffParameter.parent = tearOff.function;
}
List<NamedExpression> namedArguments = [];
for (VariableDeclaration constructorParameter
in constructor.function.namedParameters) {
VariableDeclaration tearOffParameter = new VariableDeclaration(
constructorParameter.name,
type: substitution.substituteType(constructorParameter.type),
isRequired: constructorParameter.isRequired)
..fileOffset = constructorParameter.fileOffset;
tearOff.function.namedParameters.add(tearOffParameter);
tearOffParameter.parent = tearOff.function;
namedArguments.add(new NamedExpression(tearOffParameter.name!,
new VariableGet(tearOffParameter)..fileOffset = fileOffset)
..fileOffset = fileOffset);
}
tearOff.function.returnType =
substitution.substituteType(constructor.function.returnType);
tearOff.function.requiredParameterCount =
constructor.function.requiredParameterCount;
tearOff.function.body = new ReturnStatement(
new ConstructorInvocation(
constructor,
new Arguments(positionalArguments,
named: namedArguments, types: typeArguments)
..fileOffset = tearOff.fileOffset)
..fileOffset = tearOff.fileOffset)
..fileOffset = tearOff.fileOffset
..parent = tearOff.function;
tearOff.function.fileOffset = tearOff.fileOffset;
tearOff.function.fileEndOffset = tearOff.fileOffset;
updatePrivateMemberName(tearOff, libraryBuilder);
}
/// Copies the parameter types from [constructor] to [tearOff].
///
/// These might have been inferred and therefore not available when the
/// parameters were created.
// TODO(johnniwinther): Add tests for inferred parameter types.
// TODO(johnniwinther): Avoid doing this when parameter types are not inferred.
void buildConstructorTearOffOutline(
Procedure tearOff, Constructor constructor, Class enclosingClass) {
List<TypeParameter> classTypeParameters = enclosingClass.typeParameters;
Substitution substitution = Substitution.empty;
if (classTypeParameters.isNotEmpty) {
List<DartType> typeArguments = [];
for (TypeParameter typeParameter in tearOff.function.typeParameters) {
typeArguments.add(new TypeParameterType(typeParameter,
TypeParameterType.computeNullabilityFromBound(typeParameter)));
}
substitution = Substitution.fromPairs(classTypeParameters, typeArguments);
}
for (int i = 0; i < constructor.function.positionalParameters.length; i++) {
VariableDeclaration tearOffParameter =
tearOff.function.positionalParameters[i];
VariableDeclaration constructorParameter =
constructor.function.positionalParameters[i];
tearOffParameter.type =
substitution.substituteType(constructorParameter.type);
}
for (int i = 0; i < constructor.function.namedParameters.length; i++) {
VariableDeclaration tearOffParameter = tearOff.function.namedParameters[i];
VariableDeclaration constructorParameter =
constructor.function.namedParameters[i];
tearOffParameter.type =
substitution.substituteType(constructorParameter.type);
}
}
void buildConstructorTearOffDefaultValues(
Procedure tearOff, Constructor constructor, Class enclosingClass) {
CloneVisitorNotMembers cloner = new CloneVisitorNotMembers();
for (int i = 0; i < constructor.function.positionalParameters.length; i++) {
VariableDeclaration tearOffParameter =
tearOff.function.positionalParameters[i];
VariableDeclaration constructorParameter =
constructor.function.positionalParameters[i];
tearOffParameter.initializer =
cloner.cloneOptional(constructorParameter.initializer);
tearOffParameter.initializer?.parent = tearOffParameter;
}
for (int i = 0; i < constructor.function.namedParameters.length; i++) {
VariableDeclaration tearOffParameter = tearOff.function.namedParameters[i];
VariableDeclaration constructorParameter =
constructor.function.namedParameters[i];
tearOffParameter.initializer =
cloner.cloneOptional(constructorParameter.initializer);
tearOffParameter.initializer?.parent = tearOffParameter;
}
}