Index: pkg/compiler/lib/src/universe/universe.dart |
diff --git a/pkg/compiler/lib/src/universe/universe.dart b/pkg/compiler/lib/src/universe/universe.dart |
index 3deffcba75cd27966bafcbcc8b0126afc809a713..590bb543a0a1ac000c3c177768eaf2fd8113b257 100644 |
--- a/pkg/compiler/lib/src/universe/universe.dart |
+++ b/pkg/compiler/lib/src/universe/universe.dart |
@@ -228,230 +228,78 @@ class SelectorKind { |
String toString() => name; |
} |
-class Selector { |
- final SelectorKind kind; |
- final String name; |
- final LibraryElement library; // Library is null for non-private selectors. |
- |
- // The numbers of arguments of the selector. Includes named arguments. |
+/// The structure of the arguments at a call-site. |
+// TODO(johnniwinther): Should these be cached? |
+// TODO(johnniwinther): Should isGetter/isSetter be part of the call structure |
+// instead of the selector? |
+class CallStructure { |
+ static const CallStructure NO_ARGS = const CallStructure.unnamed(0); |
+ static const CallStructure ONE_ARG = const CallStructure.unnamed(1); |
+ static const CallStructure TWO_ARGS = const CallStructure.unnamed(2); |
+ |
+ /// The numbers of arguments of the call. Includes named arguments. |
final int argumentCount; |
- final List<String> namedArguments; |
- final List<String> _orderedNamedArguments; |
- final int hashCode; |
- static const String INDEX_NAME ="[]"; |
- static const String INDEX_SET_NAME = "[]="; |
- static const String CALL_NAME = Compiler.CALL_OPERATOR_NAME; |
+ /// The number of named arguments of the call. |
+ int get namedArgumentCount => 0; |
- Selector.internal(this.kind, |
- this.name, |
- this.library, |
- this.argumentCount, |
- this.namedArguments, |
- this._orderedNamedArguments, |
- this.hashCode) { |
- assert(kind == SelectorKind.INDEX |
- || (name != INDEX_NAME && name != INDEX_SET_NAME)); |
- assert(kind == SelectorKind.OPERATOR |
- || kind == SelectorKind.INDEX |
- || !Elements.isOperatorName(name)); |
- assert(kind == SelectorKind.CALL |
- || kind == SelectorKind.GETTER |
- || kind == SelectorKind.SETTER |
- || Elements.isOperatorName(name)); |
- assert(!isPrivateName(name) || library != null); |
- } |
+ /// The number of positional argument of the call. |
+ int get positionalArgumentCount => argumentCount; |
- static Map<int, List<Selector>> canonicalizedValues = |
- new Map<int, List<Selector>>(); |
- |
- factory Selector(SelectorKind kind, |
- String name, |
- LibraryElement library, |
- int argumentCount, |
- [List<String> namedArguments]) { |
- if (!isPrivateName(name)) library = null; |
- if (namedArguments == null) namedArguments = const <String>[]; |
- int hashCode = computeHashCode( |
- kind, name, library, argumentCount, namedArguments); |
- List<Selector> list = canonicalizedValues.putIfAbsent(hashCode, |
- () => <Selector>[]); |
- for (int i = 0; i < list.length; i++) { |
- Selector existing = list[i]; |
- if (existing.match(kind, name, library, argumentCount, namedArguments)) { |
- assert(existing.hashCode == hashCode); |
- assert(existing.mask == null); |
- return existing; |
- } |
- } |
- List<String> orderedNamedArguments = namedArguments.isEmpty |
- ? const <String>[] |
- : <String>[]; |
- Selector result = new Selector.internal( |
- kind, name, library, argumentCount, |
- namedArguments, orderedNamedArguments, |
- hashCode); |
- list.add(result); |
- return result; |
- } |
+ const CallStructure.unnamed(this.argumentCount); |
- factory Selector.fromElement(Element element) { |
- String name = element.name; |
- if (element.isFunction) { |
- if (name == '[]') { |
- return new Selector.index(); |
- } else if (name == '[]=') { |
- return new Selector.indexSet(); |
- } |
- FunctionSignature signature = |
- element.asFunctionElement().functionSignature; |
- int arity = signature.parameterCount; |
- List<String> namedArguments = null; |
- if (signature.optionalParametersAreNamed) { |
- namedArguments = |
- signature.orderedOptionalParameters.map((e) => e.name).toList(); |
- } |
- if (element.isOperator) { |
- // Operators cannot have named arguments, however, that doesn't prevent |
- // a user from declaring such an operator. |
- return new Selector( |
- SelectorKind.OPERATOR, name, null, arity, namedArguments); |
- } else { |
- return new Selector.call( |
- name, element.library, arity, namedArguments); |
- } |
- } else if (element.isSetter) { |
- return new Selector.setter(name, element.library); |
- } else if (element.isGetter) { |
- return new Selector.getter(name, element.library); |
- } else if (element.isField) { |
- return new Selector.getter(name, element.library); |
- } else if (element.isConstructor) { |
- return new Selector.callConstructor(name, element.library); |
- } else { |
- throw new SpannableAssertionFailure( |
- element, "Can't get selector from $element"); |
+ factory CallStructure(int argumentCount, [List<String> namedArguments]) { |
+ if (namedArguments == null || namedArguments.isEmpty) { |
+ return new CallStructure.unnamed(argumentCount); |
} |
+ return new NamedCallStructure(argumentCount, namedArguments); |
} |
- factory Selector.getter(String name, LibraryElement library) |
- => new Selector(SelectorKind.GETTER, name, library, 0); |
- |
- factory Selector.getterFrom(Selector selector) |
- => new Selector(SelectorKind.GETTER, selector.name, selector.library, 0); |
- |
- factory Selector.setter(String name, LibraryElement library) |
- => new Selector(SelectorKind.SETTER, name, library, 1); |
+ /// `true` if this call has named arguments. |
+ bool get isNamed => false; |
- factory Selector.unaryOperator(String name) |
- => new Selector(SelectorKind.OPERATOR, |
- Elements.constructOperatorName(name, true), |
- null, 0); |
+ /// `true` if this call has no named arguments. |
+ bool get isUnnamed => true; |
- factory Selector.binaryOperator(String name) |
- => new Selector(SelectorKind.OPERATOR, |
- Elements.constructOperatorName(name, false), |
- null, 1); |
+ /// The names of the named arguments in call-site order. |
+ List<String> get namedArguments => const <String>[]; |
- factory Selector.index() |
- => new Selector(SelectorKind.INDEX, |
- Elements.constructOperatorName(INDEX_NAME, false), |
- null, 1); |
+ /// The names of the named arguments in canonicalized order. |
+ List<String> getOrderedNamedArguments() => const <String>[]; |
- factory Selector.indexSet() |
- => new Selector(SelectorKind.INDEX, |
- Elements.constructOperatorName(INDEX_SET_NAME, false), |
- null, 2); |
+ /// A description of the argument structure. |
+ String structureToString() => 'arity=$argumentCount'; |
- factory Selector.call(String name, |
- LibraryElement library, |
- int arity, |
- [List<String> namedArguments]) |
- => new Selector(SelectorKind.CALL, name, library, arity, namedArguments); |
- |
- factory Selector.callClosure(int arity, [List<String> namedArguments]) |
- => new Selector(SelectorKind.CALL, CALL_NAME, null, |
- arity, namedArguments); |
+ String toString() => 'CallStructure(${structureToString()})'; |
- factory Selector.callClosureFrom(Selector selector) |
- => new Selector(SelectorKind.CALL, CALL_NAME, null, |
- selector.argumentCount, selector.namedArguments); |
- |
- factory Selector.callConstructor(String name, LibraryElement library, |
- [int arity = 0, |
- List<String> namedArguments]) |
- => new Selector(SelectorKind.CALL, name, library, |
- arity, namedArguments); |
- |
- factory Selector.callDefaultConstructor() |
- => new Selector(SelectorKind.CALL, "", null, 0); |
- |
- bool get isGetter => identical(kind, SelectorKind.GETTER); |
- bool get isSetter => identical(kind, SelectorKind.SETTER); |
- bool get isCall => identical(kind, SelectorKind.CALL); |
- bool get isClosureCall { |
- String callName = Compiler.CALL_OPERATOR_NAME; |
- return isCall && name == callName; |
+ Selector get callSelector { |
+ return new Selector(SelectorKind.CALL, Selector.CALL_NAME, this); |
} |
- bool get isIndex => identical(kind, SelectorKind.INDEX) && argumentCount == 1; |
- bool get isIndexSet => identical(kind, SelectorKind.INDEX) && argumentCount == 2; |
- |
- bool get isOperator => identical(kind, SelectorKind.OPERATOR); |
- bool get isUnaryOperator => isOperator && argumentCount == 0; |
- |
- /** Check whether this is a call to 'assert'. */ |
- bool get isAssert => isCall && identical(name, "assert"); |
- |
- int get namedArgumentCount => namedArguments.length; |
- int get positionalArgumentCount => argumentCount - namedArgumentCount; |
- |
- bool get hasExactMask => false; |
- TypeMask get mask => null; |
- Selector get asUntyped => this; |
- |
- /** |
- * The member name for invocation mirrors created from this selector. |
- */ |
- String get invocationMirrorMemberName => |
- isSetter ? '$name=' : name; |
- |
- int get invocationMirrorKind { |
- const int METHOD = 0; |
- const int GETTER = 1; |
- const int SETTER = 2; |
- int kind = METHOD; |
- if (isGetter) { |
- kind = GETTER; |
- } else if (isSetter) { |
- kind = SETTER; |
- } |
- return kind; |
+ bool match(CallStructure other) { |
+ if (identical(this, other)) return true; |
+ return this.argumentCount == other.argumentCount |
+ && this.namedArgumentCount == other.namedArgumentCount |
+ && sameNames(this.namedArguments, other.namedArguments); |
} |
- bool appliesUnnamed(Element element, World world) { |
- assert(sameNameHack(element, world)); |
- return appliesUntyped(element, world); |
+ // TODO(johnniwinther): Cache hash code? |
+ int get hashCode { |
+ int named = namedArguments.length; |
+ int hash = mixHashCodeBits(argumentCount, named); |
+ for (int i = 0; i < named; i++) { |
+ hash = mixHashCodeBits(hash, namedArguments[i].hashCode); |
+ } |
+ return hash; |
} |
- bool appliesUntyped(Element element, World world) { |
- assert(sameNameHack(element, world)); |
- if (Elements.isUnresolved(element)) return false; |
- if (isPrivateName(name) && library != element.library) return false; |
- if (world.isForeign(element)) return true; |
- if (element.isSetter) return isSetter; |
- if (element.isGetter) return isGetter || isCall; |
- if (element.isField) { |
- return isSetter |
- ? !element.isFinal && !element.isConst |
- : isGetter || isCall; |
- } |
- if (isGetter) return true; |
- if (isSetter) return false; |
- return signatureApplies(element); |
+ bool operator ==(other) { |
+ if (other is! CallStructure) return false; |
+ return match(other); |
} |
bool signatureApplies(FunctionElement function) { |
+ if (Elements.isUnresolved(function)) return false; |
FunctionSignature parameters = function.functionSignature; |
if (argumentCount > parameters.parameterCount) return false; |
int requiredParameterCount = parameters.requiredParameterCount; |
@@ -484,18 +332,6 @@ class Selector { |
} |
} |
- bool sameNameHack(Element element, World world) { |
- // TODO(ngeoffray): Remove workaround checks. |
- return element.isConstructor || |
- name == element.name || |
- name == 'assert' && world.isAssertMethod(element); |
- } |
- |
- bool applies(Element element, World world) { |
- if (!sameNameHack(element, world)) return false; |
- return appliesUnnamed(element, world); |
- } |
- |
/** |
* Returns a `List` with the evaluated arguments in the normalized order. |
* |
@@ -564,21 +400,20 @@ class Selector { |
* Returns [:true:] if the signature of the [caller] matches the |
* signature of the [callee], [:false:] otherwise. |
*/ |
- static bool addForwardingElementArgumentsToList( |
- FunctionElement caller, |
- List list, |
- FunctionElement callee, |
- compileArgument(Element element), |
- compileConstant(Element element), |
- World world) { |
+ static /*<T>*/ bool addForwardingElementArgumentsToList( |
+ ConstructorElement caller, |
+ List/*<T>*/ list, |
+ ConstructorElement callee, |
+ /*T*/ compileArgument(ParameterElement element), |
+ /*T*/ compileConstant(ParameterElement element)) { |
FunctionSignature signature = caller.functionSignature; |
- Map mapping = new Map(); |
+ Map<Node, ParameterElement> mapping = <Node, ParameterElement>{}; |
// TODO(ngeoffray): This is a hack that fakes up AST nodes, so |
// that we can call [addArgumentsToList]. |
- Link computeCallNodesFromParameters() { |
- LinkBuilder builder = new LinkBuilder(); |
+ Link<Node> computeCallNodesFromParameters() { |
+ LinkBuilder<Node> builder = new LinkBuilder<Node>(); |
signature.forEachRequiredParameter((ParameterElement element) { |
Node node = element.node; |
mapping[node] = element; |
@@ -599,29 +434,28 @@ class Selector { |
return builder.toLink(); |
} |
- internalCompileArgument(Node node) { |
+ /*T*/ internalCompileArgument(Node node) { |
return compileArgument(mapping[node]); |
} |
Link<Node> nodes = computeCallNodesFromParameters(); |
- // Synthesize a selector for the call. |
+ // Synthesize a structure for the call. |
// TODO(ngeoffray): Should the resolver do it instead? |
List<String> namedParameters; |
if (signature.optionalParametersAreNamed) { |
- namedParameters = |
- signature.optionalParameters.mapToList((e) => e.name); |
+ namedParameters = signature.optionalParameters.mapToList((e) => e.name); |
} |
- Selector selector = new Selector.call(callee.name, |
- caller.library, |
- signature.parameterCount, |
- namedParameters); |
- |
- if (!selector.applies(callee, world)) return false; |
- list.addAll(selector.makeArgumentsList(nodes, |
- callee, |
- internalCompileArgument, |
- compileConstant)); |
+ CallStructure callStructure = |
+ new CallStructure(signature.parameterCount, namedParameters); |
+ if (!callStructure.signatureApplies(callee)) { |
+ return false; |
+ } |
+ list.addAll(callStructure.makeArgumentsList( |
+ nodes, |
+ callee, |
+ internalCompileArgument, |
+ compileConstant)); |
return true; |
} |
@@ -632,59 +466,32 @@ class Selector { |
} |
return true; |
} |
+} |
- bool match(SelectorKind kind, |
- String name, |
- LibraryElement library, |
- int argumentCount, |
- List<String> namedArguments) { |
- return this.kind == kind |
- && this.name == name |
- && identical(this.library, library) |
- && this.argumentCount == argumentCount |
- && this.namedArguments.length == namedArguments.length |
- && sameNames(this.namedArguments, namedArguments); |
- } |
+/// |
+class NamedCallStructure extends CallStructure { |
+ final List<String> namedArguments; |
+ final List<String> _orderedNamedArguments = <String>[]; |
- static int computeHashCode(SelectorKind kind, |
- String name, |
- LibraryElement library, |
- int argumentCount, |
- List<String> namedArguments) { |
- // Add bits from name and kind. |
- int hash = mixHashCodeBits(name.hashCode, kind.hashCode); |
- // Add bits from the library. |
- if (library != null) hash = mixHashCodeBits(hash, library.hashCode); |
- // Add bits from the unnamed arguments. |
- hash = mixHashCodeBits(hash, argumentCount); |
- // Add bits from the named arguments. |
- int named = namedArguments.length; |
- hash = mixHashCodeBits(hash, named); |
- for (int i = 0; i < named; i++) { |
- hash = mixHashCodeBits(hash, namedArguments[i].hashCode); |
- } |
- return hash; |
+ NamedCallStructure(int argumentCount, this.namedArguments) |
+ : super.unnamed(argumentCount) { |
+ assert(namedArguments.isNotEmpty); |
} |
- // TODO(kasperl): Move this out so it becomes useful in other places too? |
- static int mixHashCodeBits(int existing, int value) { |
- // Spread the bits of value. Try to stay in the 30-bit range to |
- // avoid overflowing into a more expensive integer representation. |
- int h = value & 0x1fffffff; |
- h += ((h & 0x3fff) << 15) ^ 0x1fffcd7d; |
- h ^= (h >> 10); |
- h += ((h & 0x3ffffff) << 3); |
- h ^= (h >> 6); |
- h += ((h & 0x7ffffff) << 2) + ((h & 0x7fff) << 14); |
- h ^= (h >> 16); |
- // Combine the two hash values. |
- int high = existing >> 15; |
- int low = existing & 0x7fff; |
- return ((high * 13) ^ (low * 997) ^ h) & SMI_MASK; |
- } |
+ @override |
+ bool get isNamed => true; |
+ |
+ @override |
+ bool get isUnnamed => false; |
+ @override |
+ int get namedArgumentCount => namedArguments.length; |
+ |
+ @override |
+ int get positionalArgumentCount => argumentCount - namedArgumentCount; |
+ |
+ @override |
List<String> getOrderedNamedArguments() { |
- if (namedArguments.isEmpty) return namedArguments; |
if (!_orderedNamedArguments.isEmpty) return _orderedNamedArguments; |
_orderedNamedArguments.addAll(namedArguments); |
@@ -694,25 +501,273 @@ class Selector { |
return _orderedNamedArguments; |
} |
- String namedArgumentsToString() { |
- if (namedArgumentCount > 0) { |
- StringBuffer result = new StringBuffer(); |
- for (int i = 0; i < namedArgumentCount; i++) { |
- if (i != 0) result.write(', '); |
- result.write(namedArguments[i]); |
+ @override |
+ String structureToString() { |
+ return 'arity=$argumentCount, named=[${namedArguments.join(', ')}]'; |
+ } |
+} |
+ |
+class Selector { |
+ final SelectorKind kind; |
+ final Name memberName; |
+ final CallStructure callStructure; |
+ |
+ final int hashCode; |
+ |
+ int get argumentCount => callStructure.argumentCount; |
+ int get namedArgumentCount => callStructure.namedArgumentCount; |
+ int get positionalArgumentCount => callStructure.positionalArgumentCount; |
+ List<String> get namedArguments => callStructure.namedArguments; |
+ |
+ String get name => memberName.text; |
+ |
+ LibraryElement get library => memberName.library; |
+ |
+ static const Name INDEX_NAME = const PublicName("[]"); |
+ static const Name INDEX_SET_NAME = const PublicName("[]="); |
+ static const Name CALL_NAME = const PublicName(Compiler.CALL_OPERATOR_NAME); |
+ |
+ Selector.internal(this.kind, |
+ this.memberName, |
+ this.callStructure, |
+ this.hashCode) { |
+ assert(kind == SelectorKind.INDEX || |
+ (memberName != INDEX_NAME && memberName != INDEX_SET_NAME)); |
+ assert(kind == SelectorKind.OPERATOR || |
+ kind == SelectorKind.INDEX || |
+ !Elements.isOperatorName(memberName.text)); |
+ assert(kind == SelectorKind.CALL || |
+ kind == SelectorKind.GETTER || |
+ kind == SelectorKind.SETTER || |
+ Elements.isOperatorName(memberName.text)); |
+ } |
+ |
+ // TODO(johnniwinther): Extract caching. |
+ static Map<int, List<Selector>> canonicalizedValues = |
+ new Map<int, List<Selector>>(); |
+ |
+ factory Selector(SelectorKind kind, |
+ Name name, |
+ CallStructure callStructure) { |
+ // TODO(johnniwinther): Maybe use equality instead of implicit hashing. |
+ int hashCode = computeHashCode(kind, name, callStructure); |
+ List<Selector> list = canonicalizedValues.putIfAbsent(hashCode, |
+ () => <Selector>[]); |
+ for (int i = 0; i < list.length; i++) { |
+ Selector existing = list[i]; |
+ if (existing.match(kind, name, callStructure)) { |
+ assert(existing.hashCode == hashCode); |
+ assert(existing.mask == null); |
+ return existing; |
+ } |
+ } |
+ Selector result = new Selector.internal( |
+ kind, name, callStructure, hashCode); |
+ list.add(result); |
+ return result; |
+ } |
+ |
+ factory Selector.fromElement(Element element) { |
+ String name = element.name; |
+ if (element.isFunction) { |
+ if (name == '[]') { |
+ return new Selector.index(); |
+ } else if (name == '[]=') { |
+ return new Selector.indexSet(); |
+ } |
+ FunctionSignature signature = |
+ element.asFunctionElement().functionSignature; |
+ int arity = signature.parameterCount; |
+ List<String> namedArguments = null; |
+ if (signature.optionalParametersAreNamed) { |
+ namedArguments = |
+ signature.orderedOptionalParameters.map((e) => e.name).toList(); |
} |
- return "[$result]"; |
+ if (element.isOperator) { |
+ // Operators cannot have named arguments, however, that doesn't prevent |
+ // a user from declaring such an operator. |
+ return new Selector( |
+ SelectorKind.OPERATOR, |
+ new PublicName(name), |
+ new CallStructure(arity, namedArguments)); |
+ } else { |
+ return new Selector.call( |
+ name, element.library, arity, namedArguments); |
+ } |
+ } else if (element.isSetter) { |
+ return new Selector.setter(name, element.library); |
+ } else if (element.isGetter) { |
+ return new Selector.getter(name, element.library); |
+ } else if (element.isField) { |
+ return new Selector.getter(name, element.library); |
+ } else if (element.isConstructor) { |
+ return new Selector.callConstructor(name, element.library); |
+ } else { |
+ throw new SpannableAssertionFailure( |
+ element, "Can't get selector from $element"); |
+ } |
+ } |
+ |
+ factory Selector.getter(String name, LibraryElement library) |
+ => new Selector(SelectorKind.GETTER, |
+ new Name(name, library), |
+ CallStructure.NO_ARGS); |
+ |
+ factory Selector.getterFrom(Selector selector) |
+ => new Selector(SelectorKind.GETTER, |
+ selector.memberName, |
+ CallStructure.NO_ARGS); |
+ |
+ factory Selector.setter(String name, LibraryElement library) |
+ => new Selector(SelectorKind.SETTER, |
+ new Name(name, library, isSetter: true), |
+ CallStructure.ONE_ARG); |
+ |
+ factory Selector.unaryOperator(String name) => new Selector( |
+ SelectorKind.OPERATOR, |
+ new PublicName(Elements.constructOperatorName(name, true)), |
+ CallStructure.NO_ARGS); |
+ |
+ factory Selector.binaryOperator(String name) => new Selector( |
+ SelectorKind.OPERATOR, |
+ new PublicName(Elements.constructOperatorName(name, false)), |
+ CallStructure.ONE_ARG); |
+ |
+ factory Selector.index() |
+ => new Selector(SelectorKind.INDEX, INDEX_NAME, |
+ CallStructure.ONE_ARG); |
+ |
+ factory Selector.indexSet() |
+ => new Selector(SelectorKind.INDEX, INDEX_SET_NAME, |
+ CallStructure.TWO_ARGS); |
+ |
+ factory Selector.call(String name, |
+ LibraryElement library, |
+ int arity, |
+ [List<String> namedArguments]) |
+ => new Selector(SelectorKind.CALL, |
+ new Name(name, library), |
+ new CallStructure(arity, namedArguments)); |
+ |
+ factory Selector.callClosure(int arity, [List<String> namedArguments]) |
+ => new Selector(SelectorKind.CALL, CALL_NAME, |
+ new CallStructure(arity, namedArguments)); |
+ |
+ factory Selector.callClosureFrom(Selector selector) |
+ => new Selector(SelectorKind.CALL, CALL_NAME, selector.callStructure); |
+ |
+ factory Selector.callConstructor(String name, LibraryElement library, |
+ [int arity = 0, |
+ List<String> namedArguments]) |
+ => new Selector(SelectorKind.CALL, new Name(name, library), |
+ new CallStructure(arity, namedArguments)); |
+ |
+ factory Selector.callDefaultConstructor() |
+ => new Selector( |
+ SelectorKind.CALL, |
+ const PublicName(''), |
+ CallStructure.NO_ARGS); |
+ |
+ bool get isGetter => kind == SelectorKind.GETTER; |
+ bool get isSetter => kind == SelectorKind.SETTER; |
+ bool get isCall => kind == SelectorKind.CALL; |
+ bool get isClosureCall => isCall && memberName == CALL_NAME; |
+ |
+ bool get isIndex => kind == SelectorKind.INDEX && argumentCount == 1; |
+ bool get isIndexSet => kind == SelectorKind.INDEX && argumentCount == 2; |
+ |
+ bool get isOperator => kind == SelectorKind.OPERATOR; |
+ bool get isUnaryOperator => isOperator && argumentCount == 0; |
+ |
+ /** Check whether this is a call to 'assert'. */ |
+ bool get isAssert => isCall && identical(name, "assert"); |
+ |
+ bool get hasExactMask => false; |
+ TypeMask get mask => null; |
+ Selector get asUntyped => this; |
+ |
+ /** |
+ * The member name for invocation mirrors created from this selector. |
+ */ |
+ String get invocationMirrorMemberName => |
+ isSetter ? '$name=' : name; |
+ |
+ int get invocationMirrorKind { |
+ const int METHOD = 0; |
+ const int GETTER = 1; |
+ const int SETTER = 2; |
+ int kind = METHOD; |
+ if (isGetter) { |
+ kind = GETTER; |
+ } else if (isSetter) { |
+ kind = SETTER; |
+ } |
+ return kind; |
+ } |
+ |
+ bool appliesUnnamed(Element element, World world) { |
+ assert(sameNameHack(element, world)); |
+ return appliesUntyped(element, world); |
+ } |
+ |
+ bool appliesUntyped(Element element, World world) { |
+ assert(sameNameHack(element, world)); |
+ if (Elements.isUnresolved(element)) return false; |
+ if (memberName.isPrivate && memberName.library != element.library) { |
+ // TODO(johnniwinther): Maybe this should be |
+ // `memberName != element.memberName`. |
+ return false; |
} |
- return ''; |
+ if (world.isForeign(element)) return true; |
+ if (element.isSetter) return isSetter; |
+ if (element.isGetter) return isGetter || isCall; |
+ if (element.isField) { |
+ return isSetter |
+ ? !element.isFinal && !element.isConst |
+ : isGetter || isCall; |
+ } |
+ if (isGetter) return true; |
+ if (isSetter) return false; |
+ return signatureApplies(element); |
+ } |
+ |
+ bool signatureApplies(FunctionElement function) { |
+ return callStructure.signatureApplies(function); |
+ } |
+ |
+ bool sameNameHack(Element element, World world) { |
+ // TODO(ngeoffray): Remove workaround checks. |
+ return element.isConstructor || |
+ name == element.name || |
+ name == 'assert' && world.isAssertMethod(element); |
+ } |
+ |
+ bool applies(Element element, World world) { |
+ if (!sameNameHack(element, world)) return false; |
+ return appliesUnnamed(element, world); |
+ } |
+ |
+ bool match(SelectorKind kind, |
+ Name memberName, |
+ CallStructure callStructure) { |
+ return this.kind == kind |
+ && this.memberName == memberName |
+ && this.callStructure.match(callStructure); |
+ } |
+ |
+ static int computeHashCode(SelectorKind kind, |
+ Name name, |
+ CallStructure callStructure) { |
+ // Add bits from name and kind. |
+ int hash = mixHashCodeBits(name.hashCode, kind.hashCode); |
+ // Add bits from the call structure. |
+ return mixHashCodeBits(hash, callStructure.hashCode); |
} |
String toString() { |
- String named = ''; |
String type = ''; |
- if (namedArgumentCount > 0) named = ', named=${namedArgumentsToString()}'; |
if (mask != null) type = ', mask=$mask'; |
- return 'Selector($kind, $name, ' |
- 'arity=$argumentCount$named$type)'; |
+ return 'Selector($kind, $name, ${callStructure.structureToString()}$type)'; |
} |
Selector extendIfReachesAll(Compiler compiler) { |
@@ -730,11 +785,8 @@ class TypedSelector extends Selector { |
TypedSelector.internal(this.mask, Selector selector, int hashCode) |
: asUntyped = selector, |
super.internal(selector.kind, |
- selector.name, |
- selector.library, |
- selector.argumentCount, |
- selector.namedArguments, |
- selector._orderedNamedArguments, |
+ selector.memberName, |
+ selector.callStructure, |
hashCode) { |
assert(mask != null); |
assert(asUntyped.mask == null); |
@@ -758,7 +810,7 @@ class TypedSelector extends Selector { |
.putIfAbsent(untyped, () => new Map<TypeMask, TypedSelector>()); |
TypedSelector result = map[mask]; |
if (result == null) { |
- int hashCode = Selector.mixHashCodeBits(untyped.hashCode, mask.hashCode); |
+ int hashCode = mixHashCodeBits(untyped.hashCode, mask.hashCode); |
result = map[mask] = new TypedSelector.internal(mask, untyped, hashCode); |
} |
return result; |