Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(674)

Unified Diff: pkg/compiler/lib/src/kernel/kernel.dart

Issue 2265383002: Copy Rasta visitor to dart2js. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: missed some renames Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/compiler/lib/src/kernel/kernel.dart
diff --git a/pkg/compiler/lib/src/kernel/kernel.dart b/pkg/compiler/lib/src/kernel/kernel.dart
new file mode 100644
index 0000000000000000000000000000000000000000..34ac4f82d8607ca3d03d00669f57ef04c10a235b
--- /dev/null
+++ b/pkg/compiler/lib/src/kernel/kernel.dart
@@ -0,0 +1,584 @@
+// Copyright (c) 2016, 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.md file.
+
+import 'dart:collection' show Queue;
+
+import 'package:kernel/ast.dart' as ir;
+import 'package:kernel/checks.dart' show CheckParentPointers;
+import 'package:kernel/frontend/super_calls.dart' show moveSuperCallLast;
+
+import '../compiler.dart' show Compiler;
+import '../constants/expressions.dart' show TypeConstantExpression;
+import '../dart_types.dart'
+ show DartType, FunctionType, InterfaceType, TypeKind, TypeVariableType;
+import '../diagnostics/messages.dart' show MessageKind;
+import '../diagnostics/spannable.dart' show Spannable;
+import '../elements/elements.dart'
+ show
+ ClassElement,
+ ConstructorElement,
+ Element,
+ FieldElement,
+ FunctionElement,
+ LibraryElement,
+ MixinApplicationElement,
+ TypeVariableElement;
+import '../elements/modelx.dart' show ErroneousFieldElementX;
+import '../tree/tree.dart' show FunctionExpression, Node;
+import 'kernel_visitor.dart' show IrFunction, KernelVisitor;
+
+typedef void WorkAction();
+
+class WorkItem {
+ final Element element;
+ final WorkAction action;
+
+ WorkItem(this.element, this.action);
+}
+
+class Kernel {
+ final Compiler compiler;
+
+ final Map<LibraryElement, ir.Library> libraries =
+ <LibraryElement, ir.Library>{};
+
+ final Map<ClassElement, ir.Class> classes = <ClassElement, ir.Class>{};
+
+ final Map<FunctionElement, ir.Member> functions =
+ <FunctionElement, ir.Member>{};
+
+ final Map<FieldElement, ir.Field> fields = <FieldElement, ir.Field>{};
+
+ final Map<TypeVariableElement, ir.TypeParameter> typeParameters =
+ <TypeVariableElement, ir.TypeParameter>{};
+
+ final Map<TypeVariableElement, ir.TypeParameter> factoryTypeParameters =
+ <TypeVariableElement, ir.TypeParameter>{};
+
+ final Set<ir.TreeNode> checkedNodes = new Set<ir.TreeNode>();
+
+ final Map<LibraryElement, Map<String, int>> mixinApplicationNamesByLibrary =
+ <LibraryElement, Map<String, int>>{};
+
+ /// FIFO queue of work that needs to be completed before the returned AST
+ /// nodes are correct.
+ final Queue<WorkItem> workQueue = new Queue<WorkItem>();
+
+ Kernel(this.compiler);
+
+ void addWork(Element element, WorkAction action) {
+ workQueue.addLast(new WorkItem(element, action));
+ }
+
+ void checkMember(Element key, ir.TreeNode value) {
+ if (!checkedNodes.add(value)) return;
+ if (value.parent == null) {
+ internalError(key, "Missing parent on IR node.");
+ }
+ try {
+ CheckParentPointers.check(value);
+ } catch (e, s) {
+ internalError(key, "$e\n$s");
+ }
+ }
+
+ void checkLibrary(Element key, ir.Library library) {
+ if (!checkedNodes.add(library)) return;
+ CheckParentPointers.check(library);
+ }
+
+ void processWorkQueue() {
+ while (workQueue.isNotEmpty) {
+ WorkItem work = workQueue.removeFirst();
+ work.action();
+ }
+ assert(() {
+ libraries.forEach(checkLibrary);
+ classes.forEach(checkMember);
+ functions.forEach(checkMember);
+ fields.forEach(checkMember);
+ return true;
+ });
+ }
+
+ ir.Name irName(String name, Element element) {
+ ir.Library irLibrary = null;
+ if (name.startsWith("_")) {
+ ClassElement cls = element.enclosingClass;
+ if (cls != null && cls.isMixinApplication) {
+ MixinApplicationElement mixinApplication = cls;
+ element = mixinApplication.mixin;
+ }
+ irLibrary = libraryToIr(element.library);
+ }
+ return new ir.Name(name, irLibrary);
+ }
+
+ ir.Library libraryToIr(LibraryElement library) {
+ library = library.declaration;
+ return libraries.putIfAbsent(library, () {
+ String name = library.hasLibraryName ? library.libraryName : null;
+ ir.Library libraryNode = new ir.Library(library.canonicalUri,
+ name: name, classes: null, procedures: null, fields: null);
+ addWork(library, () {
+ Queue<ir.Class> classes = new Queue<ir.Class>();
+ Queue<ir.Member> members = new Queue<ir.Member>();
+ library.implementation.forEachLocalMember((Element e) {
+ if (e.isClass) {
+ classes.addFirst(classToIr(e));
+ } else if (e.isFunction || e.isAccessor) {
+ members.addFirst(functionToIr(e));
+ } else if (e.isField) {
+ members.addFirst(fieldToIr(e));
+ } else if (e.isTypedef) {
+ // Ignored, typedefs are unaliased on use.
+ } else {
+ internalError(e, "Unhandled library member: $e");
+ }
+ });
+ // The elements were inserted in reverse order as forEachLocalMember
+ // above gives them in reversed order.
+ classes.forEach(libraryNode.addClass);
+ members.forEach(libraryNode.addMember);
+ });
+ return libraryNode;
+ });
+ }
+
+ /// Compute a name for [cls]. We want to have unique names in a library, but
+ /// mixin applications can lead to multiple classes with the same name. So
+ /// for those we append `#` and a number.
+ String computeName(ClassElement cls) {
+ String name = cls.name;
+ if (!cls.isUnnamedMixinApplication) return name;
+ Map<String, int> mixinApplicationNames = mixinApplicationNamesByLibrary
+ .putIfAbsent(cls.library.implementation, () => <String, int>{});
+ int count = mixinApplicationNames.putIfAbsent(name, () => 0);
+ mixinApplicationNames[name] = count + 1;
+ return "$name#$count";
+ }
+
+ ir.Class classToIr(ClassElement cls) {
+ cls = cls.declaration;
+ return classes.putIfAbsent(cls, () {
+ String name = computeName(cls);
+ ir.Class classNode = new ir.Class(
+ name: name,
+ isAbstract: cls.isAbstract,
+ typeParameters: null,
+ implementedTypes: null,
+ constructors: null,
+ procedures: null,
+ fields: null);
+ addWork(cls, () {
+ if (cls.supertype != null) {
+ classNode.supertype = interfaceTypeToIr(cls.supertype);
+ }
+ classNode.parent = libraryToIr(cls.library);
+ if (cls.isUnnamedMixinApplication) {
+ classNode.enclosingLibrary.addClass(classNode);
+ }
+ cls.implementation
+ .forEachMember((ClassElement enclosingClass, Element member) {
+ if (member.enclosingClass.declaration != cls) {
+ internalError(cls, "`$member` isn't mine.");
+ } else if (member.isFunction ||
+ member.isAccessor ||
+ member.isConstructor) {
+ classNode.addMember(functionToIr(member));
+ } else if (member.isField) {
+ classNode.addMember(fieldToIr(member));
+ } else {
+ internalError(member, "Unhandled class member: $member");
+ }
+ });
+ classNode.typeParameters.addAll(typeVariablesToIr(cls.typeVariables));
+ for (ir.InterfaceType interface in typesToIr(cls.interfaces.toList())) {
+ classNode.implementedTypes.add(interface);
+ }
+ });
+ return classNode;
+ });
+ }
+
+ bool hasHierarchyProblem(ClassElement cls) => cls.hasIncompleteHierarchy;
+
+ ir.InterfaceType interfaceTypeToIr(InterfaceType type) {
+ ir.Class cls = classToIr(type.element);
+ if (type.typeArguments.isEmpty) {
+ return cls.rawType;
+ } else {
+ return new ir.InterfaceType(cls, typesToIr(type.typeArguments));
+ }
+ }
+
+ // TODO(ahe): Remove this method when dart2js support generic type arguments.
+ List<ir.TypeParameter> typeParametersNotImplemented() {
+ return const <ir.TypeParameter>[];
+ }
+
+ ir.FunctionType functionTypeToIr(FunctionType type) {
+ List<ir.TypeParameter> typeParameters = typeParametersNotImplemented();
+ int requiredParameterCount = type.parameterTypes.length;
+ List<ir.DartType> positionalParameters =
+ new List<ir.DartType>.from(typesToIr(type.parameterTypes))
+ ..addAll(typesToIr(type.optionalParameterTypes));
+ Map<String, ir.DartType> namedParameters = <String, ir.DartType>{};
+ for (int i = 0; i < type.namedParameters.length; i++) {
+ namedParameters[type.namedParameters[i]] =
+ typeToIr(type.namedParameterTypes[i]);
+ }
+ ir.DartType returnType = typeToIr(type.returnType);
+
+ return new ir.FunctionType(positionalParameters, returnType,
+ namedParameters: namedParameters,
+ typeParameters: typeParameters,
+ requiredParameterCount: requiredParameterCount);
+ }
+
+ ir.TypeParameterType typeVariableTypeToIr(TypeVariableType type) {
+ return new ir.TypeParameterType(typeVariableToIr(type.element));
+ }
+
+ List<ir.DartType> typesToIr(List<DartType> types) {
+ List<ir.DartType> result = new List<ir.DartType>(types.length);
+ for (int i = 0; i < types.length; i++) {
+ result[i] = typeToIr(types[i]);
+ }
+ return result;
+ }
+
+ ir.DartType typeToIr(DartType type) {
+ switch (type.kind) {
+ case TypeKind.FUNCTION:
+ return functionTypeToIr(type);
+
+ case TypeKind.INTERFACE:
+ return interfaceTypeToIr(type);
+
+ case TypeKind.STATEMENT:
+ throw "Internal error: statement type: $type.";
+
+ case TypeKind.TYPEDEF:
+ type.computeUnaliased(compiler.resolution);
+ return typeToIr(type.unaliased);
+
+ case TypeKind.TYPE_VARIABLE:
+ return typeVariableTypeToIr(type);
+
+ case TypeKind.MALFORMED_TYPE:
+ return const ir.InvalidType();
+
+ case TypeKind.DYNAMIC:
+ return const ir.DynamicType();
+
+ case TypeKind.VOID:
+ return const ir.VoidType();
+ }
+ }
+
+ ir.DartType typeLiteralToIr(TypeConstantExpression constant) {
+ return typeToIr(constant.type);
+ }
+
+ void setParent(ir.Member member, Element element) {
+ if (element.isLocal) {
+ member.parent = elementToIr(element.enclosingElement);
+ } else if (element.isTopLevel) {
+ member.parent = elementToIr(element.library);
+ } else if (element.isClassMember) {
+ member.parent = elementToIr(element.enclosingClass);
+ } else {
+ member.parent = elementToIr(element.enclosingElement);
+ }
+ }
+
+ bool isNativeMethod(FunctionElement element) {
+ // This method is a (modified) copy of the same method in
+ // `pkg/compiler/lib/src/native/enqueue.dart`.
+ if (!compiler.backend.canLibraryUseNative(element.library)) return false;
+ return compiler.reporter.withCurrentElement(element, () {
+ FunctionExpression functionExpression =
+ element.node?.asFunctionExpression();
+ if (functionExpression == null) return false;
+ Node body = functionExpression.body;
+ if (body == null) return false;
+ if (identical(body.getBeginToken().stringValue, 'native')) return true;
+ return false;
+ });
+ }
+
+ ir.Member functionToIr(FunctionElement function) {
+ if (function.isDeferredLoaderGetter) {
+ internalError(function, "Deferred loader.");
+ }
+ if (function.isLocal) {
+ internalError(function, "Local function.");
+ }
+ if (isSyntheticError(function)) {
+ internalError(function, "Synthetic error function: $function.");
+ }
+ function = function.declaration;
+ return functions.putIfAbsent(function, () {
+ function = function.implementation;
+ ir.Member member;
+ ir.Constructor constructor;
+ ir.Procedure procedure;
+ ir.Name name = irName(function.name, function);
+ bool isNative = isNativeMethod(function);
+ if (function.isGenerativeConstructor) {
+ member = constructor = new ir.Constructor(null,
+ name: name,
+ isConst: function.isConst,
+ isExternal: isNative || function.isExternal,
+ initializers: null);
+ } else {
+ member = procedure = new ir.Procedure(name, null, null,
+ isAbstract: function.isAbstract,
+ isStatic: function.isStatic ||
+ function.isTopLevel ||
+ function.isFactoryConstructor,
+ isExternal: isNative || function.isExternal,
+ isConst: false); // TODO(ahe): When is this true?
+ }
+ addWork(function, () {
+ setParent(member, function);
+ KernelVisitor visitor =
+ new KernelVisitor(function, function.treeElements, this);
+ beginFactoryScope(function);
+ IrFunction irFunction = visitor.buildFunction();
+ // TODO(ahe): Add addFunction/set function to [ir.Procedure].
+ irFunction.node.parent = member;
+ if (irFunction.isConstructor) {
+ assert(irFunction.kind == null);
+ constructor.function = irFunction.node;
+ constructor.initializers = irFunction.initializers;
+ // TODO(ahe): Add setInitializers to [ir.Constructor].
+ for (ir.Initializer initializer in irFunction.initializers) {
+ initializer.parent = constructor;
+ }
+ moveSuperCallLast(constructor);
+ } else {
+ assert(irFunction.kind != null);
+ procedure.function = irFunction.node;
+ procedure.kind = irFunction.kind;
+ }
+ endFactoryScope(function);
+ assert(() {
+ visitor.locals.forEach(checkMember);
+ return true;
+ });
+ });
+ return member;
+ });
+ }
+
+ /// Adds the type parameters of the enclosing class of [function] to
+ /// [factoryTypeParameters]. This serves as a local scope for type variables
+ /// resolved inside the factory.
+ ///
+ /// This method solves the problem that a factory method really is a generic
+ /// method that has its own type parameters, one for each type parameter in
+ /// the enclosing class.
+ void beginFactoryScope(FunctionElement function) {
+ assert(factoryTypeParameters.isEmpty);
+ if (!function.isFactoryConstructor) return;
+ ClassElement cls = function.enclosingClass;
+ for (DartType type in cls.typeVariables) {
+ if (type.isTypeVariable) {
+ TypeVariableElement variable = type.element;
+ factoryTypeParameters[variable] =
+ new ir.TypeParameter(variable.name, null);
+ }
+ }
+ for (DartType type in cls.typeVariables) {
+ if (type.isTypeVariable) {
+ TypeVariableElement variable = type.element;
+ factoryTypeParameters[variable].bound = typeToIr(variable.bound);
+ }
+ }
+ }
+
+ /// Ends the local scope started by [beginFactoryScope].
+ void endFactoryScope(FunctionElement function) {
+ factoryTypeParameters.clear();
+ }
+
+ ir.Field fieldToIr(FieldElement field) {
+ if (isSyntheticError(field)) {
+ internalError(field, "Synthetic error field: $field.");
+ }
+ field = field.declaration;
+ return fields.putIfAbsent(field, () {
+ field = field.implementation;
+ ir.DartType type =
+ field.isMalformed ? const ir.InvalidType() : typeToIr(field.type);
+ ir.Field fieldNode = new ir.Field(irName(field.memberName.text, field),
+ type: type,
+ initializer: null,
+ isFinal: field.isFinal,
+ isStatic: field.isStatic || field.isTopLevel,
+ isConst: field.isConst);
+ addWork(field, () {
+ setParent(fieldNode, field);
+ if (!field.isMalformed &&
+ !field.isInstanceMember &&
+ field.initializer != null) {
+ KernelVisitor visitor =
+ new KernelVisitor(field, field.treeElements, this);
+ fieldNode.initializer = visitor.buildInitializer()
+ ..parent = fieldNode;
+ }
+ });
+ return fieldNode;
+ });
+ }
+
+ ir.TypeParameter typeVariableToIr(TypeVariableElement variable) {
+ variable = variable.declaration;
+ ir.TypeParameter parameter = factoryTypeParameters[variable];
+ if (parameter != null) return parameter;
+ return typeParameters.putIfAbsent(variable, () {
+ ir.TypeParameter parameter = new ir.TypeParameter(variable.name, null);
+ addWork(variable, () {
+ // TODO(ahe): This assignment will probably not be correct when dart2js
+ // supports generic methods.
+ ClassElement cls = variable.typeDeclaration;
+ parameter.parent = classToIr(cls);
+ parameter.bound = typeToIr(variable.bound);
+ });
+ return parameter;
+ });
+ }
+
+ List<ir.TypeParameter> typeVariablesToIr(List<DartType> variables) {
+ List<ir.TypeParameter> result =
+ new List<ir.TypeParameter>(variables.length);
+ for (int i = 0; i < variables.length; i++) {
+ TypeVariableType type = variables[i];
+ result[i] = typeVariableToIr(type.element);
+ }
+ return result;
+ }
+
+ ir.TreeNode elementToIr(Element element) {
+ if (element.isLibrary) return libraryToIr(element);
+ if (element.isClass) return classToIr(element);
+ if (element.isFunction || element.isAccessor) return functionToIr(element);
+ if (element.isField) return fieldToIr(element);
+ throw "unhandled element: $element";
+ }
+
+ void debugMessage(Spannable spannable, String message) {
+ compiler.reporter
+ .reportHintMessage(spannable, MessageKind.GENERIC, {'text': message});
+ }
+
+ void internalError(Spannable spannable, String message) {
+ compiler.reporter.internalError(spannable, message);
+ throw message;
+ }
+
+ ConstructorTarget computeEffectiveTarget(
+ ConstructorElement constructor, DartType type) {
+ constructor = constructor.implementation;
+ Set<ConstructorElement> seen = new Set<ConstructorElement>();
+ functionToIr(constructor);
+ while (constructor != constructor.effectiveTarget) {
+ type = constructor.computeEffectiveTargetType(type);
+ if (constructor.isGenerativeConstructor) break;
+ if (!seen.add(constructor)) break;
+ constructor = constructor.effectiveTarget.implementation;
+ if (isSyntheticError(constructor)) break;
+ functionToIr(constructor);
+ }
+ return new ConstructorTarget(constructor, type);
+ }
+
+ /// Returns true if [element] is synthesized to recover or represent a
+ /// semantic error, for example, missing, duplicated, or ambiguous elements.
+ /// However, returns false for elements that have an unrecoverable syntax
+ /// error. Both kinds of element will return true from [Element.isMalformed],
+ /// but they must be handled differently. For example, a static call to
+ /// synthetic error element should be compiled to [ir.InvalidExpression],
+ /// whereas a static call to a method which has a syntax error should be
+ /// compiled to a static call to the method. The method itself will have a
+ /// method body that is [ir.InvalidStatement].
+ bool isSyntheticError(Element element) {
+ if (element.isAmbiguous) return true;
+ if (element.isError) return true;
+ if (element.isField && element is ErroneousFieldElementX) {
+ return true;
+ }
+ return false;
+ }
+
+ ir.Procedure getDartCoreMethod(String name) {
+ LibraryElement library =
+ compiler.libraryLoader.lookupLibrary(Uri.parse("dart:core"));
+ Element function = library.implementation.localLookup(name);
+ return functionToIr(function);
+ }
+
+ ir.Procedure getMalformedTypeErrorBuilder() {
+ return getDartCoreMethod('_malformedTypeError');
+ }
+
+ ir.Procedure getUnresolvedConstructorBuilder() {
+ return getDartCoreMethod('_unresolvedConstructorError');
+ }
+
+ ir.Procedure getUnresolvedStaticGetterBuilder() {
+ return getDartCoreMethod('_unresolvedStaticGetterError');
+ }
+
+ ir.Procedure getUnresolvedStaticSetterBuilder() {
+ return getDartCoreMethod('_unresolvedStaticSetterError');
+ }
+
+ ir.Procedure getUnresolvedStaticMethodBuilder() {
+ return getDartCoreMethod('_unresolvedStaticMethodError');
+ }
+
+ ir.Procedure getUnresolvedTopLevelGetterBuilder() {
+ return getDartCoreMethod('_unresolvedTopLevelGetterError');
+ }
+
+ ir.Procedure getUnresolvedTopLevelSetterBuilder() {
+ return getDartCoreMethod('_unresolvedTopLevelSetterError');
+ }
+
+ ir.Procedure getUnresolvedTopLevelMethodBuilder() {
+ return getDartCoreMethod('_unresolvedTopLevelMethodError');
+ }
+
+ ir.Procedure getUnresolvedSuperGetterBuilder() {
+ return getDartCoreMethod('_unresolvedSuperGetterError');
+ }
+
+ ir.Procedure getUnresolvedSuperSetterBuilder() {
+ return getDartCoreMethod('_unresolvedSuperSetterError');
+ }
+
+ ir.Procedure getUnresolvedSuperMethodBuilder() {
+ return getDartCoreMethod('_unresolvedSuperMethodError');
+ }
+
+ ir.Procedure getGenericNoSuchMethodBuilder() {
+ return getDartCoreMethod('_genericNoSuchMethod');
+ }
+
+ ir.Procedure getFallThroughErrorBuilder() {
+ return getDartCoreMethod('_fallThroughError');
+ }
+}
+
+class ConstructorTarget {
+ final ConstructorElement element;
+ final DartType type;
+
+ ConstructorTarget(this.element, this.type);
+
+ String toString() => "ConstructorTarget($element, $type)";
+}
« no previous file with comments | « pkg/compiler/lib/src/kernel/fall_through_visitor.dart ('k') | pkg/compiler/lib/src/kernel/kernel_visitor.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698