Files
sdk/pkg/front_end/tool/_fasta/bench_maker.dart
T
Chloe Stefantsova de302d7f3b [cfe] Introduce StructuralParameters
This CL introduces StructuralParameter and StructuralParameterType
classes. They are intended to replace TypeParameter and
TypeParameterType respectively where those were used as type
parameters defined by FunctionTypes. Previously, type parameters of
FunctionTypes were represented by TypeParameter objects with the
‘parent’ field set to null. By introducing StructuralParameter and
StructuralParameterType this CL unambiguously separates the two
notions of type parameters.

TEST=existing

Change-Id: Ida3feb7ad96a7b2acef55840eacba9e36bf2a3e7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/312264
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Commit-Queue: Chloe Stefantsova <cstefantsova@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Mayank Patke <fishythefish@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
2023-09-25 10:44:41 +00:00

445 lines
12 KiB
Dart

// Copyright (c) 2019, 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.
library fasta.tool.entry_points;
import "dart:convert" show JsonEncoder;
import "dart:io" show File;
import "package:kernel/ast.dart";
import "package:front_end/src/fasta/type_inference/type_schema.dart"
show UnknownType;
String jsonEncode(Object object) {
return const JsonEncoder.withIndent(" ").convert(object);
}
Iterable<String> nameGenerator() sync* {
int i = 0;
while (true) {
List<int> characters = <int>[];
int j = i;
while (j > 25) {
int c = j % 26;
j = (j ~/ 26) - 1;
characters.add(c + 65);
}
characters.add(j + 65);
yield new String.fromCharCodes(characters.reversed);
i++;
}
}
class BenchMaker implements DartTypeVisitor1<void, StringBuffer> {
final List<Object> checks = <Object>[];
final Map<TreeNode, String> nodeNames = <TreeNode, String>{};
final Map<StructuralParameter, String> structuralParameterNames =
<StructuralParameter, String>{};
final Set<String> usedNames = new Set<String>();
final Iterator<String> names = nameGenerator().iterator..moveNext();
final List<String> classes = <String>[];
final List<TypeParameter> usedTypeParameters = <TypeParameter>[];
String serializeTypeChecks(List<Object> typeChecks) {
for (Object list in typeChecks) {
List<Object> typeCheck = list as List<Object>;
writeTypeCheck(typeCheck[0] as DartType, typeCheck[1] as DartType,
typeCheck[2] as bool);
}
writeClasses();
return jsonEncode(this);
}
void writeTypeCheck(DartType s, DartType t, bool expected) {
assert(usedTypeParameters.isEmpty);
usedTypeParameters.clear();
StringBuffer sb = new StringBuffer();
s.accept1(this, sb);
String sString = "$sb";
sb.clear();
t.accept1(this, sb);
String tString = "$sb";
List<Object> arguments = <Object>[sString, tString];
Set<TypeParameter> seenTypeParameters = new Set<TypeParameter>();
List<String> parameterStrings = <String>[];
while (usedTypeParameters.isNotEmpty) {
List<TypeParameter> typeParameters = usedTypeParameters.toList();
usedTypeParameters.clear();
for (TypeParameter parameter in typeParameters) {
if (seenTypeParameters.add(parameter)) {
sb.clear();
writeTypeParameter(parameter, sb);
parameterStrings.add("$sb");
}
}
}
if (parameterStrings.isNotEmpty) {
arguments.add(parameterStrings);
}
checks.add(<String, dynamic>{
"kind": expected ? "isSubtype" : "isNotSubtype",
"arguments": arguments,
});
}
void writeTypeParameter(TypeParameter parameter, StringBuffer sb) {
sb.write(computeName(parameter));
DartType bound = parameter.bound;
DartType defaultType = parameter.defaultType;
bool hasExplicitBound = true;
if (bound is InterfaceType && defaultType is DynamicType) {
if (bound.classNode.supertype == null) {
hasExplicitBound = false;
}
}
if (hasExplicitBound) {
sb.write(" extends ");
bound.accept1(this, sb);
}
}
void writeStructuralParameter(
StructuralParameter parameter, StringBuffer sb) {
sb.write(computeStructuralParameterName(parameter));
DartType bound = parameter.bound;
DartType defaultType = parameter.defaultType;
bool hasExplicitBound = true;
if (bound is InterfaceType && defaultType is DynamicType) {
if (bound.classNode.supertype == null) {
hasExplicitBound = false;
}
}
if (hasExplicitBound) {
sb.write(" extends ");
bound.accept1(this, sb);
}
}
void writeTypeParameters(
List<TypeParameter> typeParameters, StringBuffer sb) {
if (typeParameters.isNotEmpty) {
sb.write("<");
bool first = true;
for (TypeParameter p in typeParameters) {
if (!first) sb.write(", ");
writeTypeParameter(p, sb);
first = false;
}
sb.write(">");
}
}
void writeStructuralParameters(
List<StructuralParameter> typeParameters, StringBuffer sb) {
if (typeParameters.isNotEmpty) {
sb.write("<");
bool first = true;
for (StructuralParameter p in typeParameters) {
if (!first) sb.write(", ");
writeStructuralParameter(p, sb);
first = false;
}
sb.write(">");
}
}
void writeClasses() {
Set<Class> writtenClasses = new Set<Class>();
int index = 0;
List<TreeNode> nodes = nodeNames.keys.toList();
while (index < nodes.length) {
for (; index < nodes.length; index++) {
TreeNode node = nodes[index];
if (node is Class) {
writeClass(node, writtenClasses);
}
}
nodes = nodeNames.keys.toList();
}
}
void writeClass(Class? cls, Set<Class> writtenClasses) {
if (cls == null || !writtenClasses.add(cls)) return;
Supertype? supertype = cls.supertype;
writeClass(supertype?.classNode, writtenClasses);
Supertype? mixedInType = cls.mixedInType;
writeClass(mixedInType?.classNode, writtenClasses);
for (Supertype implementedType in cls.implementedTypes) {
writeClass(implementedType.classNode, writtenClasses);
}
StringBuffer sb = new StringBuffer();
sb.write("class ");
sb.write(computeName(cls));
writeTypeParameters(cls.typeParameters, sb);
if (supertype != null) {
sb.write(" extends ");
supertype.asInterfaceType.accept1(this, sb);
}
if (mixedInType != null) {
sb.write(" with ");
mixedInType.asInterfaceType.accept1(this, sb);
}
bool first = true;
for (Supertype implementedType in cls.implementedTypes) {
if (first) {
sb.write(" implements ");
} else {
sb.write(", ");
}
implementedType.asInterfaceType.accept1(this, sb);
first = false;
}
Procedure? callOperator;
for (Procedure procedure in cls.procedures) {
if (procedure.name.text == "call") {
callOperator = procedure;
}
}
if (callOperator != null) {
sb.write("{ ");
callOperator.function
.computeFunctionType(cls.enclosingLibrary.nonNullable)
.accept1(this, sb);
sb.write(" }");
} else {
sb.write(";");
}
classes.add("$sb");
}
String computeName(TreeNode node) {
String? name = nodeNames[node];
if (name != null) return name;
if (node is Class) {
Library library = node.enclosingLibrary;
String uriString = "${library.importUri}";
if (uriString == "dart:core" || uriString == "dart:async") {
if (!usedNames.add(node.name)) {
throw "Class name conflict for $node";
}
return nodeNames[node] = node.name;
}
}
while (!usedNames.add(name = names.current)) {
names.moveNext();
}
names.moveNext();
return nodeNames[node] = name;
}
String computeStructuralParameterName(StructuralParameter node) {
String? name = structuralParameterNames[node];
if (name != null) return name;
while (!usedNames.add(name = names.current)) {
names.moveNext();
}
names.moveNext();
return structuralParameterNames[node] = name;
}
void writeNullability(Nullability nullability, StringBuffer sb) {
switch (nullability) {
case Nullability.nullable:
sb.write("?");
break;
case Nullability.legacy:
sb.write("*");
break;
case Nullability.undetermined:
sb.write("%");
break;
case Nullability.nonNullable:
default:
break;
}
}
@override
void visitAuxiliaryType(AuxiliaryType node, StringBuffer sb) {
if (node is UnknownType) {
sb.write("?");
} else {
throw "Unsupported auxiliary type ${node} (${node.runtimeType}).";
}
}
@override
void visitInvalidType(InvalidType node, StringBuffer sb) {
throw "not implemented";
}
@override
void visitDynamicType(DynamicType node, StringBuffer sb) {
sb.write("dynamic");
}
@override
void visitVoidType(VoidType node, StringBuffer sb) {
sb.write("void");
}
@override
void visitNeverType(NeverType node, StringBuffer sb) {
sb.write("Never");
writeNullability(node.nullability, sb);
}
@override
void visitNullType(NullType node, StringBuffer sb) {
sb.write("Null");
}
@override
void visitInterfaceType(InterfaceType node, StringBuffer sb) {
Class cls = node.classNode;
sb.write(computeName(cls));
if (node.typeArguments.isNotEmpty) {
sb.write("<");
bool first = true;
for (DartType type in node.typeArguments) {
if (!first) sb.write(", ");
type.accept1(this, sb);
first = false;
}
sb.write(">");
}
Uri clsImportUri = cls.enclosingLibrary.importUri;
bool isNull = cls.name == "Null" &&
clsImportUri.isScheme("dart") &&
clsImportUri.path == "core";
if (!isNull) {
writeNullability(node.nullability, sb);
}
}
@override
void visitFutureOrType(FutureOrType node, StringBuffer sb) {
sb.write("FutureOr<");
node.typeArgument.accept1(this, sb);
sb.write(">");
writeNullability(node.declaredNullability, sb);
}
@override
void visitFunctionType(FunctionType node, StringBuffer sb) {
writeStructuralParameters(node.typeParameters, sb);
sb.write("(");
bool first = true;
for (int i = 0; i < node.requiredParameterCount; i++) {
if (!first) sb.write(", ");
node.positionalParameters[i].accept1(this, sb);
first = false;
}
if (node.requiredParameterCount != node.positionalParameters.length) {
if (!first) sb.write(", ");
sb.write("[");
first = true;
for (int i = node.requiredParameterCount;
i < node.positionalParameters.length;
i++) {
if (!first) sb.write(", ");
node.positionalParameters[i].accept1(this, sb);
first = false;
}
sb.write("]");
first = false;
}
if (node.namedParameters.isNotEmpty) {
if (!first) sb.write(", ");
sb.write("{");
first = true;
for (NamedType named in node.namedParameters) {
if (!first) sb.write(", ");
named.type.accept1(this, sb);
sb.write(" ");
sb.write(named.name);
first = false;
}
sb.write("}");
first = false;
}
sb.write(") ->");
writeNullability(node.nullability, sb);
sb.write(" ");
node.returnType.accept1(this, sb);
}
@override
void visitRecordType(RecordType node, StringBuffer sb) {
sb.write("(");
bool first = true;
for (int i = 0; i < node.positional.length; i++) {
if (!first) sb.write(", ");
node.positional[i].accept1(this, sb);
first = false;
}
if (node.named.isNotEmpty) {
if (!first) sb.write(", ");
sb.write("{");
first = true;
for (NamedType named in node.named) {
if (!first) sb.write(", ");
named.type.accept1(this, sb);
sb.write(" ");
sb.write(named.name);
first = false;
}
sb.write("}");
first = false;
}
sb.write(")");
writeNullability(node.nullability, sb);
}
@override
void visitTypeParameterType(TypeParameterType node, StringBuffer sb) {
String name = computeName(node.parameter);
usedTypeParameters.add(node.parameter);
sb.write(name);
}
@override
void visitStructuralParameterType(
StructuralParameterType node, StringBuffer sb) {
throw "not implemented";
}
@override
void visitIntersectionType(IntersectionType node, StringBuffer sb) {
node.left.accept1(this, sb);
sb.write(" & ");
node.right.accept1(this, sb);
}
@override
void visitTypedefType(TypedefType node, StringBuffer sb) {
throw "not implemented";
}
@override
void visitExtensionType(ExtensionType node, StringBuffer sb) {
throw "not implemented";
}
Map<String, dynamic> toJson() {
return <String, dynamic>{
"classes": classes,
"checks": checks,
};
}
static void writeTypeChecks(String filename, List<Object> typeChecks) {
new File(filename)
.writeAsString(new BenchMaker().serializeTypeChecks(typeChecks));
}
}