Index: pkg/compiler/lib/src/ssa/optimize.dart |
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart |
index 031922228f881912a882b621935a64d4a3312644..4700112b3211ec528f9b1bd3194091f8c985be00 100644 |
--- a/pkg/compiler/lib/src/ssa/optimize.dart |
+++ b/pkg/compiler/lib/src/ssa/optimize.dart |
@@ -1057,6 +1057,34 @@ class SsaInstructionSimplifier extends HBaseVisitor |
return node; |
} |
+ /// Read the type variable from an allocation of type [createdClass], where |
+ /// [selectTypeArgumentFromObjectCreation] extracts the type argument from |
+ /// the allocation for factory constructor call. |
+ HInstruction finishSubstituted(ClassElement createdClass, |
+ HInstruction selectTypeArgumentFromObjectCreation(int index)) { |
+ HInstruction instructionForTypeVariable(TypeVariableType tv) { |
+ return selectTypeArgumentFromObjectCreation( |
+ createdClass.thisType.typeArguments.indexOf(tv)); |
+ } |
+ |
+ DartType type = createdClass.thisType |
+ .asInstanceOf(variable.element.enclosingClass) |
+ .typeArguments[variable.element.index]; |
+ if (type is TypeVariableType) { |
+ return instructionForTypeVariable(type); |
+ } |
+ List<HInstruction> arguments = <HInstruction>[]; |
+ type.forEachTypeVariable((v) { |
+ arguments.add(instructionForTypeVariable(v)); |
+ }); |
+ HInstruction replacement = new HTypeInfoExpression( |
+ TypeInfoExpressionKind.COMPLETE, |
+ type, |
+ arguments, |
+ backend.dynamicType); |
+ return replacement; |
+ } |
+ |
// Type variable evaluated in the context of a constant can be replaced with |
// a ground term type. |
if (object is HConstant) { |
@@ -1067,10 +1095,42 @@ class SsaInstructionSimplifier extends HBaseVisitor |
return node; |
} |
- // TODO(sra): HTypeInfoReadVariable on an instance creation can be replaced |
- // with an input of the instance creation's HTypeInfoExpression (or a |
- // HTypeInfoExpression of an input). This would in effect store-forward the |
- // type parameters. |
+ // Look for an allocation with type information and re-write type variable |
+ // as a function of the type parameters of the allocation. This effectively |
+ // store-forwards a type variable read through an allocation. |
+ |
+ // Match: |
+ // |
+ // setRuntimeTypeInfo( |
+ // HForeignNew(ClassElement), |
+ // HTypeInfoExpression(t_0, t_1, t_2, ...)); |
+ // |
+ // The `t_i` are the values of the type parameters of ClassElement. |
+ if (object is HInvokeStatic) { |
+ if (object.element == helpers.setRuntimeTypeInfo) { |
+ HInstruction allocation = object.inputs[0]; |
+ if (allocation is HForeignNew) { |
+ HInstruction typeInfo = object.inputs[1]; |
+ if (typeInfo is HTypeInfoExpression) { |
+ return finishSubstituted( |
+ allocation.element, (int index) => typeInfo.inputs[index]); |
+ } |
+ } |
+ return node; |
+ } |
+ // TODO(sra): Factory constructors pass type arguments after the value |
+ // arguments. The [select] argument indexes into these type arguments. |
+ } |
+ |
+ // Non-generic type (which extends or mixes in a generic type, for example |
+ // CodeUnits extends UnmodifiableListBase<int>). |
+ // Also used for raw-type when the type parameters are elided. |
+ if (object is HForeignNew) { |
+ return finishSubstituted( |
+ object.element, |
+ // If there are type arguments, all type arguments are 'dynamic'. |
+ (int i) => graph.addConstantNull(compiler)); |
+ } |
return node; |
} |