Index: pkg/compiler/lib/src/inferrer/type_graph_nodes.dart |
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart |
index d5492f1a3d1446b582e61d0f3d53f4d2d1626282..dedb4e2ecbdfab549799619f05147a4d5c1f581a 100644 |
--- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart |
+++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart |
@@ -856,10 +856,13 @@ class DynamicCallSiteTypeInformation extends CallSiteTypeInformation { |
} |
/** |
- * We optimize certain operations on the [int] class because we know |
- * more about their return type than the actual Dart code. For |
- * example, we know int + int returns an int. The Dart code for |
- * [int.operator+] only says it returns a [num]. |
+ * We optimize certain operations on the [int] class because we know more |
+ * about their return type than the actual Dart code. For example, we know int |
+ * + int returns an int. The Dart library code for [int.operator+] only says |
+ * it returns a [num]. |
+ * |
+ * Returns the more precise TypeInformation, or `null` to defer to the library |
+ * code. |
*/ |
TypeInformation handleIntrisifiedSelector( |
Selector selector, TypeMask mask, TypeGraphInferrerEngine inferrer) { |
@@ -883,63 +886,78 @@ class DynamicCallSiteTypeInformation extends CallSiteTypeInformation { |
return info.type |
.satisfies(classWorld.backend.positiveIntImplementation, classWorld); |
} |
+ TypeInformation tryLater() => inferrer.types.nonNullEmptyType; |
+ |
+ TypeInformation argument = |
+ arguments.isEmpty ? null : arguments.positional.first; |
String name = selector.name; |
- // We are optimizing for the cases that are not expressed in the |
- // Dart code, for example: |
- // int + int -> int |
- // uint31 | uint31 -> uint31 |
- if (name == '*' || |
- name == '+' || |
- name == '%' || |
- name == 'remainder' || |
- name == '~/') { |
- if (isPositiveInt(receiver) && |
- arguments.hasOnePositionalArgumentThatMatches(isPositiveInt)) { |
- // uint31 + uint31 -> uint32 |
- if (name == '+' && |
- isUInt31(receiver) && |
- arguments.hasOnePositionalArgumentThatMatches(isUInt31)) { |
- return inferrer.types.uint32Type; |
- } else { |
+ // These are type inference rules only for useful cases that are not |
+ // expressed in the library code, for example: |
+ // |
+ // int + int -> int |
+ // uint31 | uint31 -> uint31 |
+ // |
+ switch (name) { |
+ case '*': |
+ case '+': |
+ case '%': |
+ case 'remainder': |
+ case '~/': |
+ if (isEmpty(argument)) return tryLater(); |
+ if (isPositiveInt(receiver) && isPositiveInt(argument)) { |
+ // uint31 + uint31 -> uint32 |
+ if (name == '+' && isUInt31(receiver) && isUInt31(argument)) { |
+ return inferrer.types.uint32Type; |
+ } |
return inferrer.types.positiveIntType; |
} |
- } else if (arguments.hasOnePositionalArgumentThatMatches(isInt)) { |
- return inferrer.types.intType; |
- } else if (arguments.hasOnePositionalArgumentThatMatches(isEmpty)) { |
- return inferrer.types.nonNullEmptyType; |
- } else { |
+ if (isInt(argument)) { |
+ return inferrer.types.intType; |
+ } |
return null; |
- } |
- } else if (name == '|' || name == '^') { |
- if (isUInt31(receiver) && |
- arguments.hasOnePositionalArgumentThatMatches(isUInt31)) { |
- return inferrer.types.uint31Type; |
- } |
- } else if (name == '>>') { |
- if (isUInt31(receiver)) { |
- return inferrer.types.uint31Type; |
- } |
- } else if (name == '&') { |
- if (isUInt31(receiver) || |
- arguments.hasOnePositionalArgumentThatMatches(isUInt31)) { |
- return inferrer.types.uint31Type; |
- } |
- } else if (name == 'unary-') { |
- // The receiver being an int, the return value will also be an |
- // int. |
- return inferrer.types.intType; |
- } else if (name == '-') { |
- if (arguments.hasOnePositionalArgumentThatMatches(isInt)) { |
+ |
+ case '|': |
+ case '^': |
+ if (isEmpty(argument)) return tryLater(); |
+ if (isUInt31(receiver) && isUInt31(argument)) { |
+ return inferrer.types.uint31Type; |
+ } |
+ return null; |
+ |
+ case '>>': |
+ if (isEmpty(argument)) return tryLater(); |
+ if (isUInt31(receiver)) { |
+ return inferrer.types.uint31Type; |
+ } |
+ return null; |
+ |
+ case '&': |
+ if (isEmpty(argument)) return tryLater(); |
+ if (isUInt31(receiver) || isUInt31(argument)) { |
+ return inferrer.types.uint31Type; |
+ } |
+ return null; |
+ |
+ case '-': |
+ if (isEmpty(argument)) return tryLater(); |
+ if (isInt(argument)) { |
+ return inferrer.types.intType; |
+ } |
+ return null; |
+ |
+ case 'unary-': |
+ // The receiver being an int, the return value will also be an int. |
return inferrer.types.intType; |
- } else if (arguments.hasOnePositionalArgumentThatMatches(isEmpty)) { |
- return inferrer.types.nonNullEmptyType; |
- } |
- return null; |
- } else if (name == 'abs') { |
- return arguments.hasNoArguments() ? inferrer.types.positiveIntType : null; |
+ |
+ case 'abs': |
+ return arguments.hasNoArguments() |
+ ? inferrer.types.positiveIntType |
+ : null; |
+ |
+ default: |
+ return null; |
} |
- return null; |
} |
TypeMask computeType(TypeGraphInferrerEngine inferrer) { |