Index: pkg/compiler/lib/src/ssa/builder_kernel.dart |
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart |
index 3f407cab4f35bd7c4a41ab38c29c0d1ebc10b184..7050eae76ef968d6972f3464167f9e0ea2b1f566 100644 |
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart |
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart |
@@ -29,6 +29,7 @@ import 'loop_handler.dart'; |
import 'nodes.dart'; |
import 'ssa_branch_builder.dart'; |
import 'type_builder.dart'; |
+import 'types.dart' show TypeMaskFactory; |
class SsaKernelBuilderTask extends CompilerTask { |
final JavaScriptBackend backend; |
@@ -57,6 +58,14 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder { |
final ResolvedAst resolvedAst; |
final CodegenRegistry registry; |
+ /// A stack of [DartType]s that have been seen during inlining of factory |
+ /// constructors. These types are preserved in [HInvokeStatic]s and |
+ /// [HCreate]s inside the inline code and registered during code generation |
+ /// for these nodes. |
+ // TODO(karlklose): consider removing this and keeping the (substituted) types |
+ // of the type variables in an environment (like the [LocalsHandler]). |
+ final List<DartType> currentImplicitInstantiations = <DartType>[]; |
+ |
@override |
JavaScriptBackend get backend => compiler.backend; |
@@ -320,6 +329,18 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder { |
closeFunction(); |
} |
+ void addImplicitInstantiation(DartType type) { |
+ if (type != null) { |
+ currentImplicitInstantiations.add(type); |
+ } |
+ } |
+ |
+ void removeImplicitInstantiation(DartType type) { |
+ if (type != null) { |
+ currentImplicitInstantiations.removeLast(); |
+ } |
+ } |
+ |
void openFunction() { |
HBasicBlock block = graph.addNewBlock(); |
open(graph.entry); |
@@ -715,7 +736,9 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder { |
stack.add(graph.addConstantNull(compiler)); |
} |
- HInstruction setRtiIfNeeded(HInstruction object, ir.ListLiteral listLiteral) { |
+ /// Set the runtime type information if necessary. |
+ HInstruction setListRuntimeTypeInfoIfNeeded( |
+ HInstruction object, ir.ListLiteral listLiteral) { |
InterfaceType type = localsHandler |
.substInContext(elements.getType(astAdapter.getNode(listLiteral))); |
if (!backend.classNeedsRti(type.element) || type.treatAsRaw) { |
@@ -744,7 +767,8 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder { |
} |
listInstruction = new HLiteralList(elements, backend.extendableArrayType); |
add(listInstruction); |
- listInstruction = setRtiIfNeeded(listInstruction, listLiteral); |
+ listInstruction = |
+ setListRuntimeTypeInfoIfNeeded(listInstruction, listLiteral); |
} |
TypeMask type = astAdapter.typeOfNewList(targetElement, listLiteral); |
@@ -783,8 +807,52 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder { |
inputs.add(argList); |
} |
- // TODO(het): Add type information |
- _pushStaticInvocation(constructor, inputs, backend.dynamicType); |
+ assert(constructor.kind == ir.ProcedureKind.Factory); |
+ |
+ InterfaceType type = localsHandler |
+ .substInContext(elements.getType(astAdapter.getNode(mapLiteral))); |
+ |
+ ir.Class cls = constructor.enclosingClass; |
+ |
+ if (backend.classNeedsRti(astAdapter.getElement(cls))) { |
+ List<HInstruction> typeInputs = <HInstruction>[]; |
+ type.typeArguments.forEach((DartType argument) { |
+ typeInputs |
+ .add(typeBuilder.analyzeTypeArgument(argument, sourceElement)); |
+ }); |
+ |
+ // We lift this common call pattern into a helper function to save space |
+ // in the output. |
+ if (typeInputs.every((HInstruction input) => input.isNull())) { |
+ if (constructorArgs.isEmpty) { |
+ constructor = astAdapter.mapLiteralUntypedEmptyMaker; |
+ } else { |
+ constructor = astAdapter.mapLiteralUntypedMaker; |
+ } |
+ } else { |
+ inputs.addAll(typeInputs); |
+ } |
+ } |
+ |
+ // If runtime type information is needed and the map literal has no type |
+ // parameters, 'constructor' is a static function that forwards the call to |
+ // the factory constructor without type parameters. |
+ assert(constructor.kind == ir.ProcedureKind.Factory); |
+ |
+ // The instruction type will always be a subtype of the mapLiteralClass, but |
+ // type inference might discover a more specific type, or find nothing (in |
+ // dart2js unit tests). |
+ TypeMask mapType = new TypeMask.nonNullSubtype( |
+ astAdapter.getElement(astAdapter.mapLiteralClass), |
+ compiler.closedWorld); |
+ TypeMask returnTypeMask = TypeMaskFactory.inferredReturnTypeForElement( |
+ astAdapter.getElement(constructor), compiler); |
+ TypeMask instructionType = |
+ mapType.intersection(returnTypeMask, compiler.closedWorld); |
+ |
+ addImplicitInstantiation(type); |
+ _pushStaticInvocation(constructor, inputs, instructionType); |
+ removeImplicitInstantiation(type); |
} |
@override |
@@ -917,6 +985,10 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder { |
HInstruction instruction = new HInvokeStatic( |
astAdapter.getMember(target), arguments, typeMask, |
targetCanThrow: astAdapter.getCanThrow(target)); |
+ if (currentImplicitInstantiations.isNotEmpty) { |
+ instruction.instantiatedTypes = |
+ new List<DartType>.from(currentImplicitInstantiations); |
+ } |
instruction.sideEffects = astAdapter.getSideEffects(target); |
push(instruction); |