[cfe][Contexts][InternalNodes] Add internal nodes for FunctionNode, FunctionExpression and FunctionDeclaration

This adds internal nodes for FunctionNode, FunctionExpression and FunctionDeclaration which require InternalVariable rather than Variable. This is in preparation for using the new variable model by default.

Change-Id: I3c29954bcaae555c20b37e6a3ba1e70d959f1559
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/506941
Reviewed-by: Slava Egorov <vegorov@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Johnni Winther
2026-05-29 02:41:29 -07:00
committed by dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent 8c42f67d35
commit 02046380d1
15 changed files with 603 additions and 263 deletions
+75 -62
View File
@@ -145,77 +145,21 @@ class FunctionNode extends TreeNode implements ScopeProvider, ContextConsumer {
/// is useful in some contexts, especially when reasoning about the function
/// type of the enclosing generic function and in combination with
/// [FunctionType.withoutTypeParameters].
FunctionType computeThisFunctionType(
Nullability nullability, {
bool reuseTypeParameters = false,
}) {
FunctionType computeThisFunctionType(Nullability nullability) {
TreeNode? parent = this.parent;
List<StructuralParameter> structuralParameters;
List<TypeParameter> typeParametersToCopy = parent is Constructor
? parent.enclosingClass.typeParameters
: typeParameters;
DartType returnType;
List<DartType> positionalParameters;
List<NamedType> namedParameters;
if (typeParametersToCopy.isEmpty || reuseTypeParameters) {
structuralParameters = const <StructuralParameter>[];
returnType = this.returnType;
List<Variable> thisPositionals = this.positionalParameters;
positionalParameters = List.generate(
thisPositionals.length,
(index) => _getTypeOfVariable(thisPositionals[index]),
growable: false,
);
List<Variable> thisNamed = this.namedParameters;
if (thisNamed.isEmpty) {
namedParameters = const <NamedType>[];
} else {
namedParameters = List.generate(
thisNamed.length,
(index) => _getNamedTypeOfVariable(thisNamed[index]),
growable: false,
);
namedParameters.sort();
}
} else {
// We need create a copy of the list of type parameters, otherwise
// transformations like erasure don't work.
FreshStructuralParametersFromTypeParameters freshStructuralParameters =
getFreshStructuralParametersFromTypeParameters(typeParametersToCopy);
structuralParameters = freshStructuralParameters.freshTypeParameters;
Substitution substitution = freshStructuralParameters.substitution;
returnType = substitution.substituteType(this.returnType);
List<Variable> thisPositionals = this.positionalParameters;
positionalParameters = List.generate(
thisPositionals.length,
(index) => substitution.substituteType(
_getTypeOfVariable(thisPositionals[index]),
),
growable: false,
);
List<Variable> thisNamed = this.namedParameters;
if (thisNamed.isEmpty) {
namedParameters = const <NamedType>[];
} else {
namedParameters = List.generate(
thisNamed.length,
(index) => _getNamedTypeOfVariable(thisNamed[index], substitution),
growable: false,
);
namedParameters.sort();
}
}
// TODO(johnniwinther,cstefantsova): Cache the function type here and use
// [DartType.withDeclaredNullability] to handle the variants.
return new FunctionType(
positionalParameters,
returnType,
nullability,
return computeFunctionTypeFromData(
returnType: returnType,
typeParameters: typeParametersToCopy,
positionalParameters: positionalParameters,
namedParameters: namedParameters,
typeParameters: structuralParameters,
nullability: nullability,
requiredParameterCount: requiredParameterCount,
);
}
@@ -233,6 +177,75 @@ class FunctionNode extends TreeNode implements ScopeProvider, ContextConsumer {
return computeThisFunctionType(nullability);
}
static FunctionType computeFunctionTypeFromData({
required DartType returnType,
required List<TypeParameter> typeParameters,
required List<Variable> positionalParameters,
required List<Variable> namedParameters,
required Nullability nullability,
required int requiredParameterCount,
}) {
List<StructuralParameter> structuralParameters;
DartType functionReturnType;
List<DartType> positionalParameterTypes;
List<NamedType> namedParameterTypes;
if (typeParameters.isEmpty) {
structuralParameters = const <StructuralParameter>[];
functionReturnType = returnType;
positionalParameterTypes = List.generate(
positionalParameters.length,
(index) => _getTypeOfVariable(positionalParameters[index]),
growable: false,
);
if (namedParameters.isEmpty) {
namedParameterTypes = const <NamedType>[];
} else {
namedParameterTypes = List.generate(
namedParameters.length,
(index) => _getNamedTypeOfVariable(namedParameters[index]),
growable: false,
);
namedParameterTypes.sort();
}
} else {
// We need create a copy of the list of type parameters, otherwise
// transformations like erasure don't work.
FreshStructuralParametersFromTypeParameters freshStructuralParameters =
getFreshStructuralParametersFromTypeParameters(typeParameters);
structuralParameters = freshStructuralParameters.freshTypeParameters;
Substitution substitution = freshStructuralParameters.substitution;
functionReturnType = substitution.substituteType(returnType);
positionalParameterTypes = List.generate(
positionalParameters.length,
(index) => substitution.substituteType(
_getTypeOfVariable(positionalParameters[index]),
),
growable: false,
);
if (namedParameters.isEmpty) {
namedParameterTypes = const <NamedType>[];
} else {
namedParameterTypes = List.generate(
namedParameters.length,
(index) =>
_getNamedTypeOfVariable(namedParameters[index], substitution),
growable: false,
);
namedParameterTypes.sort();
}
}
return new FunctionType(
positionalParameterTypes,
functionReturnType,
nullability,
namedParameters: namedParameterTypes,
typeParameters: structuralParameters,
requiredParameterCount: requiredParameterCount,
);
}
@override
R accept<R>(TreeVisitor<R> v) => v.visitFunctionNode(this);