Chromium Code Reviews| Index: lib/compiler/implementation/universe.dart |
| =================================================================== |
| --- lib/compiler/implementation/universe.dart (revision 6933) |
| +++ lib/compiler/implementation/universe.dart (working copy) |
| @@ -9,8 +9,8 @@ |
| final Set<SourceString> instantiatedClassInstanceFields; |
| final Set<FunctionElement> staticFunctionsNeedingGetter; |
| final Map<SourceString, Set<Selector>> invokedNames; |
| - final Set<SourceString> invokedGetters; |
| - final Set<SourceString> invokedSetters; |
| + final Map<SourceString, Set<Selector>> invokedGetters; |
| + final Map<SourceString, Set<Selector>> invokedSetters; |
| final Map<String, LibraryElement> libraries; |
| // TODO(ngeoffray): This should be a Set<Type>. |
| final Set<Element> isChecks; |
| @@ -22,8 +22,8 @@ |
| instantiatedClassInstanceFields = new Set<SourceString>(), |
| staticFunctionsNeedingGetter = new Set<FunctionElement>(), |
| invokedNames = new Map<SourceString, Set<Selector>>(), |
| - invokedGetters = new Set<SourceString>(), |
| - invokedSetters = new Set<SourceString>(), |
| + invokedGetters = new Map<SourceString, Set<Selector>>(), |
| + invokedSetters = new Map<SourceString, Set<Selector>>(), |
| isChecks = new Set<Element>(); |
| void addGeneratedCode(WorkItem work, String code) { |
| @@ -33,6 +33,30 @@ |
| void addBailoutCode(WorkItem work, String code) { |
| generatedBailoutCode[work.element] = code; |
| } |
| + |
| + bool hasMatchingSelector( |
| + Set<Selector> selectors, Element member, Compiler compiler) { |
|
kasperl
2012/04/25 14:14:54
Move first argument to previous line and split aft
ngeoffray
2012/04/26 09:31:51
Done.
|
| + if (selectors === null) return false; |
| + for (Selector selector in selectors) { |
| + if (selector.applies(member, compiler)) return true; |
| + } |
| + return false; |
| + } |
| + |
| + bool hasInvocation(Element member, Compiler compiler) { |
| + return hasMatchingSelector( |
| + compiler.universe.invokedNames[member.name], member, compiler); |
| + } |
| + |
| + bool hasGetter(Element member, Compiler compiler) { |
| + return hasMatchingSelector( |
| + compiler.universe.invokedGetters[member.name], member, compiler); |
| + } |
| + |
| + bool hasSetter(Element member, Compiler compiler) { |
| + return hasMatchingSelector( |
| + compiler.universe.invokedSetters[member.name], member, compiler); |
| + } |
| } |
| class SelectorKind { |
| @@ -52,34 +76,67 @@ |
| // The numbers of arguments of the selector. Includes named arguments. |
| final int argumentCount; |
| final SelectorKind kind; |
| - const Selector(this.kind, this.argumentCount); |
| + final List<SourceString> namedArguments = const <SourceString>[]; |
| + final List<SourceString> orderedNamedArguments = const <SourceString>[]; |
| + // The const constructor. |
| + const Selector.constant(this.kind, this.argumentCount); |
| + |
| + Selector( |
| + this.kind, |
| + this.argumentCount, |
| + [List<SourceString> namedArguments = const <SourceString>[]]) |
| + : this.namedArguments = namedArguments, |
| + this.orderedNamedArguments = namedArguments.isEmpty() |
| + ? namedArguments |
| + : <SourceString>[]; |
| + |
| + Selector.invocation( |
| + int argumentCount, |
| + [List<SourceString> namedArguments = const <SourceString>[]]) |
| + : this(SelectorKind.INVOCATION, argumentCount, namedArguments); |
| + |
| int hashCode() => argumentCount + 1000 * namedArguments.length; |
| - List<SourceString> get namedArguments() => const <SourceString>[]; |
| - int get namedArgumentCount() => 0; |
| - int get positionalArgumentCount() => argumentCount; |
| + int get namedArgumentCount() => namedArguments.length; |
| + int get positionalArgumentCount() => argumentCount - namedArgumentCount; |
| - static final Selector GETTER = const Selector(SelectorKind.GETTER, 0); |
| - static final Selector SETTER = const Selector(SelectorKind.SETTER, 1); |
| + static final Selector GETTER = |
| + const Selector.constant(SelectorKind.GETTER, 0); |
| + static final Selector SETTER = |
| + const Selector.constant(SelectorKind.SETTER, 1); |
| static final Selector UNARY_OPERATOR = |
| - const Selector(SelectorKind.OPERATOR, 0); |
| + const Selector.constant(SelectorKind.OPERATOR, 0); |
| static final Selector BINARY_OPERATOR = |
| - const Selector(SelectorKind.OPERATOR, 1); |
| - static final Selector INDEX = const Selector(SelectorKind.INDEX, 1); |
| - static final Selector INDEX_SET = const Selector(SelectorKind.INDEX, 2); |
| + const Selector.constant(SelectorKind.OPERATOR, 1); |
| + static final Selector INDEX = |
| + const Selector.constant(SelectorKind.INDEX, 1); |
| + static final Selector INDEX_SET = |
| + const Selector.constant(SelectorKind.INDEX, 2); |
| static final Selector INDEX_AND_INDEX_SET = |
| - const Selector(SelectorKind.INDEX, 2); |
| + const Selector.constant(SelectorKind.INDEX, 2); |
| static final Selector GETTER_AND_SETTER = |
| - const Selector(SelectorKind.SETTER, 1); |
| + const Selector.constant(SelectorKind.SETTER, 1); |
| static final Selector INVOCATION_0 = |
| - const Selector(SelectorKind.INVOCATION, 0); |
| + const Selector.constant(SelectorKind.INVOCATION, 0); |
| static final Selector INVOCATION_1 = |
| - const Selector(SelectorKind.INVOCATION, 1); |
| + const Selector.constant(SelectorKind.INVOCATION, 1); |
| static final Selector INVOCATION_2 = |
| - const Selector(SelectorKind.INVOCATION, 2); |
| + const Selector.constant(SelectorKind.INVOCATION, 2); |
| - bool applies(FunctionElement element, Compiler compiler) { |
| - FunctionParameters parameters = element.computeParameters(compiler); |
| + bool applies(Element element, Compiler compiler) { |
| + if (element.isSetter()) return kind === SelectorKind.SETTER; |
| + if (element.isGetter()) { |
| + return kind === SelectorKind.GETTER || kind === SelectorKind.INVOCATION; |
| + } |
| + if (element.isField()) { |
| + return kind === SelectorKind.GETTER |
| + || kind === SelectorKind.INVOCATION |
| + || kind === SelectorKind.SETTER; |
| + } |
| + if (kind === SelectorKind.GETTER) return true; |
| + |
| + FunctionElement function = element; |
| + FunctionParameters parameters = function.computeParameters(compiler); |
| if (argumentCount > parameters.parameterCount) return false; |
| int requiredParameterCount = parameters.requiredParameterCount; |
| int optionalParameterCount = parameters.optionalParameterCount; |
| @@ -203,63 +260,76 @@ |
| && sameNames(namedArguments, other.namedArguments); |
| } |
| - List<SourceString> getOrderedNamedArguments() => namedArguments; |
| - |
| - toString() => '$kind $argumentCount'; |
| -} |
| - |
| -class Invocation extends Selector { |
| - final List<SourceString> namedArguments; |
| - List<SourceString> orderedNamedArguments; |
| - int get namedArgumentCount() => namedArguments.length; |
| - int get positionalArgumentCount() => argumentCount - namedArgumentCount; |
| - |
| - Invocation(int argumentCount, |
| - [List<SourceString> names = const <SourceString>[]]) |
| - : super(SelectorKind.INVOCATION, argumentCount), |
| - namedArguments = names, |
| - orderedNamedArguments = const <SourceString>[]; |
| - |
| List<SourceString> getOrderedNamedArguments() { |
| if (namedArguments.isEmpty()) return namedArguments; |
| - // We use the empty const List as a sentinel. |
| if (!orderedNamedArguments.isEmpty()) return orderedNamedArguments; |
| - List<SourceString> list = new List<SourceString>.from(namedArguments); |
| - list.sort((SourceString first, SourceString second) { |
| + orderedNamedArguments.addAll(namedArguments); |
| + orderedNamedArguments.sort((SourceString first, SourceString second) { |
| return first.slowToString().compareTo(second.slowToString()); |
| }); |
| - orderedNamedArguments = list; |
| return orderedNamedArguments; |
| } |
| + |
| + toString() => '$kind $argumentCount'; |
| } |
| -/** |
| - * A [TypedInvocation] is an invocation where we have information on |
| - * the type of the receiver. |
| - */ |
| -class TypedInvocation extends Invocation { |
| +class TypedSelector extends Selector { |
| /** |
| * The type of the receiver. Any subtype of that type can be the |
| * target of the invocation. |
| */ |
| final Type receiverType; |
| - TypedInvocation(this.receiverType, Selector selector) |
| - : super(selector.argumentCount, selector.namedArguments); |
| + TypedSelector(this.receiverType, Selector selector) |
| + : super(selector.kind, |
| + selector.argumentCount, |
| + selector.namedArguments); |
| - bool applies(FunctionElement element, Compiler compiler) { |
| + bool applies(Element element, Compiler compiler) { |
| if (!element.enclosingElement.isClass()) return false; |
| + // A closure can be called through any typed selector: |
| + // class A { |
| + // get foo() => () => 42; |
| + // bar() => foo(); // The call to 'foo' is a typed selector. |
| + // } |
| + if (element.enclosingElement.superclass === compiler.closureClass) { |
| + return super.applies(element, compiler); |
| + } |
| + |
| ClassElement other = element.enclosingElement; |
| ClassElement self = receiverType.element; |
| - if (!other.isSubclassOf(self)) return false; |
| - return super.applies(element, compiler); |
| + |
| + // If the class of the element is a subclass of this selector's |
| + // class, it is a candidate. |
| + if (other.isSubclassOf(self)) { |
| + return super.applies(element, compiler); |
| + } |
| + |
| + if (self.isSubclassOf(other)) { |
| + // Resolve an invocation of [element.name] on [self]. If the |
| + // found element is [element], or is an abstract field whose |
| + // getter or setter is [element], this selector is a candidate. |
| + |
|
kasperl
2012/04/25 14:14:54
I'd remove this newline.
ngeoffray
2012/04/26 09:31:51
Done.
|
| + Element resolved = self.lookupMember(element.name); |
| + if (resolved === element) { |
| + return super.applies(element, compiler); |
| + } |
| + |
| + if (resolved !== null && resolved.kind === ElementKind.ABSTRACT_FIELD) { |
| + AbstractFieldElement field = resolved; |
| + if (element === field.getter || element === field.setter) { |
| + return super.applies(element, compiler); |
| + } |
| + } |
| + } |
| + |
| return false; |
| } |
| bool operator ==(other) { |
| - if (other is !TypedInvocation) return false; |
| + if (other is !TypedSelector) return false; |
| if (other.receiverType !== receiverType) return false; |
| return super == other; |
| } |