Index: sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart |
diff --git a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart |
index ec025ead89457d24c056e80241745435acd017dd..88d9fea4177f1d773af631b0f4c864a10ba34500 100644 |
--- a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart |
+++ b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart |
@@ -484,7 +484,7 @@ class ConcreteTypesInferrer { |
List<FunctionElement> getMembersByName(SourceString methodName) { |
// TODO(polux): make this faster! |
var result = new List<FunctionElement>(); |
- for (final cls in compiler.enqueuer.resolution.seenClasses) { |
+ for (ClassElement cls in compiler.enqueuer.resolution.seenClasses) { |
Element elem = cls.lookupLocalMember(methodName); |
if (elem != null) { |
result.add(elem); |
@@ -992,55 +992,93 @@ class TypeInferrerVisitor extends ResolvedVisitor<ConcreteType> { |
inferrer.fail(node, 'not yet implemented'); |
} |
+ ConcreteType analyzeSetElement(Element receiver, ConcreteType argumentType) { |
+ environment = environment.put(receiver, argumentType); |
+ if (receiver.isField()) { |
+ inferrer.augmentFieldType(receiver, argumentType); |
+ } else if (receiver.isSetter()){ |
+ FunctionElement setter = receiver; |
+ // TODO(polux): A setter always returns void so there's no need to |
+ // invalidate its callers even if it is called with new arguments. |
+ // However, if we start to record more than returned types, like |
+ // exceptions for instance, we need to do it by uncommenting the following |
+ // line. |
+ // inferrer.addCaller(setter, currentMethod); |
+ BaseType baseReceiverType = new ClassBaseType(receiver.enclosingElement); |
+ inferrer.getSendReturnType(setter, baseReceiverType, |
+ new ArgumentsTypes([argumentType], new Map())); |
+ } |
+ return argumentType; |
+ } |
+ |
+ ConcreteType analyzeSetNode(Node receiver, ConcreteType argumentType, |
+ SourceString source) { |
+ ConcreteType receiverType = analyze(receiver); |
+ |
+ void augmentField(BaseType baseReceiverType, Element fieldOrSetter) { |
+ if (fieldOrSetter.isField()) { |
+ inferrer.augmentFieldType(fieldOrSetter, argumentType); |
+ } else { |
+ AbstractFieldElement abstractField = fieldOrSetter; |
+ FunctionElement setter = abstractField.setter; |
+ // TODO(polux): A setter always returns void so there's no need to |
+ // invalidate its callers even if it is called with new arguments. |
+ // However, if we start to record more than returned types, like |
+ // exceptions for instance, we need to do it by uncommenting the |
+ // following line. |
+ // inferrer.addCaller(setter, currentMethod); |
+ inferrer.getSendReturnType(setter, baseReceiverType, |
+ new ArgumentsTypes([argumentType], new Map())); |
+ } |
+ } |
+ |
+ if (receiverType.isUnkown()) { |
+ for (FunctionElement member in inferrer.getMembersByName(source)) { |
+ Element classElem = member.getEnclosingClass(); |
+ BaseType baseReceiverType = new ClassBaseType(classElem); |
+ augmentField(baseReceiverType, member); |
+ } |
+ } else { |
+ for (ClassBaseType baseReceiverType in receiverType.baseTypes) { |
+ Element member = baseReceiverType.element.lookupMember(source); |
+ if (member != null) { |
+ augmentField(baseReceiverType, member); |
+ } |
+ } |
+ } |
+ return argumentType; |
+ } |
+ |
+ SourceString canonicalizeCompoundOperator(String op) { |
+ if (op == '++') return const SourceString(r'operator$add'); |
+ else return const SourceString(r'operator$sub'); |
+ } |
+ |
// TODO(polux): handle sendset as expression |
ConcreteType visitSendSet(SendSet node) { |
Identifier selector = node.selector; |
final name = node.assignmentOperator.source.stringValue; |
- if (identical(name, '++') || identical(name, '--')) { |
- inferrer.fail(node, 'not yet implemented'); |
+ ConcreteType argumentType; |
+ if (name == '++' || name == '--') { |
+ ConcreteType receiverType = visitGetterSend(node); |
+ SourceString canonicalizedMethodName = canonicalizeCompoundOperator(name); |
+ List<ConcreteType> positionalArguments = <ConcreteType>[ |
+ new ConcreteType.singleton(inferrer.baseTypes.intBaseType)]; |
+ ArgumentsTypes argumentsTypes = |
+ new ArgumentsTypes(positionalArguments, new Map()); |
+ argumentType = analyzeDynamicSend(receiverType, canonicalizedMethodName, |
+ argumentsTypes); |
} else { |
- Element element = elements[node]; |
- if (element != null) { |
- ConcreteType type = analyze(node.argumentsNode); |
- environment = environment.put(elements[node], type); |
- if (element.isField()) { |
- inferrer.augmentFieldType(element, type); |
- } |
- } else { |
- ConcreteType receiverType = analyze(node.receiver); |
- ConcreteType type = analyze(node.argumentsNode); |
- SourceString source = node.selector.asIdentifier().source; |
- |
- void augmentField(BaseType baseReceiverType, Element fieldOrSetter) { |
- if (fieldOrSetter.isField()) { |
- inferrer.augmentFieldType(fieldOrSetter, type); |
- } else { |
- FunctionElement setter = |
- (fieldOrSetter as AbstractFieldElement).setter; |
- // TODO: uncomment if we add an effect system |
- //inferrer.addCaller(setter, currentMethod); |
- inferrer.getSendReturnType(setter, baseReceiverType, |
- new ArgumentsTypes([type], new Map())); |
- } |
- } |
+ argumentType = analyze(node.argumentsNode); |
+ } |
- if (receiverType.isUnkown()) { |
- for (final member in inferrer.getMembersByName(source)) { |
- Element classElem = member.enclosingElement; |
- BaseType baseReceiverType = new ClassBaseType(classElem); |
- augmentField(baseReceiverType, member); |
- } |
- } else { |
- for (ClassBaseType baseReceiverType in receiverType.baseTypes) { |
- Element member = baseReceiverType.element.lookupMember(source); |
- if (member != null) { |
- augmentField(baseReceiverType, member); |
- } |
- } |
- } |
- } |
+ Element element = elements[node]; |
+ if (element != null) { |
+ return analyzeSetElement(element, argumentType); |
+ } else { |
+ return analyzeSetNode(node.receiver, argumentType, |
+ node.selector.asIdentifier().source); |
} |
- return new ConcreteType.empty(); |
} |
ConcreteType visitLiteralInt(LiteralInt node) { |
@@ -1237,6 +1275,19 @@ class TypeInferrerVisitor extends ResolvedVisitor<ConcreteType> { |
return visitDynamicSend(node); |
} |
+ ConcreteType analyzeFieldRead(Element field) { |
+ inferrer.addReader(field, currentMethod); |
+ return inferrer.getFieldType(field); |
+ } |
+ |
+ ConcreteType analyzeGetterSend(BaseType baseReceiverType, |
+ FunctionElement getter) { |
+ inferrer.addCaller(getter, currentMethod); |
+ return inferrer.getSendReturnType(getter, |
+ baseReceiverType, |
+ new ArgumentsTypes([], new Map())); |
+ } |
+ |
ConcreteType visitGetterSend(Send node) { |
Element element = elements[node]; |
if (element != null) { |
@@ -1246,9 +1297,15 @@ class TypeInferrerVisitor extends ResolvedVisitor<ConcreteType> { |
// node is a local variable |
return result; |
} else { |
- // node is a field of this |
- inferrer.addReader(element, currentMethod); |
- return inferrer.getFieldType(element); |
+ // node is a field or a getter of this |
+ if (element.isField()) { |
+ return analyzeFieldRead(element); |
+ } else { |
+ assert(element.isGetter()); |
+ ClassBaseType baseReceiverType = |
+ new ClassBaseType(element.enclosingElement); |
+ return analyzeGetterSend(baseReceiverType, element); |
+ } |
} |
} else { |
// node is a field of not(this) |
@@ -1257,18 +1314,12 @@ class TypeInferrerVisitor extends ResolvedVisitor<ConcreteType> { |
ConcreteType result = new ConcreteType.empty(); |
void augmentResult(BaseType baseReceiverType, Element getterOrField) { |
if (getterOrField.isField()) { |
- inferrer.addReader(getterOrField, currentMethod); |
- result = result.union(inferrer.getFieldType(getterOrField)); |
+ result = result.union(analyzeFieldRead(getterOrField)); |
} else { |
// call to a getter |
- FunctionElement getter = |
- (getterOrField as AbstractFieldElement).getter; |
- inferrer.addCaller(getter, currentMethod); |
- ConcreteType returnType = |
- inferrer.getSendReturnType(getter, |
- baseReceiverType, |
- new ArgumentsTypes([], new Map())); |
- result = result.union(returnType); |
+ AbstractFieldElement abstractField = getterOrField; |
+ result = result.union(analyzeGetterSend(baseReceiverType, |
+ abstractField.getter)); |
} |
} |
@@ -1277,7 +1328,7 @@ class TypeInferrerVisitor extends ResolvedVisitor<ConcreteType> { |
List<Element> members = |
inferrer.getMembersByName(node.selector.asIdentifier().source); |
for (final member in members) { |
- Element classElement = member.enclosingElement; |
+ Element classElement = member.getEnclosingClass(); |
ClassBaseType baseReceiverType = new ClassBaseType(classElement); |
augmentResult(baseReceiverType, member); |
} |
@@ -1342,18 +1393,15 @@ class TypeInferrerVisitor extends ResolvedVisitor<ConcreteType> { |
: s; |
} |
- ConcreteType visitDynamicSend(Send node) { |
- ConcreteType receiverType = (node.receiver != null) |
- ? analyze(node.receiver) |
- : new ConcreteType.singleton( |
- new ClassBaseType(currentMethod.getEnclosingClass())); |
+ ConcreteType analyzeDynamicSend(ConcreteType receiverType, |
+ SourceString canonicalizedMethodName, |
+ ArgumentsTypes argumentsTypes) { |
ConcreteType result = new ConcreteType.empty(); |
- final argumentsTypes = analyzeArguments(node.arguments); |
if (receiverType.isUnkown()) { |
- List<FunctionElement> methods = inferrer.getMembersByName( |
- canonicalizeMethodName(node.selector.asIdentifier().source)); |
- for (final method in methods) { |
+ List<FunctionElement> methods = |
+ inferrer.getMembersByName(canonicalizedMethodName); |
+ for (FunctionElement method in methods) { |
inferrer.addCaller(method, currentMethod); |
Element classElem = method.enclosingElement; |
ClassBaseType baseReceiverType = new ClassBaseType(classElem); |
@@ -1365,8 +1413,8 @@ class TypeInferrerVisitor extends ResolvedVisitor<ConcreteType> { |
for (BaseType baseReceiverType in receiverType.baseTypes) { |
if (!baseReceiverType.isNull()) { |
ClassBaseType classBaseReceiverType = baseReceiverType; |
- FunctionElement method = classBaseReceiverType.element |
- .lookupMember(canonicalizeMethodName(node.selector.asIdentifier().source)); |
+ FunctionElement method = classBaseReceiverType.element.lookupMember( |
+ canonicalizedMethodName); |
if (method != null) { |
inferrer.addCaller(method, currentMethod); |
result = result.union(inferrer.getSendReturnType(method, |
@@ -1378,6 +1426,17 @@ class TypeInferrerVisitor extends ResolvedVisitor<ConcreteType> { |
return result; |
} |
+ ConcreteType visitDynamicSend(Send node) { |
+ ConcreteType receiverType = (node.receiver != null) |
+ ? analyze(node.receiver) |
+ : new ConcreteType.singleton( |
+ new ClassBaseType(currentMethod.getEnclosingClass())); |
+ SourceString name = |
+ canonicalizeMethodName(node.selector.asIdentifier().source); |
+ ArgumentsTypes argumentsTypes = analyzeArguments(node.arguments); |
+ return analyzeDynamicSend(receiverType, name, argumentsTypes); |
+ } |
+ |
ConcreteType visitForeignSend(Send node) { |
inferrer.fail(node, 'not implemented'); |
} |