Chromium Code Reviews| Index: pkg/kernel/lib/ast.dart |
| diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart |
| index 2f3cb111d74337e809f435bacbdfa2000ae8f9db..9cae89229a28b826dcf717aa8ad98068c50c0d69 100644 |
| --- a/pkg/kernel/lib/ast.dart |
| +++ b/pkg/kernel/lib/ast.dart |
| @@ -56,6 +56,9 @@ export 'visitor.dart'; |
| import 'type_propagation/type_propagation.dart'; |
| export 'type_propagation/type_propagation.dart'; |
| +import 'canonical_name.dart' show CanonicalName; |
| +export 'canonical_name.dart' show CanonicalName; |
| + |
| import 'transformations/flags.dart'; |
| import 'text/ast_to_text.dart'; |
| import 'type_algebra.dart'; |
| @@ -152,11 +155,62 @@ abstract class TreeNode extends Node { |
| } |
| } |
| +/// An AST node that can be referenced by other nodes. |
| +/// |
| +/// There is a single [box] belonging to this node, providing a level of |
| +/// indirection that is needed during serialization. |
| +abstract class LinkedNode extends TreeNode { |
|
Kevin Millikin (Google)
2017/02/22 09:09:30
Suggestion: LinkedNode ==> NamedNode, LinkedNodeBo
asgerf
2017/02/22 10:06:54
Done.
|
| + final LinkedNodeBox box; |
| + |
| + LinkedNode(LinkedNodeBox box) |
| + : this.box = box ?? new LinkedNodeBox() { |
| + this.box.node = this; |
| + } |
| + |
| + CanonicalName get canonicalName => box?.canonicalName; |
| +} |
| + |
| +/// Indirection between a reference and its definition. |
| +class LinkedNodeBox { |
| + CanonicalName canonicalName; |
| + LinkedNode node; |
| + |
| + Library get asLibrary { |
| + if (node == null) throw 'The box is empty. A library was expected'; |
| + return node as Library; |
| + } |
| + |
| + Class get asClass { |
| + if (node == null) throw 'The box is empty. A class was expected'; |
| + return node as Class; |
| + } |
| + |
| + Member get asMember { |
| + if (node == null) throw 'The box is empty. A member was expected'; |
| + return node as Member; |
| + } |
| + |
| + Field get asField { |
| + if (node == null) throw 'The box is empty. A field was expected'; |
| + return node as Field; |
| + } |
| + |
| + Constructor get asConstructor { |
| + if (node == null) throw 'The box is empty. A constructor was expected'; |
| + return node as Constructor; |
| + } |
| + |
| + Procedure get asProcedure { |
| + if (node == null) throw 'The box is empty. A procedure was expected'; |
| + return node as Procedure; |
| + } |
| +} |
| + |
| // ------------------------------------------------------------------------ |
| // LIBRARIES and CLASSES |
| // ------------------------------------------------------------------------ |
| -class Library extends TreeNode implements Comparable<Library> { |
| +class Library extends LinkedNode implements Comparable<Library> { |
| /// An import path to this library. |
| /// |
| /// The [Uri] should have the `dart`, `package`, `app`, or `file` scheme. |
| @@ -191,11 +245,13 @@ class Library extends TreeNode implements Comparable<Library> { |
| List<Class> classes, |
| List<Procedure> procedures, |
| List<Field> fields, |
| - this.fileUri}) |
| + this.fileUri, |
| + LinkedNodeBox box}) |
| : this.deferredImports = imports ?? <DeferredImport>[], |
| this.classes = classes ?? <Class>[], |
| this.procedures = procedures ?? <Procedure>[], |
| - this.fields = fields ?? <Field>[] { |
| + this.fields = fields ?? <Field>[], |
| + super(box) { |
| setParents(this.classes, this); |
| setParents(this.procedures, this); |
| setParents(this.fields, this); |
| @@ -224,6 +280,20 @@ class Library extends TreeNode implements Comparable<Library> { |
| classes.add(class_); |
| } |
| + void computeCanonicalNames() { |
| + assert(canonicalName != null); |
| + for (var field in fields) { |
| + canonicalName.getChildFromMember(field).bindTo(field.box); |
| + } |
| + for (var member in procedures) { |
| + canonicalName.getChildFromMember(member).bindTo(member.box); |
| + } |
| + for (var class_ in classes) { |
| + canonicalName.getChild(class_.name).bindTo(class_.box); |
| + class_.computeCanonicalNames(); |
| + } |
| + } |
| + |
| accept(TreeVisitor v) => v.visitLibrary(this); |
| visitChildren(Visitor v) { |
| @@ -254,12 +324,16 @@ class Library extends TreeNode implements Comparable<Library> { |
| /// An import of form: `import <url> deferred as <name>;`. |
| class DeferredImport extends TreeNode { |
| - Library importedLibrary; |
| + LinkedNodeBox importedLibraryBox; |
| String name; |
| - DeferredImport(this.importedLibrary, this.name); |
| + DeferredImport(Library importedLibrary, String name) |
| + : this.byBox(importedLibrary.box, name); |
| + |
| + DeferredImport.byBox(this.importedLibraryBox, this.name); |
| Library get enclosingLibrary => parent; |
| + Library get importedLibrary => importedLibraryBox.node; |
| accept(TreeVisitor v) => v.visitDeferredImport(this); |
| @@ -321,7 +395,7 @@ enum ClassLevel { |
| /// use those from its mixed-in type. However, the IR does not enforce this |
| /// rule directly, as doing so can obstruct transformations. It is possible to |
| /// transform a mixin application to become a regular class, and vice versa. |
| -class Class extends TreeNode { |
| +class Class extends LinkedNode { |
| /// The degree to which the contents of the class have been loaded. |
| ClassLevel level = ClassLevel.Body; |
| @@ -378,18 +452,33 @@ class Class extends TreeNode { |
| List<Constructor> constructors, |
| List<Procedure> procedures, |
| List<Field> fields, |
| - this.fileUri}) |
| + this.fileUri, |
| + LinkedNodeBox box}) |
| : this.typeParameters = typeParameters ?? <TypeParameter>[], |
| this.implementedTypes = implementedTypes ?? <Supertype>[], |
| this.fields = fields ?? <Field>[], |
| this.constructors = constructors ?? <Constructor>[], |
| - this.procedures = procedures ?? <Procedure>[] { |
| + this.procedures = procedures ?? <Procedure>[], |
| + super(box) { |
| setParents(this.typeParameters, this); |
| setParents(this.constructors, this); |
| setParents(this.procedures, this); |
| setParents(this.fields, this); |
| } |
| + void computeCanonicalNames() { |
| + assert(canonicalName != null); |
| + for (var member in fields) { |
| + canonicalName.getChildFromMember(member).bindTo(member.box); |
| + } |
| + for (var member in procedures) { |
| + canonicalName.getChildFromMember(member).bindTo(member.box); |
| + } |
| + for (var member in constructors) { |
| + canonicalName.getChildFromMember(member).bindTo(member.box); |
| + } |
| + } |
| + |
| /// The immediate super class, or `null` if this is the root class. |
| Class get superclass => supertype?.classNode; |
| @@ -522,14 +611,7 @@ class Class extends TreeNode { |
| // MEMBERS |
| // ------------------------------------------------------------------------ |
| -/// A indirect reference to a member, which can be updated to point at another |
| -/// member at a later time. |
| -class _MemberAccessor { |
| - Member target; |
| - _MemberAccessor(this.target); |
| -} |
| - |
| -abstract class Member extends TreeNode { |
| +abstract class Member extends LinkedNode { |
| /// End offset in the source file it comes from. Valid values are from 0 and |
| /// up, or -1 ([TreeNode.noOffset]) if the file end offset is not available |
| /// (this is the default if none is specifically set). |
| @@ -559,7 +641,7 @@ abstract class Member extends TreeNode { |
| // TODO(asgerf): It might be worthwhile to put this on classes as well. |
| int transformerFlags = 0; |
| - Member(this.name); |
| + Member(this.name, LinkedNodeBox box) : super(box); |
| Class get enclosingClass => parent is Class ? parent : null; |
| Library get enclosingLibrary => parent is Class ? parent.parent : parent; |
| @@ -617,9 +699,6 @@ abstract class Member extends TreeNode { |
| bool get containsSuperCalls { |
| return transformerFlags & TransformerFlag.superCalls != 0; |
| } |
| - |
| - _MemberAccessor get _getterInterface; |
| - _MemberAccessor get _setterInterface; |
| } |
| /// A field declaration. |
| @@ -627,8 +706,6 @@ abstract class Member extends TreeNode { |
| /// The implied getter and setter for the field are not represented explicitly, |
| /// but can be made explicit if needed. |
| class Field extends Member { |
| - _MemberAccessor _getterInterface, _setterInterface; |
| - |
| DartType type; // Not null. Defaults to DynamicType. |
| InferredValue inferredValue; // May be null. |
| int flags = 0; |
| @@ -647,10 +724,9 @@ class Field extends Member { |
| bool hasImplicitGetter, |
| bool hasImplicitSetter, |
| int transformerFlags: 0, |
| - this.fileUri}) |
| - : super(name) { |
| - _getterInterface = new _MemberAccessor(this); |
| - _setterInterface = new _MemberAccessor(this); |
| + this.fileUri, |
| + LinkedNodeBox box}) |
| + : super(name, box) { |
| assert(type != null); |
| initializer?.parent = this; |
| this.isFinal = isFinal; |
| @@ -750,46 +826,6 @@ class Field extends Member { |
| DartType get getterType => type; |
| DartType get setterType => isMutable ? type : const BottomType(); |
| - /// Makes all [PropertyGet]s that have this field as its interface target |
| - /// use [getter] as its interface target instead. |
| - /// |
| - /// That can be used to introduce an explicit getter for a field instead of |
| - /// its implicit getter. |
| - /// |
| - /// This method only updates the stored interface target -- the caller must |
| - /// ensure that [getter] actually becomes the target for dispatches that |
| - /// would previously hit the implicit field getter. |
| - /// |
| - /// [DirectPropertyGet]s are not affected, and will continue to access the |
| - /// field directly. [PropertyGet] nodes created after the call will not be |
| - /// affected until the method is called again. |
| - /// |
| - /// Existing [ClassHierarchy] instances are not affected by this call. |
| - void replaceGetterInterfaceWith(Procedure getter) { |
| - _getterInterface.target = getter; |
| - _getterInterface = new _MemberAccessor(this); |
| - } |
| - |
| - /// Makes all [PropertySet]s that have this field as its interface target |
| - /// use [setter] as its interface target instead. |
| - /// |
| - /// That can be used to introduce an explicit setter for a field instead of |
| - /// its implicit setter. |
| - /// |
| - /// This method only updates the stored interface target -- the caller must |
| - /// ensure that [setter] actually becomes the target for dispatches that |
| - /// would previously hit the implicit field setter. |
| - /// |
| - /// [DirectPropertySet] and [FieldInitializer]s are not affected, and will |
| - /// continue to access the field directly. [PropertySet] nodes created after |
| - /// the call will not be affected until the method is called again. |
| - /// |
| - /// Existing [ClassHierarchy] instances are not affected by this call. |
| - void replaceSetterInterfaceWith(Procedure setter) { |
| - _setterInterface.target = setter; |
| - _setterInterface = new _MemberAccessor(this); |
| - } |
| - |
| Location _getLocationInEnclosingFile(int offset) { |
| return enclosingProgram.getLocation(fileUri, offset); |
| } |
| @@ -813,9 +849,10 @@ class Constructor extends Member { |
| bool isConst: false, |
| bool isExternal: false, |
| List<Initializer> initializers, |
| - int transformerFlags: 0}) |
| + int transformerFlags: 0, |
| + LinkedNodeBox box}) |
| : this.initializers = initializers ?? <Initializer>[], |
| - super(name) { |
| + super(name, box) { |
| function?.parent = this; |
| setParents(this.initializers, this); |
| this.isConst = isConst; |
| @@ -864,14 +901,6 @@ class Constructor extends Member { |
| DartType get getterType => const BottomType(); |
| DartType get setterType => const BottomType(); |
| - |
| - _MemberAccessor get _getterInterface { |
| - throw 'Constructors cannot be used as getters'; |
| - } |
| - |
| - _MemberAccessor get _setterInterface { |
| - throw 'Constructors cannot be used as setters'; |
| - } |
| } |
| /// A method, getter, setter, index-getter, index-setter, operator overloader, |
| @@ -890,7 +919,6 @@ class Constructor extends Member { |
| /// For operators, this is the token for the operator, e.g. `+` or `==`, |
| /// except for the unary minus operator, whose name is `unary-`. |
| class Procedure extends Member { |
| - _MemberAccessor _reference; |
| ProcedureKind kind; |
| int flags = 0; |
| FunctionNode function; // Body is null if and only if abstract or external. |
| @@ -904,9 +932,9 @@ class Procedure extends Member { |
| bool isExternal: false, |
| bool isConst: false, |
| int transformerFlags: 0, |
| - this.fileUri}) |
| - : super(name) { |
| - _reference = new _MemberAccessor(this); |
| + this.fileUri, |
| + LinkedNodeBox box}) |
| + : super(name, box) { |
| function?.parent = this; |
| this.isAbstract = isAbstract; |
| this.isStatic = isStatic; |
| @@ -979,9 +1007,6 @@ class Procedure extends Member { |
| : const BottomType(); |
| } |
| - _MemberAccessor get _getterInterface => _reference; |
| - _MemberAccessor get _setterInterface => _reference; |
| - |
| Location _getLocationInEnclosingFile(int offset) { |
| return enclosingProgram.getLocation(fileUri, offset); |
| } |
| @@ -1027,13 +1052,22 @@ class InvalidInitializer extends Initializer { |
| // exactly once, and that no fields are assigned twice in the initializer list. |
| class FieldInitializer extends Initializer { |
| /// Reference to the field being initialized. Not null. |
| - Field field; |
| + LinkedNodeBox fieldBox; |
| Expression value; |
| - FieldInitializer(this.field, this.value) { |
| + FieldInitializer(Field field, Expression value) |
| + : this.byBox(field?.box, value); |
| + |
| + FieldInitializer.byBox(this.fieldBox, this.value) { |
| value?.parent = this; |
| } |
| + Field get field => fieldBox?.node; |
| + |
| + void set field(Field field) { |
| + fieldBox = field?.box; |
| + } |
| + |
| accept(InitializerVisitor v) => v.visitFieldInitializer(this); |
| visitChildren(Visitor v) { |
| @@ -1060,13 +1094,22 @@ class FieldInitializer extends Initializer { |
| // from the extends clause. |
| class SuperInitializer extends Initializer { |
| /// Reference to the constructor being invoked in the super class. Not null. |
| - Constructor target; |
| + LinkedNodeBox targetBox; |
| Arguments arguments; |
| - SuperInitializer(this.target, this.arguments) { |
| + SuperInitializer(Constructor target, Arguments arguments) |
| + : this.byBox(getBoxOfMember(target), arguments); |
| + |
| + SuperInitializer.byBox(this.targetBox, this.arguments) { |
| arguments?.parent = this; |
| } |
| + Constructor get target => targetBox?.asConstructor; |
| + |
| + void set target(Constructor target) { |
| + targetBox = getBoxOfMember(target); |
| + } |
| + |
| accept(InitializerVisitor v) => v.visitSuperInitializer(this); |
| visitChildren(Visitor v) { |
| @@ -1089,13 +1132,22 @@ class SuperInitializer extends Initializer { |
| // constructor has a body or if there is a cycle in the initializer calls. |
| class RedirectingInitializer extends Initializer { |
| /// Reference to the constructor being invoked in the same class. Not null. |
| - Constructor target; |
| + LinkedNodeBox targetBox; |
| Arguments arguments; |
| - RedirectingInitializer(this.target, this.arguments) { |
| + RedirectingInitializer(Constructor target, Arguments arguments) |
| + : this.byBox(getBoxOfMember(target), arguments); |
| + |
| + RedirectingInitializer.byBox(this.targetBox, this.arguments) { |
| arguments?.parent = this; |
| } |
| + Constructor get target => targetBox?.asConstructor; |
| + |
| + void set target(Constructor target) { |
| + targetBox = getBoxOfMember(target); |
| + } |
| + |
| accept(InitializerVisitor v) => v.visitRedirectingInitializer(this); |
| visitChildren(Visitor v) { |
| @@ -1388,17 +1440,19 @@ class PropertyGet extends Expression { |
| Expression receiver; |
| Name name; |
| - _MemberAccessor _interfaceTargetReference; |
| + LinkedNodeBox interfaceTargetBox; |
| + |
| + PropertyGet(Expression receiver, Name name, [Member interfaceTarget]) |
| + : this.byBox(receiver, name, getBoxOfMember(interfaceTarget)); |
| - PropertyGet(this.receiver, this.name, [Member interfaceTarget]) { |
| + PropertyGet.byBox(this.receiver, this.name, this.interfaceTargetBox) { |
| receiver?.parent = this; |
| - this.interfaceTarget = interfaceTarget; |
| } |
| - Member get interfaceTarget => _interfaceTargetReference?.target; |
| + Member get interfaceTarget => interfaceTargetBox?.asMember; |
| - void set interfaceTarget(Member newTarget) { |
| - _interfaceTargetReference = newTarget?._getterInterface; |
| + void set interfaceTarget(Member member) { |
| + interfaceTargetBox = getBoxOfMember(member); |
| } |
| DartType getStaticType(TypeEnvironment types) { |
| @@ -1445,18 +1499,23 @@ class PropertySet extends Expression { |
| Name name; |
| Expression value; |
| - _MemberAccessor _interfaceTargetReference; |
| + LinkedNodeBox interfaceTargetBox; |
| - PropertySet(this.receiver, this.name, this.value, [Member interfaceTarget]) { |
| + PropertySet(Expression receiver, Name name, Expression value, |
| + [Member interfaceTarget]) |
| + : this.byBox( |
| + receiver, name, value, getBoxOfMember(interfaceTarget)); |
| + |
| + PropertySet.byBox( |
| + this.receiver, this.name, this.value, this.interfaceTargetBox) { |
| receiver?.parent = this; |
| value?.parent = this; |
| - this.interfaceTarget = interfaceTarget; |
| } |
| - Member get interfaceTarget => _interfaceTargetReference?.target; |
| + Member get interfaceTarget => interfaceTargetBox?.asMember; |
| - void set interfaceTarget(Member newTarget) { |
| - _interfaceTargetReference = newTarget?._setterInterface; |
| + void set interfaceTarget(Member member) { |
| + interfaceTargetBox = getBoxOfMember(member); |
| } |
| DartType getStaticType(TypeEnvironment types) => value.getStaticType(types); |
| @@ -1484,12 +1543,21 @@ class PropertySet extends Expression { |
| /// Directly read a field, call a getter, or tear off a method. |
| class DirectPropertyGet extends Expression { |
| Expression receiver; |
| - Member target; |
| + LinkedNodeBox targetBox; |
| + |
| + DirectPropertyGet(Expression receiver, Member target) |
| + : this.byBox(receiver, getBoxOfMember(target)); |
| - DirectPropertyGet(this.receiver, this.target) { |
| + DirectPropertyGet.byBox(this.receiver, this.targetBox) { |
| receiver?.parent = this; |
| } |
| + Member get target => targetBox?.asMember; |
| + |
| + void set target(Member target) { |
| + targetBox = getBoxOfMember(target); |
| + } |
| + |
| visitChildren(Visitor v) { |
| receiver?.accept(v); |
| target?.acceptReference(v); |
| @@ -1518,14 +1586,23 @@ class DirectPropertyGet extends Expression { |
| /// Evaluates to the value of [value]. |
| class DirectPropertySet extends Expression { |
| Expression receiver; |
| - Member target; |
| + LinkedNodeBox targetBox; |
| Expression value; |
| - DirectPropertySet(this.receiver, this.target, this.value) { |
| + DirectPropertySet(Expression receiver, Member target, Expression value) |
| + : this.byBox(receiver, getBoxOfMember(target), value); |
| + |
| + DirectPropertySet.byBox(this.receiver, this.targetBox, this.value) { |
| receiver?.parent = this; |
| value?.parent = this; |
| } |
| + Member get target => targetBox?.asMember; |
| + |
| + void set target(Member target) { |
| + targetBox = getBoxOfMember(target); |
| + } |
| + |
| visitChildren(Visitor v) { |
| receiver?.accept(v); |
| target?.acceptReference(v); |
| @@ -1551,14 +1628,25 @@ class DirectPropertySet extends Expression { |
| /// Directly call an instance method, bypassing ordinary dispatch. |
| class DirectMethodInvocation extends InvocationExpression { |
| Expression receiver; |
| - Procedure target; |
| + LinkedNodeBox targetBox; |
| Arguments arguments; |
| - DirectMethodInvocation(this.receiver, this.target, this.arguments) { |
| + DirectMethodInvocation( |
| + Expression receiver, Procedure target, Arguments arguments) |
| + : this.byBox(receiver, getBoxOfMember(target), arguments); |
| + |
| + DirectMethodInvocation.byBox( |
| + this.receiver, this.targetBox, this.arguments) { |
| receiver?.parent = this; |
| arguments?.parent = this; |
| } |
| + Procedure get target => targetBox?.asProcedure; |
| + |
| + void set target(Procedure target) { |
| + targetBox = getBoxOfMember(target); |
| + } |
| + |
| Name get name => target?.name; |
| visitChildren(Visitor v) { |
| @@ -1601,16 +1689,17 @@ class DirectMethodInvocation extends InvocationExpression { |
| /// This may invoke a getter, read a field, or tear off a method. |
| class SuperPropertyGet extends Expression { |
| Name name; |
| - _MemberAccessor _interfaceTargetReference; |
| + LinkedNodeBox interfaceTargetBox; |
| - SuperPropertyGet(this.name, [Member interfaceTarget]) { |
| - _interfaceTargetReference = interfaceTarget?._getterInterface; |
| - } |
| + SuperPropertyGet(Name name, [Member interfaceTarget]) |
| + : this.byBox(name, getBoxOfMember(interfaceTarget)); |
| + |
| + SuperPropertyGet.byBox(this.name, this.interfaceTargetBox); |
| - Member get interfaceTarget => _interfaceTargetReference?.target; |
| + Member get interfaceTarget => interfaceTargetBox?.asMember; |
| - void set interfaceTarget(Member newTarget) { |
| - _interfaceTargetReference = newTarget?._getterInterface; |
| + void set interfaceTarget(Member member) { |
| + interfaceTargetBox = getBoxOfMember(member); |
| } |
| DartType getStaticType(TypeEnvironment types) { |
| @@ -1642,17 +1731,19 @@ class SuperPropertyGet extends Expression { |
| class SuperPropertySet extends Expression { |
| Name name; |
| Expression value; |
| - _MemberAccessor _interfaceTargetReference; |
| + LinkedNodeBox interfaceTargetBox; |
| + |
| + SuperPropertySet(Name name, Expression value, Member interfaceTarget) |
| + : this.byBox(name, value, getBoxOfMember(interfaceTarget)); |
| - SuperPropertySet(this.name, this.value, [Member interfaceTarget]) { |
| + SuperPropertySet.byBox(this.name, this.value, this.interfaceTargetBox) { |
| value?.parent = this; |
| - _interfaceTargetReference = interfaceTarget?._setterInterface; |
| } |
| - Member get interfaceTarget => _interfaceTargetReference?.target; |
| + Member get interfaceTarget => interfaceTargetBox?.asMember; |
| - void set interfaceTarget(Member newTarget) { |
| - _interfaceTargetReference = newTarget?._setterInterface; |
| + void set interfaceTarget(Member member) { |
| + interfaceTargetBox = getBoxOfMember(member); |
| } |
| DartType getStaticType(TypeEnvironment types) => value.getStaticType(types); |
| @@ -1675,9 +1766,17 @@ class SuperPropertySet extends Expression { |
| /// Read a static field, call a static getter, or tear off a static method. |
| class StaticGet extends Expression { |
| /// A static field, getter, or method (for tear-off). |
| - Member target; |
| + LinkedNodeBox targetBox; |
| + |
| + StaticGet(Member target) : this.byBox(getBoxOfMember(target)); |
| + |
| + StaticGet.byBox(this.targetBox); |
| - StaticGet(this.target); |
| + Member get target => targetBox?.asMember; |
| + |
| + void set target(Member target) { |
| + targetBox = getBoxOfMember(target); |
| + } |
| DartType getStaticType(TypeEnvironment types) => target.getterType; |
| @@ -1695,13 +1794,22 @@ class StaticGet extends Expression { |
| /// Evaluates to the value of [value]. |
| class StaticSet extends Expression { |
| /// A mutable static field or a static setter. |
| - Member target; |
| + LinkedNodeBox targetBox; |
| Expression value; |
| - StaticSet(this.target, this.value) { |
| + StaticSet(Member target, Expression value) |
| + : this.byBox(getBoxOfMember(target), value); |
| + |
| + StaticSet.byBox(this.targetBox, this.value) { |
| value?.parent = this; |
| } |
| + Member get target => targetBox?.asMember; |
| + |
| + void set target(Member target) { |
| + targetBox = getBoxOfMember(target); |
| + } |
| + |
| DartType getStaticType(TypeEnvironment types) => value.getStaticType(types); |
| accept(ExpressionVisitor v) => v.visitStaticSet(this); |
| @@ -1795,14 +1903,25 @@ class MethodInvocation extends InvocationExpression { |
| Name name; |
| Arguments arguments; |
| - Procedure interfaceTarget; |
| + LinkedNodeBox interfaceTargetBox; |
| + |
| + MethodInvocation(Expression receiver, Name name, Arguments arguments, |
| + [Procedure interfaceTarget]) |
| + : this.byBox(receiver, name, arguments, |
| + getBoxOfMember(interfaceTarget)); |
| - MethodInvocation(this.receiver, this.name, this.arguments, |
| - [this.interfaceTarget]) { |
| + MethodInvocation.byBox( |
| + this.receiver, this.name, this.arguments, this.interfaceTargetBox) { |
| receiver?.parent = this; |
| arguments?.parent = this; |
| } |
| + Procedure get interfaceTarget => interfaceTargetBox?.asProcedure; |
| + |
| + void set interfaceTarget(Member target) { |
| + interfaceTargetBox = getBoxOfMember(target); |
| + } |
| + |
| DartType getStaticType(TypeEnvironment types) { |
| if (interfaceTarget != null) { |
| if (types.isOverloadedArithmeticOperator(interfaceTarget)) { |
| @@ -1864,12 +1983,23 @@ class SuperMethodInvocation extends InvocationExpression { |
| Name name; |
| Arguments arguments; |
| - Procedure interfaceTarget; |
| + LinkedNodeBox interfaceTargetBox; |
| + |
| + SuperMethodInvocation(Name name, Arguments arguments, |
| + [Procedure interfaceTarget]) |
| + : this.byBox(name, arguments, getBoxOfMember(interfaceTarget)); |
| - SuperMethodInvocation(this.name, this.arguments, this.interfaceTarget) { |
| + SuperMethodInvocation.byBox( |
| + this.name, this.arguments, this.interfaceTargetBox) { |
| arguments?.parent = this; |
| } |
| + Procedure get interfaceTarget => interfaceTargetBox?.asProcedure; |
| + |
| + void set interfaceTarget(Procedure target) { |
| + interfaceTargetBox = getBoxOfMember(target); |
| + } |
| + |
| DartType getStaticType(TypeEnvironment types) { |
| if (interfaceTarget == null) return const DynamicType(); |
| Class superclass = interfaceTarget.enclosingClass; |
| @@ -1903,7 +2033,7 @@ class SuperMethodInvocation extends InvocationExpression { |
| /// |
| /// The provided arguments might not match the parameters of the target. |
| class StaticInvocation extends InvocationExpression { |
| - Procedure target; |
| + LinkedNodeBox targetBox; |
| Arguments arguments; |
| /// True if this is a constant call to an external constant factory. |
| @@ -1911,10 +2041,21 @@ class StaticInvocation extends InvocationExpression { |
| Name get name => target?.name; |
| - StaticInvocation(this.target, this.arguments, {this.isConst: false}) { |
| + StaticInvocation(Procedure target, Arguments arguments, {bool isConst: false}) |
| + : this.byBox(getBoxOfMember(target), arguments, |
| + isConst: isConst); |
| + |
| + StaticInvocation.byBox(this.targetBox, this.arguments, |
| + {this.isConst: false}) { |
| arguments?.parent = this; |
| } |
| + Procedure get target => targetBox?.asProcedure; |
| + |
| + void set target(Procedure target) { |
| + targetBox = getBoxOfMember(target); |
| + } |
| + |
| DartType getStaticType(TypeEnvironment types) { |
| return Substitution |
| .fromPairs(target.function.typeParameters, arguments.types) |
| @@ -1944,16 +2085,28 @@ class StaticInvocation extends InvocationExpression { |
| // `classTypeArguments`? They are quite different from type arguments to |
| // generic functions. |
| class ConstructorInvocation extends InvocationExpression { |
| - Constructor target; |
| + LinkedNodeBox targetBox; |
| Arguments arguments; |
| bool isConst; |
| Name get name => target?.name; |
| - ConstructorInvocation(this.target, this.arguments, {this.isConst: false}) { |
| + ConstructorInvocation(Constructor target, Arguments arguments, |
| + {bool isConst: false}) |
| + : this.byBox(getBoxOfMember(target), arguments, |
| + isConst: isConst); |
| + |
| + ConstructorInvocation.byBox(this.targetBox, this.arguments, |
| + {this.isConst: false}) { |
| arguments?.parent = this; |
| } |
| + Constructor get target => targetBox?.asConstructor; |
| + |
| + void set target(Constructor target) { |
| + targetBox = getBoxOfMember(target); |
| + } |
| + |
| DartType getStaticType(TypeEnvironment types) { |
| return arguments.types.isEmpty |
| ? target.enclosingClass.rawType |
| @@ -3200,17 +3353,21 @@ class FunctionDeclaration extends Statement { |
| abstract class Name implements Node { |
| final int hashCode; |
| final String name; |
| + LinkedNodeBox get libraryName; |
| Library get library; |
| bool get isPrivate; |
| Name._internal(this.hashCode, this.name); |
| - factory Name(String name, [Library library]) { |
| + factory Name(String name, [Library library]) => |
| + new Name.byReference(name, library?.box); |
| + |
| + factory Name.byReference(String name, LinkedNodeBox libraryName) { |
| /// Use separate subclasses for the public and private case to save memory |
| /// for public names. |
| if (name.startsWith('_')) { |
| - assert(library != null); |
| - return new _PrivateName(name, library); |
| + assert(libraryName != null); |
| + return new _PrivateName(name, libraryName); |
| } else { |
| return new _PublicName(name); |
| } |
| @@ -3228,21 +3385,24 @@ abstract class Name implements Node { |
| } |
| class _PrivateName extends Name { |
| - final Library library; |
| + final LinkedNodeBox libraryName; |
| bool get isPrivate => true; |
| - _PrivateName(String name, Library library) |
| - : this.library = library, |
| - super._internal(_computeHashCode(name, library), name); |
| + _PrivateName(String name, LinkedNodeBox libraryName) |
| + : this.libraryName = libraryName, |
| + super._internal(_computeHashCode(name, libraryName), name); |
| String toString() => library != null ? '$library::$name' : name; |
| - static int _computeHashCode(String name, Library library) { |
| - return 131 * name.hashCode + 17 * library.hashCode; |
| + Library get library => libraryName.asLibrary; |
| + |
| + static int _computeHashCode(String name, LinkedNodeBox libraryName) { |
| + return 131 * name.hashCode + 17 * libraryName.hashCode; |
| } |
| } |
| class _PublicName extends Name { |
| + LinkedNodeBox get libraryName => null; |
| Library get library => null; |
| bool get isPrivate => false; |
| @@ -3322,14 +3482,18 @@ class BottomType extends DartType { |
| } |
| class InterfaceType extends DartType { |
| - final Class classNode; |
| + final LinkedNodeBox className; |
| final List<DartType> typeArguments; |
| /// The [typeArguments] list must not be modified after this call. If the |
| /// list is omitted, 'dynamic' type arguments are filled in. |
| InterfaceType(Class classNode, [List<DartType> typeArguments]) |
| - : this.classNode = classNode, |
| - this.typeArguments = typeArguments ?? _defaultTypeArguments(classNode); |
| + : this.byBox(getBoxOfClass(classNode), |
| + typeArguments ?? _defaultTypeArguments(classNode)); |
| + |
| + InterfaceType.byBox(this.className, this.typeArguments); |
| + |
| + Class get classNode => className.asClass; |
| static List<DartType> _defaultTypeArguments(Class classNode) { |
| if (classNode.typeParameters.length == 0) { |
| @@ -3351,7 +3515,7 @@ class InterfaceType extends DartType { |
| bool operator ==(Object other) { |
| if (identical(this, other)) return true; |
| if (other is InterfaceType) { |
| - if (classNode != other.classNode) return false; |
| + if (className != other.className) return false; |
| if (typeArguments.length != other.typeArguments.length) return false; |
| for (int i = 0; i < typeArguments.length; ++i) { |
| if (typeArguments[i] != other.typeArguments[i]) return false; |
| @@ -3363,7 +3527,7 @@ class InterfaceType extends DartType { |
| } |
| int get hashCode { |
| - int hash = 0x3fffffff & classNode.hashCode; |
| + int hash = 0x3fffffff & className.hashCode; |
| for (int i = 0; i < typeArguments.length; ++i) { |
| hash = 0x3fffffff & (hash * 31 + (hash ^ typeArguments[i].hashCode)); |
| } |
| @@ -3551,10 +3715,15 @@ class TypeParameter extends TreeNode { |
| } |
| class Supertype extends Node { |
| - final Class classNode; |
| + final LinkedNodeBox className; |
| final List<DartType> typeArguments; |
| - Supertype(this.classNode, this.typeArguments); |
| + Supertype(Class classNode, List<DartType> typeArguments) |
| + : this.byBox(getBoxOfClass(classNode), typeArguments); |
| + |
| + Supertype.byBox(this.className, this.typeArguments); |
| + |
| + Class get classNode => className.asClass; |
| accept(Visitor v) => v.visitSupertype(this); |
| @@ -3570,7 +3739,7 @@ class Supertype extends Node { |
| bool operator ==(Object other) { |
| if (identical(this, other)) return true; |
| if (other is Supertype) { |
| - if (classNode != other.classNode) return false; |
| + if (className != other.className) return false; |
| if (typeArguments.length != other.typeArguments.length) return false; |
| for (int i = 0; i < typeArguments.length; ++i) { |
| if (typeArguments[i] != other.typeArguments[i]) return false; |
| @@ -3582,7 +3751,7 @@ class Supertype extends Node { |
| } |
| int get hashCode { |
| - int hash = 0x3fffffff & classNode.hashCode; |
| + int hash = 0x3fffffff & className.hashCode; |
| for (int i = 0; i < typeArguments.length; ++i) { |
| hash = 0x3fffffff & (hash * 31 + (hash ^ typeArguments[i].hashCode)); |
| } |
| @@ -3596,6 +3765,8 @@ class Supertype extends Node { |
| /// A way to bundle up all the libraries in a program. |
| class Program extends TreeNode { |
| + final CanonicalName root = new CanonicalName.root(); |
| + |
| final List<Library> libraries; |
| /// Map from a source file uri to a line-starts table and source code. |
| @@ -3604,12 +3775,29 @@ class Program extends TreeNode { |
| final Map<String, Source> uriToSource; |
| /// Reference to the main method in one of the libraries. |
| - Procedure mainMethod; |
| + LinkedNodeBox mainMethodName; |
| Program([List<Library> libraries, Map<String, Source> uriToSource]) |
| : libraries = libraries ?? <Library>[], |
| uriToSource = uriToSource ?? <String, Source>{} { |
| - setParents(libraries, this); |
| + setParents(this.libraries, this); |
| + } |
| + |
| + void computeCanonicalNames() { |
| + for (var library in libraries) { |
| + root.getChildFromUri(library.importUri).bindTo(library.box); |
| + library.computeCanonicalNames(); |
| + } |
| + } |
| + |
| + void unbindCanonicalNames() { |
| + root.unbindAll(); |
| + } |
| + |
| + Procedure get mainMethod => mainMethodName?.asProcedure; |
| + |
| + void set mainMethod(Procedure main) { |
| + mainMethodName = getBoxOfMember(main); |
| } |
| accept(TreeVisitor v) => v.visitProgram(this); |
| @@ -3752,3 +3940,63 @@ class Source { |
| Source(this.lineStarts, this.source); |
| } |
| + |
| +/// Returns the canonical name of [member], or throws an exception if the |
| +/// member has not been assigned a canonical name yet. |
| +/// |
| +/// Returns `null` if the member is `null`. |
| +LinkedNodeBox getBoxOfMember(Member member) { |
| + return member?.box; |
| +} |
| + |
| +/// Returns the canonical name of [class_], or throws an exception if the |
| +/// class has not been assigned a canonical name yet. |
| +/// |
| +/// Returns `null` if the class is `null`. |
| +LinkedNodeBox getBoxOfClass(Class class_) { |
| + return class_?.box; |
| +} |
| + |
| +/// Returns the canonical name of [library], or throws an exception if the |
| +/// library has not been assigned a canonical name yet. |
| +/// |
| +/// Returns `null` if the library is `null`. |
| +LinkedNodeBox getBoxOfLibrary(Library library) { |
| + return library?.box; |
| +} |
| + |
| +/// Returns the canonical name of [member], or throws an exception if the |
| +/// member has not been assigned a canonical name yet. |
| +/// |
| +/// Returns `null` if the member is `null`. |
| +CanonicalName getCanonicalNameOfMember(Member member) { |
| + if (member == null) return null; |
| + if (member.canonicalName == null) { |
| + throw '$member has no canonical name'; |
| + } |
| + return member.canonicalName; |
| +} |
| + |
| +/// Returns the canonical name of [class_], or throws an exception if the |
| +/// class has not been assigned a canonical name yet. |
| +/// |
| +/// Returns `null` if the class is `null`. |
| +CanonicalName getCanonicalNameOfClass(Class class_) { |
| + if (class_ == null) return null; |
| + if (class_.canonicalName == null) { |
| + throw '$class_ has no canonical name'; |
| + } |
| + return class_.canonicalName; |
| +} |
| + |
| +/// Returns the canonical name of [library], or throws an exception if the |
| +/// library has not been assigned a canonical name yet. |
| +/// |
| +/// Returns `null` if the library is `null`. |
| +CanonicalName getCanonicalNameOfLibrary(Library library) { |
| + if (library == null) return null; |
| + if (library.canonicalName == null) { |
| + throw '$library has no canonical name'; |
| + } |
| + return library.canonicalName; |
| +} |