Index: pkg/kernel/lib/ast.dart |
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart |
index f35e754d4d1c5238c2e6257267b16a26fcf38ddb..99d51d0a2444abbadd1b2299e16750541434c36a 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.bindTo]. |
+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,10 @@ class Library extends TreeNode implements Comparable<Library> { |
<Iterable<Member>>[fields, procedures].expand((x) => x); |
void addMember(Member member) { |
+ if (member.canonicalName == null || !member.canonicalName.isDummy) { |
+ // This should not run from the dart2js/rasta adaptor. |
ahe
2017/02/02 16:24:01
Add TODO?
asgerf
2017/02/03 10:31:16
I don't think it actually helps to spray non-actio
|
+ getCanonicalNameOfLibrary(this).getChildFromMember(member).bindTo(member); |
+ } |
member.parent = this; |
if (member is Procedure) { |
procedures.add(member); |
@@ -216,6 +235,10 @@ class Library extends TreeNode implements Comparable<Library> { |
} |
void addClass(Class class_) { |
+ if (class_.canonicalName == null || !class_.canonicalName.isDummy) { |
+ // This should not run from the dart2js/rasta adaptor. |
+ getCanonicalNameOfLibrary(this).getChild(class_.name).bindTo(class_); |
+ } |
class_.parent = this; |
classes.add(class_); |
} |
@@ -289,7 +312,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 +420,10 @@ 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 || !member.canonicalName.isDummy) { |
+ // This should not run from the dart2js/rasta adaptor. |
+ getCanonicalNameOfClass(this).getChildFromMember(member).bindTo(member); |
+ } |
member.parent = this; |
if (member is Constructor) { |
constructors.add(member); |
@@ -490,14 +517,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 +605,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 +612,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 +632,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 +731,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 +805,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 +823,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 +838,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 +910,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 +955,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?.asField; |
+ |
+ void set field(Field field) { |
+ fieldName = getCanonicalNameOfMember(field); |
+ } |
+ |
accept(InitializerVisitor v) => v.visitFieldInitializer(this); |
visitChildren(Visitor v) { |
@@ -1028,13 +997,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?.asConstructor; |
+ |
+ void set target(Constructor target) { |
+ targetName = getCanonicalNameOfMember(target); |
+ } |
+ |
accept(InitializerVisitor v) => v.visitSuperInitializer(this); |
visitChildren(Visitor v) { |
@@ -1057,13 +1035,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?.asConstructor; |
+ |
+ void set target(Constructor target) { |
+ targetName = getCanonicalNameOfMember(target); |
+ } |
+ |
accept(InitializerVisitor v) => v.visitRedirectingInitializer(this); |
visitChildren(Visitor v) { |
@@ -1356,17 +1343,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 +1402,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 +1446,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 +1489,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 +1531,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 +1590,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 +1632,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 +1667,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 +1695,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 +1804,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 +1884,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 +1934,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 +1942,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 +1986,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,17 +3209,21 @@ 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 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); |
} |
@@ -3149,21 +3241,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 +3338,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 +3371,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 +3383,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 +3571,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 +3595,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 +3607,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 +3621,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 +3631,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 +3677,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.bindTo(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 +3799,51 @@ 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; |
+} |
+ |
+/// 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; |
+ } |
+ 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; |
+} |