blob: 86f8a683b7e64c4bd9cfac15c783129d34965b29 [file] [log] [blame]
// 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.
import "package:kernel/ast.dart"
show
BottomType,
Class,
DartType,
DynamicType,
FunctionType,
InterfaceType,
Library,
NamedType,
Node,
Supertype,
TreeNode,
TypeParameter,
TypeParameterType,
Typedef,
TypedefType,
VoidType,
setParents;
import "package:kernel/src/bounds_checks.dart" show calculateBounds;
import "type_parser.dart" as type_parser show parse;
import "type_parser.dart"
show
ParsedClass,
ParsedIntersectionType,
ParsedFunctionType,
ParsedInterfaceType,
ParsedType,
ParsedTypeVariable,
ParsedTypedef,
ParsedVoidType,
Visitor;
Library parseLibrary(Uri uri, String text,
{Uri fileUri, KernelEnvironment environment}) {
fileUri ??= uri;
environment ??= new KernelEnvironment(uri, fileUri);
Library library =
new Library(uri, fileUri: fileUri, name: uri.path.replaceAll("/", "."));
for (ParsedType type in type_parser.parse(text)) {
Node node = environment.kernelFromParsedType(type);
if (node is Class) {
library.addClass(node);
} else if (node is Typedef) {
library.addTypedef(node);
} else {
throw "Unsupported: $node";
}
}
return library;
}
class KernelEnvironment {
final Uri uri;
final Uri fileUri;
final Map<String, TreeNode> declarations = <String, TreeNode>{};
KernelEnvironment(this.uri, this.fileUri);
Node kernelFromParsedType(ParsedType type) {
Node node = type.accept(const KernelFromParsedType(), this);
return node;
}
bool isObject(String name) => name == "Object" && "$uri" == "dart:core";
Class get objectClass => this["Object"];
TreeNode operator [](String name) {
return declarations[name] ?? (throw "Not found: $name");
}
void operator []=(String name, TreeNode declaration) {
TreeNode existing = declarations[name];
if (existing != null) {
throw "Duplicated declaration: $name";
}
declarations[name] = declaration;
}
KernelEnvironment extend(Map<String, TreeNode> declarations) {
return new KernelEnvironment(uri, fileUri)
..declarations.addAll(this.declarations)
..declarations.addAll(declarations);
}
}
class KernelFromParsedType implements Visitor<Node, KernelEnvironment> {
const KernelFromParsedType();
DartType visitInterfaceType(
ParsedInterfaceType node, KernelEnvironment environment) {
String name = node.name;
if (name == "dynamic") {
// Don't return a const object to ensure we test implementations that use
// identical.
return new DynamicType();
} else if (name == "void") {
// Don't return a const object to ensure we test implementations that use
// identical.
return new VoidType();
} else if (name == "bottom") {
// Don't return a const object to ensure we test implementations that use
// identical.
return new BottomType();
}
TreeNode declaration = environment[name];
List<ParsedType> arguments = node.arguments;
List<DartType> kernelArguments =
new List<DartType>.filled(arguments.length, null);
for (int i = 0; i < arguments.length; i++) {
kernelArguments[i] =
arguments[i].accept<Node, KernelEnvironment>(this, environment);
}
if (declaration is Class) {
List<TypeParameter> typeVariables = declaration.typeParameters;
if (kernelArguments.isEmpty && typeVariables.isNotEmpty) {
kernelArguments = new List<DartType>.filled(typeVariables.length, null);
for (int i = 0; i < typeVariables.length; i++) {
kernelArguments[i] = typeVariables[i].defaultType;
}
} else if (kernelArguments.length != typeVariables.length) {
throw "Expected ${typeVariables.length} type arguments: $node";
}
return new InterfaceType(declaration, kernelArguments);
} else if (declaration is TypeParameter) {
if (arguments.isNotEmpty) {
throw "Type variable can't have arguments (${node.name})";
}
return new TypeParameterType(declaration);
} else if (declaration is Typedef) {
return new TypedefType(declaration, kernelArguments);
} else {
throw "Unhandled ${declaration.runtimeType}";
}
}
Class visitClass(ParsedClass node, KernelEnvironment environment) {
String name = node.name;
Class cls =
environment[name] = new Class(fileUri: environment.fileUri, name: name);
ParameterEnvironment parameterEnvironment =
computeTypeParameterEnvironment(node.typeVariables, environment);
List<TypeParameter> parameters = parameterEnvironment.parameters;
setParents(parameters, cls);
cls.typeParameters.addAll(parameters);
{
KernelEnvironment environment = parameterEnvironment.environment;
InterfaceType type =
node.supertype?.accept<Node, KernelEnvironment>(this, environment);
if (type == null) {
if (!environment.isObject(name)) {
cls.supertype = environment.objectClass.asRawSupertype;
}
} else {
cls.supertype = toSupertype(type);
}
List<ParsedType> interfaces = node.interfaces;
for (int i = 0; i < interfaces.length; i++) {
cls.implementedTypes.add(toSupertype(
interfaces[i].accept<Node, KernelEnvironment>(this, environment)));
}
}
return cls;
}
Typedef visitTypedef(ParsedTypedef node, KernelEnvironment environment) {
String name = node.name;
Typedef def = environment[name] =
new Typedef(name, null, fileUri: environment.fileUri);
ParameterEnvironment parameterEnvironment =
computeTypeParameterEnvironment(node.typeVariables, environment);
def.typeParameters.addAll(parameterEnvironment.parameters);
DartType type;
{
KernelEnvironment environment = parameterEnvironment.environment;
type = node.type.accept<Node, KernelEnvironment>(this, environment);
if (type is FunctionType) {
FunctionType f = type;
type = new FunctionType(f.positionalParameters, f.returnType,
namedParameters: f.namedParameters,
typeParameters: f.typeParameters,
requiredParameterCount: f.requiredParameterCount,
typedefType: def.thisType);
}
}
return def..type = type;
}
FunctionType visitFunctionType(
ParsedFunctionType node, KernelEnvironment environment) {
ParameterEnvironment parameterEnvironment =
computeTypeParameterEnvironment(node.typeVariables, environment);
List<DartType> positionalParameters = <DartType>[];
List<NamedType> namedParameters = <NamedType>[];
DartType returnType;
{
KernelEnvironment environment = parameterEnvironment.environment;
returnType =
node.returnType?.accept<Node, KernelEnvironment>(this, environment);
for (ParsedType argument in node.arguments.required) {
positionalParameters
.add(argument.accept<Node, KernelEnvironment>(this, environment));
}
List<Object> optional = node.arguments.optional;
for (int i = 0; i < optional.length; i++) {
ParsedType parsedType = optional[i];
DartType type =
parsedType.accept<Node, KernelEnvironment>(this, environment);
if (node.arguments.optionalAreNamed) {
namedParameters.add(new NamedType(optional[++i], type));
} else {
positionalParameters.add(type);
}
}
}
namedParameters.sort();
return new FunctionType(positionalParameters, returnType,
namedParameters: namedParameters,
requiredParameterCount: node.arguments.required.length,
typeParameters: parameterEnvironment.parameters);
}
VoidType visitVoidType(ParsedVoidType node, KernelEnvironment environment) {
return const VoidType();
}
TypeParameter visitTypeVariable(
ParsedTypeVariable node, KernelEnvironment environment) {
throw "not implemented: $node";
}
TypeParameterType visitIntersectionType(
ParsedIntersectionType node, KernelEnvironment environment) {
TypeParameterType type =
node.a.accept<Node, KernelEnvironment>(this, environment);
DartType bound = node.b.accept<Node, KernelEnvironment>(this, environment);
return new TypeParameterType(type.parameter, bound);
}
Supertype toSupertype(InterfaceType type) {
return new Supertype.byReference(type.className, type.typeArguments);
}
ParameterEnvironment computeTypeParameterEnvironment(
List<ParsedTypeVariable> typeVariables, KernelEnvironment environment) {
List<TypeParameter> typeParameters =
new List<TypeParameter>.filled(typeVariables.length, null);
Map<String, TypeParameter> typeParametersByName = <String, TypeParameter>{};
for (int i = 0; i < typeVariables.length; i++) {
String name = typeVariables[i].name;
typeParametersByName[name] = typeParameters[i] = new TypeParameter(name);
}
KernelEnvironment nestedEnvironment =
environment.extend(typeParametersByName);
Class objectClass = environment.objectClass;
for (int i = 0; i < typeVariables.length; i++) {
ParsedType bound = typeVariables[i].bound;
TypeParameter typeParameter = typeParameters[i];
if (bound == null) {
typeParameter
..bound = objectClass.rawType
..defaultType = const DynamicType();
} else {
DartType type =
bound.accept<Node, KernelEnvironment>(this, nestedEnvironment);
typeParameter
..bound = type
// The default type will be overridden below, but we need to set it
// so [calculateBounds] can destinquish between explicit and implicit
// bounds.
..defaultType = type;
}
}
List<DartType> defaultTypes = calculateBounds(typeParameters, objectClass);
for (int i = 0; i < typeParameters.length; i++) {
typeParameters[i].defaultType = defaultTypes[i];
}
return new ParameterEnvironment(typeParameters, nestedEnvironment);
}
}
class ParameterEnvironment {
final List<TypeParameter> parameters;
final KernelEnvironment environment;
const ParameterEnvironment(this.parameters, this.environment);
}