Chromium Code Reviews| Index: pkg/kernel/lib/ast.dart |
| diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart |
| index f35e754d4d1c5238c2e6257267b16a26fcf38ddb..14c256e0af9ac43872a3b847ff9a01ff83690993 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,23 @@ abstract class TreeNode extends Node { |
| } |
| } |
| +/// An AST node that has an associated [CanonicalName], allowing it to be |
| +/// referenced by name. Libraries, classes, and members are linked nodes. |
| +/// |
| +/// When created, a linked node has no associated canonical name, and must be |
| +/// linked to such a name before it can be referenced. A canonical name is |
| +/// typically assigned by either: |
| +/// - Adding it to the a class or library using `addMember` or `addClass`. |
| +/// - Explicitly assigning a name using [CanonicalName.linkTo]. |
| +abstract class LinkedNode extends TreeNode { |
| + CanonicalName canonicalName; |
| +} |
| + |
| // ------------------------------------------------------------------------ |
| // 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. |
| @@ -205,6 +220,9 @@ class Library extends TreeNode implements Comparable<Library> { |
| <Iterable<Member>>[fields, procedures].expand((x) => x); |
| void addMember(Member member) { |
| + if (member.canonicalName == null) { |
| + getCanonicalNameOfLibrary(this).getChildFromMember(member).linkTo(member); |
|
ahe
2017/01/30 17:16:16
Would it make sense to move this to "set parent"?
asgerf
2017/02/02 12:30:27
I don't see why. Set parent is the low-level acces
|
| + } |
| member.parent = this; |
| if (member is Procedure) { |
| procedures.add(member); |
| @@ -216,6 +234,9 @@ class Library extends TreeNode implements Comparable<Library> { |
| } |
| void addClass(Class class_) { |
| + if (class_.canonicalName == null) { |
| + getCanonicalNameOfLibrary(this).getChild(class_.name).linkTo(class_); |
| + } |
| class_.parent = this; |
| classes.add(class_); |
| } |
| @@ -289,7 +310,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; |
| @@ -397,6 +418,9 @@ class Class extends TreeNode { |
| /// Throws an error if attempting to add a field or procedure to a mixin |
| /// application. |
| void addMember(Member member) { |
| + if (member.canonicalName == null) { |
| + getCanonicalNameOfClass(this).getChildFromMember(member).linkTo(member); |
| + } |
|
kustermann
2017/02/01 13:00:54
Should we do some verification in the else branch,
asgerf
2017/02/02 12:30:27
The assertion is equivalent to always doing linkTo
|
| member.parent = this; |
| if (member is Constructor) { |
| constructors.add(member); |
| @@ -490,14 +514,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). |
| @@ -585,9 +602,6 @@ abstract class Member extends TreeNode { |
| bool get containsSuperCalls { |
| return transformerFlags & TransformerFlag.superCalls != 0; |
| } |
| - |
| - _MemberAccessor get _getterInterface; |
| - _MemberAccessor get _setterInterface; |
| } |
| /// A field declaration. |
| @@ -595,8 +609,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; |
| @@ -617,8 +629,6 @@ class Field extends Member { |
| int transformerFlags: 0, |
| this.fileUri}) |
| : super(name) { |
| - _getterInterface = new _MemberAccessor(this); |
| - _setterInterface = new _MemberAccessor(this); |
| assert(type != null); |
| initializer?.parent = this; |
| this.isFinal = isFinal; |
| @@ -718,46 +728,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); |
| } |
| @@ -832,14 +802,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, |
| @@ -858,7 +820,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. |
| @@ -874,7 +835,6 @@ class Procedure extends Member { |
| int transformerFlags: 0, |
| this.fileUri}) |
| : super(name) { |
| - _reference = new _MemberAccessor(this); |
| function?.parent = this; |
| this.isAbstract = isAbstract; |
| this.isStatic = isStatic; |
| @@ -947,9 +907,6 @@ class Procedure extends Member { |
| : const BottomType(); |
| } |
| - _MemberAccessor get _getterInterface => _reference; |
| - _MemberAccessor get _setterInterface => _reference; |
| - |
| Location _getLocationInEnclosingFile(int offset) { |
| return enclosingProgram.getLocation(fileUri, offset); |
| } |
| @@ -995,13 +952,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; |
| + CanonicalName fieldName; |
| Expression value; |
| - FieldInitializer(this.field, this.value) { |
| + FieldInitializer(Field field, Expression value) |
| + : this.byName(getCanonicalNameOfMember(field), value); |
| + |
| + FieldInitializer.byName(this.fieldName, this.value) { |
| value?.parent = this; |
| } |
| + Field get field => fieldName?.definition as Field; |
|
kustermann
2017/02/01 13:00:54
Could you use fieldName?.asField here?
Or is this
asgerf
2017/02/02 12:30:27
Yep, it was supposed to say fieldName?.asField.
|
| + |
| + void set field(Field field) { |
| + fieldName = getCanonicalNameOfMember(field); |
| + } |
| + |
| accept(InitializerVisitor v) => v.visitFieldInitializer(this); |
| visitChildren(Visitor v) { |
| @@ -1028,13 +994,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; |
| + CanonicalName targetName; |
| Arguments arguments; |
| - SuperInitializer(this.target, this.arguments) { |
| + SuperInitializer(Constructor target, Arguments arguments) |
| + : this.byName(getCanonicalNameOfMember(target), arguments); |
| + |
| + SuperInitializer.byName(this.targetName, this.arguments) { |
| arguments?.parent = this; |
| } |
| + Constructor get target => targetName?.definition as Constructor; |
|
kustermann
2017/02/01 13:00:54
ditto
asgerf
2017/02/02 12:30:27
Done.
|
| + |
| + void set target(Constructor target) { |
| + targetName = getCanonicalNameOfMember(target); |
| + } |
| + |
| accept(InitializerVisitor v) => v.visitSuperInitializer(this); |
| visitChildren(Visitor v) { |
| @@ -1057,13 +1032,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; |
| + CanonicalName targetName; |
| Arguments arguments; |
| - RedirectingInitializer(this.target, this.arguments) { |
| + RedirectingInitializer(Constructor target, Arguments arguments) |
| + : this.byName(getCanonicalNameOfMember(target), arguments); |
| + |
| + RedirectingInitializer.byName(this.targetName, this.arguments) { |
| arguments?.parent = this; |
| } |
| + Constructor get target => targetName?.definition as Constructor; |
|
kustermann
2017/02/01 13:00:54
ditto
asgerf
2017/02/02 12:30:27
Done.
|
| + |
| + void set target(Constructor target) { |
| + targetName = getCanonicalNameOfMember(target); |
| + } |
| + |
| accept(InitializerVisitor v) => v.visitRedirectingInitializer(this); |
| visitChildren(Visitor v) { |
| @@ -1356,17 +1340,19 @@ class PropertyGet extends Expression { |
| Expression receiver; |
| Name name; |
| - _MemberAccessor _interfaceTargetReference; |
| + CanonicalName interfaceTargetName; |
| + |
| + PropertyGet(Expression receiver, Name name, [Member interfaceTarget]) |
| + : this.byName(receiver, name, getCanonicalNameOfMember(interfaceTarget)); |
| - PropertyGet(this.receiver, this.name, [Member interfaceTarget]) { |
| + PropertyGet.byName(this.receiver, this.name, this.interfaceTargetName) { |
| receiver?.parent = this; |
| - this.interfaceTarget = interfaceTarget; |
| } |
| - Member get interfaceTarget => _interfaceTargetReference?.target; |
| + Member get interfaceTarget => interfaceTargetName?.asMember; |
| - void set interfaceTarget(Member newTarget) { |
| - _interfaceTargetReference = newTarget?._getterInterface; |
| + void set interfaceTarget(Member member) { |
| + interfaceTargetName = getCanonicalNameOfMember(member); |
| } |
| DartType getStaticType(TypeEnvironment types) { |
| @@ -1413,18 +1399,23 @@ class PropertySet extends Expression { |
| Name name; |
| Expression value; |
| - _MemberAccessor _interfaceTargetReference; |
| + CanonicalName interfaceTargetName; |
| + |
| + PropertySet(Expression receiver, Name name, Expression value, |
| + [Member interfaceTarget]) |
| + : this.byName( |
| + receiver, name, value, getCanonicalNameOfMember(interfaceTarget)); |
| - PropertySet(this.receiver, this.name, this.value, [Member interfaceTarget]) { |
| + PropertySet.byName( |
| + this.receiver, this.name, this.value, this.interfaceTargetName) { |
| receiver?.parent = this; |
| value?.parent = this; |
| - this.interfaceTarget = interfaceTarget; |
| } |
| - Member get interfaceTarget => _interfaceTargetReference?.target; |
| + Member get interfaceTarget => interfaceTargetName?.asMember; |
| - void set interfaceTarget(Member newTarget) { |
| - _interfaceTargetReference = newTarget?._setterInterface; |
| + void set interfaceTarget(Member member) { |
| + interfaceTargetName = getCanonicalNameOfMember(member); |
| } |
| DartType getStaticType(TypeEnvironment types) => value.getStaticType(types); |
| @@ -1452,12 +1443,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; |
| + CanonicalName targetName; |
| - DirectPropertyGet(this.receiver, this.target) { |
| + DirectPropertyGet(Expression receiver, Member target) |
| + : this.byName(receiver, getCanonicalNameOfMember(target)); |
| + |
| + DirectPropertyGet.byName(this.receiver, this.targetName) { |
| receiver?.parent = this; |
| } |
| + Member get target => targetName?.asMember; |
| + |
| + void set target(Member target) { |
| + targetName = getCanonicalNameOfMember(target); |
| + } |
| + |
| visitChildren(Visitor v) { |
| receiver?.accept(v); |
| target?.acceptReference(v); |
| @@ -1486,14 +1486,23 @@ class DirectPropertyGet extends Expression { |
| /// Evaluates to the value of [value]. |
| class DirectPropertySet extends Expression { |
| Expression receiver; |
| - Member target; |
| + CanonicalName targetName; |
| Expression value; |
| - DirectPropertySet(this.receiver, this.target, this.value) { |
| + DirectPropertySet(Expression receiver, Member target, Expression value) |
| + : this.byName(receiver, getCanonicalNameOfMember(target), value); |
| + |
| + DirectPropertySet.byName(this.receiver, this.targetName, this.value) { |
| receiver?.parent = this; |
| value?.parent = this; |
| } |
| + Member get target => targetName?.asMember; |
| + |
| + void set target(Member target) { |
| + targetName = getCanonicalNameOfMember(target); |
| + } |
| + |
| visitChildren(Visitor v) { |
| receiver?.accept(v); |
| target?.acceptReference(v); |
| @@ -1519,14 +1528,25 @@ class DirectPropertySet extends Expression { |
| /// Directly call an instance method, bypassing ordinary dispatch. |
| class DirectMethodInvocation extends Expression { |
| Expression receiver; |
| - Procedure target; |
| + CanonicalName targetName; |
| Arguments arguments; |
| - DirectMethodInvocation(this.receiver, this.target, this.arguments) { |
| + DirectMethodInvocation( |
| + Expression receiver, Procedure target, Arguments arguments) |
| + : this.byName(receiver, getCanonicalNameOfMember(target), arguments); |
| + |
| + DirectMethodInvocation.byName( |
| + this.receiver, this.targetName, this.arguments) { |
| receiver?.parent = this; |
| arguments?.parent = this; |
| } |
| + Procedure get target => targetName?.asProcedure; |
| + |
| + void set target(Procedure target) { |
| + targetName = getCanonicalNameOfMember(target); |
| + } |
| + |
| visitChildren(Visitor v) { |
| receiver?.accept(v); |
| target?.acceptReference(v); |
| @@ -1567,16 +1587,17 @@ class DirectMethodInvocation extends Expression { |
| /// This may invoke a getter, read a field, or tear off a method. |
| class SuperPropertyGet extends Expression { |
| Name name; |
| - _MemberAccessor _interfaceTargetReference; |
| + CanonicalName interfaceTargetName; |
| - SuperPropertyGet(this.name, [Member interfaceTarget]) { |
| - _interfaceTargetReference = interfaceTarget?._getterInterface; |
| - } |
| + SuperPropertyGet(Name name, [Member interfaceTarget]) |
| + : this.byName(name, getCanonicalNameOfMember(interfaceTarget)); |
| - Member get interfaceTarget => _interfaceTargetReference?.target; |
| + SuperPropertyGet.byName(this.name, this.interfaceTargetName); |
| - void set interfaceTarget(Member newTarget) { |
| - _interfaceTargetReference = newTarget?._getterInterface; |
| + Member get interfaceTarget => interfaceTargetName?.asMember; |
| + |
| + void set interfaceTarget(Member member) { |
| + interfaceTargetName = getCanonicalNameOfMember(member); |
| } |
| DartType getStaticType(TypeEnvironment types) { |
| @@ -1608,17 +1629,19 @@ class SuperPropertyGet extends Expression { |
| class SuperPropertySet extends Expression { |
| Name name; |
| Expression value; |
| - _MemberAccessor _interfaceTargetReference; |
| + CanonicalName interfaceTargetName; |
| + |
| + SuperPropertySet(Name name, Expression value, Member interfaceTarget) |
| + : this.byName(name, value, getCanonicalNameOfMember(interfaceTarget)); |
| - SuperPropertySet(this.name, this.value, [Member interfaceTarget]) { |
| + SuperPropertySet.byName(this.name, this.value, this.interfaceTargetName) { |
| value?.parent = this; |
| - _interfaceTargetReference = interfaceTarget?._setterInterface; |
| } |
| - Member get interfaceTarget => _interfaceTargetReference?.target; |
| + Member get interfaceTarget => interfaceTargetName?.asMember; |
| - void set interfaceTarget(Member newTarget) { |
| - _interfaceTargetReference = newTarget?._setterInterface; |
| + void set interfaceTarget(Member member) { |
| + interfaceTargetName = getCanonicalNameOfMember(member); |
| } |
| DartType getStaticType(TypeEnvironment types) => value.getStaticType(types); |
| @@ -1641,9 +1664,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; |
| + CanonicalName targetName; |
| + |
| + StaticGet(Member target) : this.byName(getCanonicalNameOfMember(target)); |
| + |
| + StaticGet.byName(this.targetName); |
| - StaticGet(this.target); |
| + Member get target => targetName?.asMember; |
| + |
| + void set target(Member target) { |
| + targetName = getCanonicalNameOfMember(target); |
| + } |
| DartType getStaticType(TypeEnvironment types) => target.getterType; |
| @@ -1661,13 +1692,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; |
| + CanonicalName targetName; |
| Expression value; |
| - StaticSet(this.target, this.value) { |
| + StaticSet(Member target, Expression value) |
| + : this.byName(getCanonicalNameOfMember(target), value); |
| + |
| + StaticSet.byName(this.targetName, this.value) { |
| value?.parent = this; |
| } |
| + Member get target => targetName?.asMember; |
| + |
| + void set target(Member target) { |
| + targetName = getCanonicalNameOfMember(target); |
| + } |
| + |
| DartType getStaticType(TypeEnvironment types) => value.getStaticType(types); |
| accept(ExpressionVisitor v) => v.visitStaticSet(this); |
| @@ -1761,14 +1801,25 @@ class MethodInvocation extends InvocationExpression { |
| Name name; |
| Arguments arguments; |
| - Procedure interfaceTarget; |
| + CanonicalName interfaceTargetName; |
| + |
| + MethodInvocation(Expression receiver, Name name, Arguments arguments, |
| + [Procedure interfaceTarget]) |
| + : this.byName(receiver, name, arguments, |
| + getCanonicalNameOfMember(interfaceTarget)); |
| - MethodInvocation(this.receiver, this.name, this.arguments, |
| - [this.interfaceTarget]) { |
| + MethodInvocation.byName( |
| + this.receiver, this.name, this.arguments, this.interfaceTargetName) { |
| receiver?.parent = this; |
| arguments?.parent = this; |
| } |
| + Procedure get interfaceTarget => interfaceTargetName?.asProcedure; |
| + |
| + void set interfaceTarget(Member target) { |
| + interfaceTargetName = getCanonicalNameOfMember(target); |
| + } |
| + |
| DartType getStaticType(TypeEnvironment types) { |
| if (interfaceTarget != null) { |
| if (types.isOverloadedArithmeticOperator(interfaceTarget)) { |
| @@ -1830,12 +1881,23 @@ class SuperMethodInvocation extends InvocationExpression { |
| Name name; |
| Arguments arguments; |
| - Member interfaceTarget; |
| + CanonicalName interfaceTargetName; |
| - SuperMethodInvocation(this.name, this.arguments, this.interfaceTarget) { |
| + SuperMethodInvocation(Name name, Arguments arguments, |
| + [Procedure interfaceTarget]) |
| + : this.byName(name, arguments, getCanonicalNameOfMember(interfaceTarget)); |
| + |
| + SuperMethodInvocation.byName( |
| + this.name, this.arguments, this.interfaceTargetName) { |
| arguments?.parent = this; |
| } |
| + Procedure get interfaceTarget => interfaceTargetName?.asProcedure; |
| + |
| + void set interfaceTarget(Procedure target) { |
| + interfaceTargetName = getCanonicalNameOfMember(target); |
| + } |
| + |
| DartType getStaticType(TypeEnvironment types) { |
| if (interfaceTarget == null) return const DynamicType(); |
| Class superclass = interfaceTarget.enclosingClass; |
| @@ -1869,7 +1931,7 @@ class SuperMethodInvocation extends InvocationExpression { |
| /// |
| /// The provided arguments might not match the parameters of the target. |
| class StaticInvocation extends InvocationExpression { |
| - Procedure target; |
| + CanonicalName targetName; |
| Arguments arguments; |
| /// True if this is a constant call to an external constant factory. |
| @@ -1877,10 +1939,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.byName(getCanonicalNameOfMember(target), arguments, |
| + isConst: isConst); |
| + |
| + StaticInvocation.byName(this.targetName, this.arguments, |
| + {this.isConst: false}) { |
| arguments?.parent = this; |
| } |
| + Procedure get target => targetName?.asProcedure; |
| + |
| + void set target(Procedure target) { |
| + targetName = getCanonicalNameOfMember(target); |
| + } |
| + |
| DartType getStaticType(TypeEnvironment types) { |
| return Substitution |
| .fromPairs(target.function.typeParameters, arguments.types) |
| @@ -1910,16 +1983,28 @@ class StaticInvocation extends InvocationExpression { |
| // `classTypeArguments`? They are quite different from type arguments to |
| // generic functions. |
| class ConstructorInvocation extends InvocationExpression { |
| - Constructor target; |
| + CanonicalName targetName; |
| 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.byName(getCanonicalNameOfMember(target), arguments, |
| + isConst: isConst); |
| + |
| + ConstructorInvocation.byName(this.targetName, this.arguments, |
| + {this.isConst: false}) { |
| arguments?.parent = this; |
| } |
| + Constructor get target => targetName?.asConstructor; |
| + |
| + void set target(Constructor target) { |
| + targetName = getCanonicalNameOfMember(target); |
| + } |
| + |
| DartType getStaticType(TypeEnvironment types) { |
| return arguments.types.isEmpty |
| ? target.enclosingClass.rawType |
| @@ -3121,12 +3206,16 @@ class FunctionDeclaration extends Statement { |
| abstract class Name implements Node { |
| final int hashCode; |
| final String name; |
| + CanonicalName 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?.canonicalName); |
| + |
| + factory Name.byReference(String name, CanonicalName library) { |
|
kustermann
2017/02/01 13:00:54
library -> libraryName
asgerf
2017/02/02 12:30:27
Done.
|
| /// Use separate subclasses for the public and private case to save memory |
| /// for public names. |
| if (name.startsWith('_')) { |
| @@ -3149,21 +3238,24 @@ abstract class Name implements Node { |
| } |
| class _PrivateName extends Name { |
| - final Library library; |
| + final CanonicalName libraryName; |
| bool get isPrivate => true; |
| - _PrivateName(String name, Library library) |
| - : this.library = library, |
| - super._internal(_computeHashCode(name, library), name); |
| + _PrivateName(String name, CanonicalName 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, CanonicalName libraryName) { |
| + return 131 * name.hashCode + 17 * libraryName.hashCode; |
| } |
| } |
| class _PublicName extends Name { |
| + CanonicalName get libraryName => null; |
| Library get library => null; |
| bool get isPrivate => false; |
| @@ -3243,14 +3335,18 @@ class BottomType extends DartType { |
| } |
| class InterfaceType extends DartType { |
| - final Class classNode; |
| + final CanonicalName 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.byName(getCanonicalNameOfClass(classNode), |
| + typeArguments ?? _defaultTypeArguments(classNode)); |
| + |
| + InterfaceType.byName(this.className, this.typeArguments); |
| + |
| + Class get classNode => className.asClass; |
| static List<DartType> _defaultTypeArguments(Class classNode) { |
| if (classNode.typeParameters.length == 0) { |
| @@ -3272,7 +3368,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; |
| @@ -3284,7 +3380,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)); |
| } |
| @@ -3472,10 +3568,15 @@ class TypeParameter extends TreeNode { |
| } |
| class Supertype extends Node { |
| - final Class classNode; |
| + final CanonicalName className; |
| final List<DartType> typeArguments; |
| - Supertype(this.classNode, this.typeArguments); |
| + Supertype(Class classNode, List<DartType> typeArguments) |
| + : this.byName(getCanonicalNameOfClass(classNode), typeArguments); |
| + |
| + Supertype.byName(this.className, this.typeArguments); |
| + |
| + Class get classNode => className.asClass; |
| accept(Visitor v) => v.visitSupertype(this); |
| @@ -3491,7 +3592,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; |
| @@ -3503,7 +3604,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)); |
| } |
| @@ -3517,6 +3618,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. |
| @@ -3525,12 +3628,18 @@ class Program extends TreeNode { |
| final Map<String, Source> uriToSource; |
| /// Reference to the main method in one of the libraries. |
| - Procedure mainMethod; |
| + CanonicalName mainMethodName; |
| Program([List<Library> libraries, Map<String, Source> uriToSource]) |
| : libraries = libraries ?? <Library>[], |
| uriToSource = uriToSource ?? <String, Source>{} { |
| - setParents(libraries, this); |
| + setParents(this.libraries, this); |
| + } |
| + |
| + Procedure get mainMethod => mainMethodName?.asProcedure; |
| + |
| + void set mainMethod(Procedure main) { |
| + mainMethodName = getCanonicalNameOfMember(main); |
| } |
| accept(TreeVisitor v) => v.visitProgram(this); |
| @@ -3565,6 +3674,20 @@ class Program extends TreeNode { |
| int columnNumber = 1 + offset - lineStart; |
| return new Location(file, lineNumber, columnNumber); |
| } |
| + |
| + Library getLibraryReference(Uri uri) { |
| + assert(uri.hasScheme); |
| + var canonicalName = root.getChildFromUri(uri); |
| + Library library; |
| + if (canonicalName.definition == null) { |
| + library = new Library(uri, isExternal: true); |
| + canonicalName.linkTo(library); |
| + libraries.add(library..parent = this); |
| + } else { |
| + library = canonicalName.definition; |
| + } |
| + return library; |
| + } |
| } |
| /// A tuple with file, line, and column number, for displaying human-readable |
| @@ -3673,3 +3796,47 @@ 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`. |
| +CanonicalName getCanonicalNameOfMember(Member member) { |
| + if (member == null) { |
| + return null; |
| + } |
| + var name = member.canonicalName; |
| + if (name == null) { |
| + throw '$member has no canonical name. ' |
| + 'It must be added to a class or library before it can be referenced.'; |
| + } |
| + return name; |
| +} |
| + |
| +/// 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; |
| + } |
| + var name = class_.canonicalName; |
| + if (name == null) { |
| + throw '$class_ has no canonical name. ' |
| + 'It must be added to a library before it can be referenced.'; |
| + } |
| + return name; |
| +} |
| + |
| +CanonicalName getCanonicalNameOfLibrary(Library library) { |
|
kustermann
2017/02/01 13:00:54
for consistency you can add the comment here as we
asgerf
2017/02/02 12:30:27
Done.
|
| + if (library == null) { |
| + return null; |
| + } |
| + var name = library.canonicalName; |
| + if (name == null) { |
| + throw '$library has no canonical name. ' |
| + 'It must be added to a program before it can be referenced.'; |
| + } |
| + return name; |
| +} |