| Index: pkg/kernel/lib/ast.dart
|
| diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
|
| index 2f3cb111d74337e809f435bacbdfa2000ae8f9db..4bcc7f8e358581854631c9e2d8044e70962a41e9 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,86 @@ abstract class TreeNode extends Node {
|
| }
|
| }
|
|
|
| +/// An AST node that can be referenced by other nodes.
|
| +///
|
| +/// There is a single [reference] belonging to this node, providing a level of
|
| +/// indirection that is needed during serialization.
|
| +abstract class NamedNode extends TreeNode {
|
| + final Reference reference;
|
| +
|
| + NamedNode(Reference reference)
|
| + : this.reference = reference ?? new Reference() {
|
| + this.reference.node = this;
|
| + }
|
| +
|
| + CanonicalName get canonicalName => reference?.canonicalName;
|
| +}
|
| +
|
| +/// Indirection between a reference and its definition.
|
| +///
|
| +/// There is only one reference object per [NamedNode].
|
| +class Reference {
|
| + CanonicalName canonicalName;
|
| + NamedNode node;
|
| +
|
| + String toString() {
|
| + if (canonicalName != null) {
|
| + return 'Reference to $canonicalName';
|
| + }
|
| + if (node != null) {
|
| + return 'Reference to $node';
|
| + }
|
| + return 'Unbound reference';
|
| + }
|
| +
|
| + Library get asLibrary {
|
| + if (node == null) {
|
| + throw '$this is not bound to an AST node. A library was expected';
|
| + }
|
| + return node as Library;
|
| + }
|
| +
|
| + Class get asClass {
|
| + if (node == null) {
|
| + throw '$this is not bound to an AST node. A class was expected';
|
| + }
|
| + return node as Class;
|
| + }
|
| +
|
| + Member get asMember {
|
| + if (node == null) {
|
| + throw '$this is not bound to an AST node. A member was expected';
|
| + }
|
| + return node as Member;
|
| + }
|
| +
|
| + Field get asField {
|
| + if (node == null) {
|
| + throw '$this is not bound to an AST node. A field was expected';
|
| + }
|
| + return node as Field;
|
| + }
|
| +
|
| + Constructor get asConstructor {
|
| + if (node == null) {
|
| + throw '$this is not bound to an AST node. A constructor was expected';
|
| + }
|
| + return node as Constructor;
|
| + }
|
| +
|
| + Procedure get asProcedure {
|
| + if (node == null) {
|
| + throw '$this is not bound to an AST node. A procedure was expected';
|
| + }
|
| + return node as Procedure;
|
| + }
|
| +}
|
| +
|
| // ------------------------------------------------------------------------
|
| // LIBRARIES and CLASSES
|
| // ------------------------------------------------------------------------
|
|
|
| -class Library extends TreeNode implements Comparable<Library> {
|
| +class Library extends NamedNode implements Comparable<Library> {
|
| /// An import path to this library.
|
| ///
|
| /// The [Uri] should have the `dart`, `package`, `app`, or `file` scheme.
|
| @@ -191,11 +269,13 @@ class Library extends TreeNode implements Comparable<Library> {
|
| List<Class> classes,
|
| List<Procedure> procedures,
|
| List<Field> fields,
|
| - this.fileUri})
|
| + this.fileUri,
|
| + Reference reference})
|
| : this.deferredImports = imports ?? <DeferredImport>[],
|
| this.classes = classes ?? <Class>[],
|
| this.procedures = procedures ?? <Procedure>[],
|
| - this.fields = fields ?? <Field>[] {
|
| + this.fields = fields ?? <Field>[],
|
| + super(reference) {
|
| setParents(this.classes, this);
|
| setParents(this.procedures, this);
|
| setParents(this.fields, this);
|
| @@ -224,6 +304,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.reference);
|
| + }
|
| + for (var member in procedures) {
|
| + canonicalName.getChildFromMember(member).bindTo(member.reference);
|
| + }
|
| + for (var class_ in classes) {
|
| + canonicalName.getChild(class_.name).bindTo(class_.reference);
|
| + class_.computeCanonicalNames();
|
| + }
|
| + }
|
| +
|
| accept(TreeVisitor v) => v.visitLibrary(this);
|
|
|
| visitChildren(Visitor v) {
|
| @@ -254,12 +348,16 @@ class Library extends TreeNode implements Comparable<Library> {
|
|
|
| /// An import of form: `import <url> deferred as <name>;`.
|
| class DeferredImport extends TreeNode {
|
| - Library importedLibrary;
|
| + Reference importedLibraryReference;
|
| String name;
|
|
|
| - DeferredImport(this.importedLibrary, this.name);
|
| + DeferredImport(Library importedLibrary, String name)
|
| + : this.byReference(importedLibrary.reference, name);
|
| +
|
| + DeferredImport.byReference(this.importedLibraryReference, this.name);
|
|
|
| Library get enclosingLibrary => parent;
|
| + Library get importedLibrary => importedLibraryReference.asLibrary;
|
|
|
| accept(TreeVisitor v) => v.visitDeferredImport(this);
|
|
|
| @@ -321,7 +419,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 NamedNode {
|
| /// The degree to which the contents of the class have been loaded.
|
| ClassLevel level = ClassLevel.Body;
|
|
|
| @@ -378,18 +476,33 @@ class Class extends TreeNode {
|
| List<Constructor> constructors,
|
| List<Procedure> procedures,
|
| List<Field> fields,
|
| - this.fileUri})
|
| + this.fileUri,
|
| + Reference reference})
|
| : 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(reference) {
|
| 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.reference);
|
| + }
|
| + for (var member in procedures) {
|
| + canonicalName.getChildFromMember(member).bindTo(member.reference);
|
| + }
|
| + for (var member in constructors) {
|
| + canonicalName.getChildFromMember(member).bindTo(member.reference);
|
| + }
|
| + }
|
| +
|
| /// The immediate super class, or `null` if this is the root class.
|
| Class get superclass => supertype?.classNode;
|
|
|
| @@ -522,14 +635,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 NamedNode {
|
| /// 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 +665,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, Reference reference) : super(reference);
|
|
|
| Class get enclosingClass => parent is Class ? parent : null;
|
| Library get enclosingLibrary => parent is Class ? parent.parent : parent;
|
| @@ -617,9 +723,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 +730,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 +748,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,
|
| + Reference reference})
|
| + : super(name, reference) {
|
| assert(type != null);
|
| initializer?.parent = this;
|
| this.isFinal = isFinal;
|
| @@ -750,46 +850,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 +873,10 @@ class Constructor extends Member {
|
| bool isConst: false,
|
| bool isExternal: false,
|
| List<Initializer> initializers,
|
| - int transformerFlags: 0})
|
| + int transformerFlags: 0,
|
| + Reference reference})
|
| : this.initializers = initializers ?? <Initializer>[],
|
| - super(name) {
|
| + super(name, reference) {
|
| function?.parent = this;
|
| setParents(this.initializers, this);
|
| this.isConst = isConst;
|
| @@ -864,14 +925,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 +943,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 +956,9 @@ class Procedure extends Member {
|
| bool isExternal: false,
|
| bool isConst: false,
|
| int transformerFlags: 0,
|
| - this.fileUri})
|
| - : super(name) {
|
| - _reference = new _MemberAccessor(this);
|
| + this.fileUri,
|
| + Reference reference})
|
| + : super(name, reference) {
|
| function?.parent = this;
|
| this.isAbstract = isAbstract;
|
| this.isStatic = isStatic;
|
| @@ -979,9 +1031,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 +1076,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;
|
| + Reference fieldReference;
|
| Expression value;
|
|
|
| - FieldInitializer(this.field, this.value) {
|
| + FieldInitializer(Field field, Expression value)
|
| + : this.byReference(field?.reference, value);
|
| +
|
| + FieldInitializer.byReference(this.fieldReference, this.value) {
|
| value?.parent = this;
|
| }
|
|
|
| + Field get field => fieldReference?.node;
|
| +
|
| + void set field(Field field) {
|
| + fieldReference = field?.reference;
|
| + }
|
| +
|
| accept(InitializerVisitor v) => v.visitFieldInitializer(this);
|
|
|
| visitChildren(Visitor v) {
|
| @@ -1060,13 +1118,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;
|
| + Reference targetReference;
|
| Arguments arguments;
|
|
|
| - SuperInitializer(this.target, this.arguments) {
|
| + SuperInitializer(Constructor target, Arguments arguments)
|
| + : this.byReference(getMemberReference(target), arguments);
|
| +
|
| + SuperInitializer.byReference(this.targetReference, this.arguments) {
|
| arguments?.parent = this;
|
| }
|
|
|
| + Constructor get target => targetReference?.asConstructor;
|
| +
|
| + void set target(Constructor target) {
|
| + targetReference = getMemberReference(target);
|
| + }
|
| +
|
| accept(InitializerVisitor v) => v.visitSuperInitializer(this);
|
|
|
| visitChildren(Visitor v) {
|
| @@ -1089,13 +1156,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;
|
| + Reference targetReference;
|
| Arguments arguments;
|
|
|
| - RedirectingInitializer(this.target, this.arguments) {
|
| + RedirectingInitializer(Constructor target, Arguments arguments)
|
| + : this.byReference(getMemberReference(target), arguments);
|
| +
|
| + RedirectingInitializer.byReference(this.targetReference, this.arguments) {
|
| arguments?.parent = this;
|
| }
|
|
|
| + Constructor get target => targetReference?.asConstructor;
|
| +
|
| + void set target(Constructor target) {
|
| + targetReference = getMemberReference(target);
|
| + }
|
| +
|
| accept(InitializerVisitor v) => v.visitRedirectingInitializer(this);
|
|
|
| visitChildren(Visitor v) {
|
| @@ -1388,17 +1464,20 @@ class PropertyGet extends Expression {
|
| Expression receiver;
|
| Name name;
|
|
|
| - _MemberAccessor _interfaceTargetReference;
|
| + Reference interfaceTargetReference;
|
| +
|
| + PropertyGet(Expression receiver, Name name, [Member interfaceTarget])
|
| + : this.byReference(receiver, name, getMemberReference(interfaceTarget));
|
|
|
| - PropertyGet(this.receiver, this.name, [Member interfaceTarget]) {
|
| + PropertyGet.byReference(
|
| + this.receiver, this.name, this.interfaceTargetReference) {
|
| receiver?.parent = this;
|
| - this.interfaceTarget = interfaceTarget;
|
| }
|
|
|
| - Member get interfaceTarget => _interfaceTargetReference?.target;
|
| + Member get interfaceTarget => interfaceTargetReference?.asMember;
|
|
|
| - void set interfaceTarget(Member newTarget) {
|
| - _interfaceTargetReference = newTarget?._getterInterface;
|
| + void set interfaceTarget(Member member) {
|
| + interfaceTargetReference = getMemberReference(member);
|
| }
|
|
|
| DartType getStaticType(TypeEnvironment types) {
|
| @@ -1445,18 +1524,23 @@ class PropertySet extends Expression {
|
| Name name;
|
| Expression value;
|
|
|
| - _MemberAccessor _interfaceTargetReference;
|
| + Reference interfaceTargetReference;
|
|
|
| - PropertySet(this.receiver, this.name, this.value, [Member interfaceTarget]) {
|
| + PropertySet(Expression receiver, Name name, Expression value,
|
| + [Member interfaceTarget])
|
| + : this.byReference(
|
| + receiver, name, value, getMemberReference(interfaceTarget));
|
| +
|
| + PropertySet.byReference(
|
| + this.receiver, this.name, this.value, this.interfaceTargetReference) {
|
| receiver?.parent = this;
|
| value?.parent = this;
|
| - this.interfaceTarget = interfaceTarget;
|
| }
|
|
|
| - Member get interfaceTarget => _interfaceTargetReference?.target;
|
| + Member get interfaceTarget => interfaceTargetReference?.asMember;
|
|
|
| - void set interfaceTarget(Member newTarget) {
|
| - _interfaceTargetReference = newTarget?._setterInterface;
|
| + void set interfaceTarget(Member member) {
|
| + interfaceTargetReference = getMemberReference(member);
|
| }
|
|
|
| DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
|
| @@ -1484,12 +1568,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;
|
| + Reference targetReference;
|
| +
|
| + DirectPropertyGet(Expression receiver, Member target)
|
| + : this.byReference(receiver, getMemberReference(target));
|
|
|
| - DirectPropertyGet(this.receiver, this.target) {
|
| + DirectPropertyGet.byReference(this.receiver, this.targetReference) {
|
| receiver?.parent = this;
|
| }
|
|
|
| + Member get target => targetReference?.asMember;
|
| +
|
| + void set target(Member target) {
|
| + targetReference = getMemberReference(target);
|
| + }
|
| +
|
| visitChildren(Visitor v) {
|
| receiver?.accept(v);
|
| target?.acceptReference(v);
|
| @@ -1518,14 +1611,24 @@ class DirectPropertyGet extends Expression {
|
| /// Evaluates to the value of [value].
|
| class DirectPropertySet extends Expression {
|
| Expression receiver;
|
| - Member target;
|
| + Reference targetReference;
|
| Expression value;
|
|
|
| - DirectPropertySet(this.receiver, this.target, this.value) {
|
| + DirectPropertySet(Expression receiver, Member target, Expression value)
|
| + : this.byReference(receiver, getMemberReference(target), value);
|
| +
|
| + DirectPropertySet.byReference(
|
| + this.receiver, this.targetReference, this.value) {
|
| receiver?.parent = this;
|
| value?.parent = this;
|
| }
|
|
|
| + Member get target => targetReference?.asMember;
|
| +
|
| + void set target(Member target) {
|
| + targetReference = getMemberReference(target);
|
| + }
|
| +
|
| visitChildren(Visitor v) {
|
| receiver?.accept(v);
|
| target?.acceptReference(v);
|
| @@ -1551,14 +1654,25 @@ class DirectPropertySet extends Expression {
|
| /// Directly call an instance method, bypassing ordinary dispatch.
|
| class DirectMethodInvocation extends InvocationExpression {
|
| Expression receiver;
|
| - Procedure target;
|
| + Reference targetReference;
|
| Arguments arguments;
|
|
|
| - DirectMethodInvocation(this.receiver, this.target, this.arguments) {
|
| + DirectMethodInvocation(
|
| + Expression receiver, Procedure target, Arguments arguments)
|
| + : this.byReference(receiver, getMemberReference(target), arguments);
|
| +
|
| + DirectMethodInvocation.byReference(
|
| + this.receiver, this.targetReference, this.arguments) {
|
| receiver?.parent = this;
|
| arguments?.parent = this;
|
| }
|
|
|
| + Procedure get target => targetReference?.asProcedure;
|
| +
|
| + void set target(Procedure target) {
|
| + targetReference = getMemberReference(target);
|
| + }
|
| +
|
| Name get name => target?.name;
|
|
|
| visitChildren(Visitor v) {
|
| @@ -1601,16 +1715,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;
|
| + Reference interfaceTargetReference;
|
|
|
| - SuperPropertyGet(this.name, [Member interfaceTarget]) {
|
| - _interfaceTargetReference = interfaceTarget?._getterInterface;
|
| - }
|
| + SuperPropertyGet(Name name, [Member interfaceTarget])
|
| + : this.byReference(name, getMemberReference(interfaceTarget));
|
|
|
| - Member get interfaceTarget => _interfaceTargetReference?.target;
|
| + SuperPropertyGet.byReference(this.name, this.interfaceTargetReference);
|
|
|
| - void set interfaceTarget(Member newTarget) {
|
| - _interfaceTargetReference = newTarget?._getterInterface;
|
| + Member get interfaceTarget => interfaceTargetReference?.asMember;
|
| +
|
| + void set interfaceTarget(Member member) {
|
| + interfaceTargetReference = getMemberReference(member);
|
| }
|
|
|
| DartType getStaticType(TypeEnvironment types) {
|
| @@ -1642,17 +1757,20 @@ class SuperPropertyGet extends Expression {
|
| class SuperPropertySet extends Expression {
|
| Name name;
|
| Expression value;
|
| - _MemberAccessor _interfaceTargetReference;
|
| + Reference interfaceTargetReference;
|
| +
|
| + SuperPropertySet(Name name, Expression value, Member interfaceTarget)
|
| + : this.byReference(name, value, getMemberReference(interfaceTarget));
|
|
|
| - SuperPropertySet(this.name, this.value, [Member interfaceTarget]) {
|
| + SuperPropertySet.byReference(
|
| + this.name, this.value, this.interfaceTargetReference) {
|
| value?.parent = this;
|
| - _interfaceTargetReference = interfaceTarget?._setterInterface;
|
| }
|
|
|
| - Member get interfaceTarget => _interfaceTargetReference?.target;
|
| + Member get interfaceTarget => interfaceTargetReference?.asMember;
|
|
|
| - void set interfaceTarget(Member newTarget) {
|
| - _interfaceTargetReference = newTarget?._setterInterface;
|
| + void set interfaceTarget(Member member) {
|
| + interfaceTargetReference = getMemberReference(member);
|
| }
|
|
|
| DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
|
| @@ -1675,9 +1793,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;
|
| + Reference targetReference;
|
|
|
| - StaticGet(this.target);
|
| + StaticGet(Member target) : this.byReference(getMemberReference(target));
|
| +
|
| + StaticGet.byReference(this.targetReference);
|
| +
|
| + Member get target => targetReference?.asMember;
|
| +
|
| + void set target(Member target) {
|
| + targetReference = getMemberReference(target);
|
| + }
|
|
|
| DartType getStaticType(TypeEnvironment types) => target.getterType;
|
|
|
| @@ -1695,13 +1821,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;
|
| + Reference targetReference;
|
| Expression value;
|
|
|
| - StaticSet(this.target, this.value) {
|
| + StaticSet(Member target, Expression value)
|
| + : this.byReference(getMemberReference(target), value);
|
| +
|
| + StaticSet.byReference(this.targetReference, this.value) {
|
| value?.parent = this;
|
| }
|
|
|
| + Member get target => targetReference?.asMember;
|
| +
|
| + void set target(Member target) {
|
| + targetReference = getMemberReference(target);
|
| + }
|
| +
|
| DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
|
|
|
| accept(ExpressionVisitor v) => v.visitStaticSet(this);
|
| @@ -1795,14 +1930,25 @@ class MethodInvocation extends InvocationExpression {
|
| Name name;
|
| Arguments arguments;
|
|
|
| - Procedure interfaceTarget;
|
| + Reference interfaceTargetReference;
|
|
|
| - MethodInvocation(this.receiver, this.name, this.arguments,
|
| - [this.interfaceTarget]) {
|
| + MethodInvocation(Expression receiver, Name name, Arguments arguments,
|
| + [Procedure interfaceTarget])
|
| + : this.byReference(
|
| + receiver, name, arguments, getMemberReference(interfaceTarget));
|
| +
|
| + MethodInvocation.byReference(
|
| + this.receiver, this.name, this.arguments, this.interfaceTargetReference) {
|
| receiver?.parent = this;
|
| arguments?.parent = this;
|
| }
|
|
|
| + Procedure get interfaceTarget => interfaceTargetReference?.asProcedure;
|
| +
|
| + void set interfaceTarget(Member target) {
|
| + interfaceTargetReference = getMemberReference(target);
|
| + }
|
| +
|
| DartType getStaticType(TypeEnvironment types) {
|
| if (interfaceTarget != null) {
|
| if (types.isOverloadedArithmeticOperator(interfaceTarget)) {
|
| @@ -1864,12 +2010,23 @@ class SuperMethodInvocation extends InvocationExpression {
|
| Name name;
|
| Arguments arguments;
|
|
|
| - Procedure interfaceTarget;
|
| + Reference interfaceTargetReference;
|
| +
|
| + SuperMethodInvocation(Name name, Arguments arguments,
|
| + [Procedure interfaceTarget])
|
| + : this.byReference(name, arguments, getMemberReference(interfaceTarget));
|
|
|
| - SuperMethodInvocation(this.name, this.arguments, this.interfaceTarget) {
|
| + SuperMethodInvocation.byReference(
|
| + this.name, this.arguments, this.interfaceTargetReference) {
|
| arguments?.parent = this;
|
| }
|
|
|
| + Procedure get interfaceTarget => interfaceTargetReference?.asProcedure;
|
| +
|
| + void set interfaceTarget(Procedure target) {
|
| + interfaceTargetReference = getMemberReference(target);
|
| + }
|
| +
|
| DartType getStaticType(TypeEnvironment types) {
|
| if (interfaceTarget == null) return const DynamicType();
|
| Class superclass = interfaceTarget.enclosingClass;
|
| @@ -1903,7 +2060,7 @@ class SuperMethodInvocation extends InvocationExpression {
|
| ///
|
| /// The provided arguments might not match the parameters of the target.
|
| class StaticInvocation extends InvocationExpression {
|
| - Procedure target;
|
| + Reference targetReference;
|
| Arguments arguments;
|
|
|
| /// True if this is a constant call to an external constant factory.
|
| @@ -1911,10 +2068,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.byReference(getMemberReference(target), arguments,
|
| + isConst: isConst);
|
| +
|
| + StaticInvocation.byReference(this.targetReference, this.arguments,
|
| + {this.isConst: false}) {
|
| arguments?.parent = this;
|
| }
|
|
|
| + Procedure get target => targetReference?.asProcedure;
|
| +
|
| + void set target(Procedure target) {
|
| + targetReference = getMemberReference(target);
|
| + }
|
| +
|
| DartType getStaticType(TypeEnvironment types) {
|
| return Substitution
|
| .fromPairs(target.function.typeParameters, arguments.types)
|
| @@ -1944,16 +2112,28 @@ class StaticInvocation extends InvocationExpression {
|
| // `classTypeArguments`? They are quite different from type arguments to
|
| // generic functions.
|
| class ConstructorInvocation extends InvocationExpression {
|
| - Constructor target;
|
| + Reference targetReference;
|
| 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.byReference(getMemberReference(target), arguments,
|
| + isConst: isConst);
|
| +
|
| + ConstructorInvocation.byReference(this.targetReference, this.arguments,
|
| + {this.isConst: false}) {
|
| arguments?.parent = this;
|
| }
|
|
|
| + Constructor get target => targetReference?.asConstructor;
|
| +
|
| + void set target(Constructor target) {
|
| + targetReference = getMemberReference(target);
|
| + }
|
| +
|
| DartType getStaticType(TypeEnvironment types) {
|
| return arguments.types.isEmpty
|
| ? target.enclosingClass.rawType
|
| @@ -3200,17 +3380,21 @@ class FunctionDeclaration extends Statement {
|
| abstract class Name implements Node {
|
| final int hashCode;
|
| final String name;
|
| + Reference 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?.reference);
|
| +
|
| + factory Name.byReference(String name, Reference 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 +3412,24 @@ abstract class Name implements Node {
|
| }
|
|
|
| class _PrivateName extends Name {
|
| - final Library library;
|
| + final Reference libraryName;
|
| bool get isPrivate => true;
|
|
|
| - _PrivateName(String name, Library library)
|
| - : this.library = library,
|
| - super._internal(_computeHashCode(name, library), name);
|
| + _PrivateName(String name, Reference 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, Reference libraryName) {
|
| + return 131 * name.hashCode + 17 * libraryName.hashCode;
|
| }
|
| }
|
|
|
| class _PublicName extends Name {
|
| + Reference get libraryName => null;
|
| Library get library => null;
|
| bool get isPrivate => false;
|
|
|
| @@ -3322,14 +3509,18 @@ class BottomType extends DartType {
|
| }
|
|
|
| class InterfaceType extends DartType {
|
| - final Class classNode;
|
| + final Reference 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.byReference(getClassReference(classNode),
|
| + typeArguments ?? _defaultTypeArguments(classNode));
|
| +
|
| + InterfaceType.byReference(this.className, this.typeArguments);
|
| +
|
| + Class get classNode => className.asClass;
|
|
|
| static List<DartType> _defaultTypeArguments(Class classNode) {
|
| if (classNode.typeParameters.length == 0) {
|
| @@ -3351,7 +3542,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 +3554,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 +3742,15 @@ class TypeParameter extends TreeNode {
|
| }
|
|
|
| class Supertype extends Node {
|
| - final Class classNode;
|
| + final Reference className;
|
| final List<DartType> typeArguments;
|
|
|
| - Supertype(this.classNode, this.typeArguments);
|
| + Supertype(Class classNode, List<DartType> typeArguments)
|
| + : this.byReference(getClassReference(classNode), typeArguments);
|
| +
|
| + Supertype.byReference(this.className, this.typeArguments);
|
| +
|
| + Class get classNode => className.asClass;
|
|
|
| accept(Visitor v) => v.visitSupertype(this);
|
|
|
| @@ -3570,7 +3766,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 +3778,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 +3792,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 +3802,29 @@ class Program extends TreeNode {
|
| final Map<String, Source> uriToSource;
|
|
|
| /// Reference to the main method in one of the libraries.
|
| - Procedure mainMethod;
|
| + Reference 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.reference);
|
| + library.computeCanonicalNames();
|
| + }
|
| + }
|
| +
|
| + void unbindCanonicalNames() {
|
| + root.unbindAll();
|
| + }
|
| +
|
| + Procedure get mainMethod => mainMethodName?.asProcedure;
|
| +
|
| + void set mainMethod(Procedure main) {
|
| + mainMethodName = getMemberReference(main);
|
| }
|
|
|
| accept(TreeVisitor v) => v.visitProgram(this);
|
| @@ -3752,3 +3967,53 @@ class Source {
|
|
|
| Source(this.lineStarts, this.source);
|
| }
|
| +
|
| +/// Returns the [Reference] object for the given member.
|
| +///
|
| +/// Returns `null` if the member is `null`.
|
| +Reference getMemberReference(Member member) {
|
| + return member?.reference;
|
| +}
|
| +
|
| +/// Returns the [Reference] object for the given class.
|
| +///
|
| +/// Returns `null` if the class is `null`.
|
| +Reference getClassReference(Class class_) {
|
| + return class_?.reference;
|
| +}
|
| +
|
| +/// 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;
|
| +}
|
|
|