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 e619ae512afe706aaac9c72f6508db023b6599d5..d5b46c68cb9fe26ab093c9b12d9a5d4109fc9a4f 100644 |
--- a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart |
+++ b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart |
@@ -94,6 +94,7 @@ abstract class ConcreteType { |
ConcreteType union(ConcreteType other); |
bool isUnkown(); |
+ bool isEmpty(); |
Set<BaseType> get baseTypes; |
/** |
@@ -109,6 +110,7 @@ abstract class ConcreteType { |
class UnknownConcreteType implements ConcreteType { |
const UnknownConcreteType(); |
bool isUnkown() => true; |
+ bool isEmpty() => false; |
bool operator ==(ConcreteType other) => identical(this, other); |
Set<BaseType> get baseTypes => |
new Set<BaseType>.from([const UnknownBaseType()]); |
@@ -131,6 +133,7 @@ class UnionType implements ConcreteType { |
UnionType(this.baseTypes); |
bool isUnkown() => false; |
+ bool isEmpty() => baseTypes.isEmpty; |
bool operator ==(ConcreteType other) { |
if (other is! UnionType) return false; |
@@ -1047,31 +1050,54 @@ class TypeInferrerVisitor extends ResolvedVisitor<ConcreteType> { |
return argumentType; |
} |
- SourceString canonicalizeCompoundOperator(String op) { |
+ SourceString canonicalizeCompoundOperator(SourceString op) { |
// TODO(ahe): This class should work on elements or selectors, not |
// names. Otherwise, it is repeating work the resolver has |
// already done (or should have done). In this case, the problem |
// is that the resolver is not recording the selectors it is |
// registering in registerBinaryOperator in |
// ResolverVisitor.visitSendSet. |
- if (op == '++') return const SourceString(r'+'); |
- else return const SourceString(r'-'); |
+ String stringValue = op.stringValue; |
+ if (stringValue == '++') return const SourceString(r'+'); |
+ else if (stringValue == '--') return const SourceString(r'-'); |
+ else return Elements.mapToUserOperatorOrNull(op); |
} |
// TODO(polux): handle sendset as expression |
ConcreteType visitSendSet(SendSet node) { |
- Identifier selector = node.selector; |
- final name = node.assignmentOperator.source.stringValue; |
+ // Operator []= has a different behaviour than other send sets: it is |
+ // actually a send whose return type is that of its second argument. |
+ if (node.selector.asIdentifier().source.stringValue == '[]') { |
+ ConcreteType receiverType = analyze(node.receiver); |
+ ArgumentsTypes argumentsTypes = analyzeArguments(node.arguments); |
+ analyzeDynamicSend(receiverType, const SourceString('[]='), |
+ argumentsTypes); |
+ return argumentsTypes.positional[1]; |
+ } |
+ |
+ // All other operators have a single argument (++ and -- have an implicit |
+ // argument: 1). We will store its type in argumentType. |
ConcreteType argumentType; |
- if (name == '++' || name == '--') { |
+ SourceString operatorName = node.assignmentOperator.source; |
+ SourceString compoundOperatorName = |
+ canonicalizeCompoundOperator(node.assignmentOperator.source); |
+ // ++, --, +=, -=, ... |
+ if (compoundOperatorName != null) { |
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 is either computed from the actual arguments or [{int}] |
+ // in case of ++ or --. |
+ ArgumentsTypes argumentsTypes; |
+ if (operatorName.stringValue == '++' |
+ || operatorName.stringValue == '--') { |
+ List<ConcreteType> positionalArguments = <ConcreteType>[ |
+ new ConcreteType.singleton(inferrer.baseTypes.intBaseType)]; |
+ argumentsTypes = new ArgumentsTypes(positionalArguments, new Map()); |
+ } else { |
+ argumentsTypes = analyzeArguments(node.arguments); |
+ } |
+ argumentType = analyzeDynamicSend(receiverType, compoundOperatorName, |
argumentsTypes); |
+ // The simple assignment case: receiver = argument. |
} else { |
argumentType = analyze(node.argumentsNode); |
} |
@@ -1359,47 +1385,6 @@ class TypeInferrerVisitor extends ResolvedVisitor<ConcreteType> { |
inferrer.fail(node, 'not implemented'); |
} |
- // TODO(polux): handle unary operators and share this list with the rest of |
- // dart2js. |
- final Set<SourceString> operators = new Set<SourceString>() |
- ..add(const SourceString('==')) |
- ..add(const SourceString('!=')) |
- ..add(const SourceString('~')) |
- ..add(const SourceString('[]')) |
- ..add(const SourceString('[]=')) |
- ..add(const SourceString('*')) |
- ..add(const SourceString('*=')) |
- ..add(const SourceString('/')) |
- ..add(const SourceString('/=')) |
- ..add(const SourceString('%')) |
- ..add(const SourceString('%=')) |
- ..add(const SourceString('~/')) |
- ..add(const SourceString('~/=')) |
- ..add(const SourceString('+')) |
- ..add(const SourceString('+=')) |
- ..add(const SourceString('-')) |
- ..add(const SourceString('-=')) |
- ..add(const SourceString('<<')) |
- ..add(const SourceString('<<=')) |
- ..add(const SourceString('>>')) |
- ..add(const SourceString('>>=')) |
- ..add(const SourceString('>=')) |
- ..add(const SourceString('>')) |
- ..add(const SourceString('<=')) |
- ..add(const SourceString('<')) |
- ..add(const SourceString('&')) |
- ..add(const SourceString('&=')) |
- ..add(const SourceString('^')) |
- ..add(const SourceString('^=')) |
- ..add(const SourceString('|')) |
- ..add(const SourceString('|=')); |
- |
- SourceString canonicalizeMethodName(SourceString s) { |
- return operators.contains(s) |
- ? Elements.constructOperatorName(s, false) |
- : s; |
- } |
- |
ConcreteType analyzeDynamicSend(ConcreteType receiverType, |
SourceString canonicalizedMethodName, |
ArgumentsTypes argumentsTypes) { |
@@ -1437,6 +1422,14 @@ class TypeInferrerVisitor extends ResolvedVisitor<ConcreteType> { |
return result; |
} |
+ SourceString canonicalizeMethodName(SourceString name) { |
+ // TODO(polux): handle unary- |
+ SourceString operatorName = |
+ Elements.constructOperatorNameOrNull(name, false); |
+ if (operatorName != null) return operatorName; |
+ return name; |
+ } |
+ |
ConcreteType visitDynamicSend(Send node) { |
ConcreteType receiverType = (node.receiver != null) |
? analyze(node.receiver) |
@@ -1445,7 +1438,16 @@ class TypeInferrerVisitor extends ResolvedVisitor<ConcreteType> { |
SourceString name = |
canonicalizeMethodName(node.selector.asIdentifier().source); |
ArgumentsTypes argumentsTypes = analyzeArguments(node.arguments); |
- return analyzeDynamicSend(receiverType, name, argumentsTypes); |
+ if (name.stringValue == '!=') { |
+ ConcreteType returnType = analyzeDynamicSend(receiverType, |
+ const SourceString('=='), |
+ argumentsTypes); |
+ return returnType.isEmpty() |
+ ? returnType |
+ : new ConcreteType.singleton(inferrer.baseTypes.boolBaseType); |
+ } else { |
+ return analyzeDynamicSend(receiverType, name, argumentsTypes); |
+ } |
} |
ConcreteType visitForeignSend(Send node) { |