Index: pkg/compiler/lib/src/cps_ir/type_propagation.dart |
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
index 8a4daba9fcc0099edb0f97a34fe1801d79662306..f558d756a785c5aa8beff40962ed29cb35233c34 100644 |
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
@@ -591,6 +591,46 @@ class ConstantPropagationLattice { |
return constant(new StringConstantValue(new ast.DartString.literal(value))); |
} |
+ AbstractConstantValue indexSpecial(AbstractConstantValue left, |
+ AbstractConstantValue right) { |
+ if (left.isNothing || right.isNothing) return nothing; |
+ if (right.isConstant) { |
+ ConstantValue index = right.constant; |
+ if (left.isConstant) { |
+ ConstantValue receiver = left.constant; |
+ if (receiver is StringConstantValue) { |
+ if (index is IntConstantValue) { |
+ String stringValue = receiver.primitiveValue.slowToString(); |
+ int indexValue = index.primitiveValue; |
+ if (0 <= indexValue && indexValue < stringValue.length) { |
+ return stringConstant(stringValue[indexValue]); |
+ } else { |
+ return nothing; // Will throw. |
+ } |
+ } |
+ } else if (receiver is ListConstantValue) { |
+ if (index is IntConstantValue) { |
+ int indexValue = index.primitiveValue; |
+ if (0 <= indexValue && indexValue < receiver.length) { |
+ return constant(receiver.entries[indexValue]); |
+ } else { |
+ return nothing; // Will throw. |
+ } |
+ } |
+ } else if (receiver is MapConstantValue) { |
+ ConstantValue result = receiver.lookup(index); |
+ if (result != null) { |
+ return constant(result); |
+ } |
+ return constant(new NullConstantValue()); |
+ } |
+ } |
+ TypeMask type = typeSystem.indexWithConstant(left.type, index); |
+ if (type != null) return nonConstant(type); |
+ } |
+ return null; // The caller will use return type from type inference. |
+ } |
+ |
AbstractConstantValue stringify(AbstractConstantValue value) { |
if (value.isNothing) return nothing; |
if (value.isNonConst) return nonConstant(typeSystem.stringType); |
@@ -2607,6 +2647,14 @@ class TypePropagationVisitor implements Visitor { |
return; // And come back later. |
} |
+ void finish(AbstractConstantValue result) { |
+ if (result == null) { |
+ setResult(node, lattice.getInvokeReturnType(node.selector, node.mask)); |
+ } else { |
+ setResult(node, result, canReplace: true); |
+ } |
+ } |
+ |
if (node.selector.isGetter) { |
// Constant fold known length of containers. |
if (node.selector == Selectors.length) { |
@@ -2615,10 +2663,11 @@ class TypePropagationVisitor implements Visitor { |
AbstractConstantValue length = lattice.lengthSpecial(object); |
if (length != null) { |
setResult(node, length, canReplace: !object.isNullable); |
+ return; |
} |
} |
} |
- setResult(node, lattice.getInvokeReturnType(node.selector, node.mask)); |
+ finish(null); |
return; |
} |
@@ -2629,16 +2678,20 @@ class TypePropagationVisitor implements Visitor { |
AbstractConstantValue right = getValue(node.dartArgument(0)); |
result = lattice.codeUnitAtSpecial(object, right); |
} |
- if (result == null) { |
- setResult(node, lattice.getInvokeReturnType(node.selector, node.mask)); |
- } else { |
- setResult(node, result, canReplace: true); |
- } |
+ finish(result); |
+ return; |
+ } |
+ |
+ if (node.selector == Selectors.index) { |
+ AbstractConstantValue object = getValue(node.dartReceiver); |
+ AbstractConstantValue right = getValue(node.dartArgument(0)); |
+ AbstractConstantValue result = lattice.indexSpecial(object, right); |
+ finish(result); |
return; |
} |
if (!node.selector.isOperator) { |
- setResult(node, lattice.getInvokeReturnType(node.selector, node.mask)); |
+ finish(null); |
return; |
} |
@@ -2660,14 +2713,7 @@ class TypePropagationVisitor implements Visitor { |
BinaryOperator operator = BinaryOperator.parse(opname); |
result = lattice.binaryOp(operator, left, right); |
} |
- |
- // Update value of the continuation parameter. Again, this is effectively |
- // a phi. |
- if (result == null) { |
- setResult(node, lattice.getInvokeReturnType(node.selector, node.mask)); |
- } else { |
- setResult(node, result, canReplace: true); |
- } |
+ finish(result); |
} |
void visitApplyBuiltinOperator(ApplyBuiltinOperator node) { |