| 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) {
|
|
|