| Index: pkg/compiler/lib/src/js_backend/runtime_types.dart
|
| diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
|
| index 923148ad7a4c1a7f1494d8ce3e49aeef6f37bf59..e9c66980cc595ba17ced220208568d75100b4bfc 100644
|
| --- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
|
| +++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
|
| @@ -878,6 +878,8 @@ class TypeRepresentationGenerator implements DartTypeVisitor {
|
| OnVariableCallback onVariable;
|
| ShouldEncodeTypedefCallback shouldEncodeTypedef;
|
|
|
| + Map<ResolutionTypeVariableType, jsAst.Expression> typedefBindings;
|
| +
|
| TypeRepresentationGenerator(this.namer, this.emitter);
|
|
|
| /**
|
| @@ -888,6 +890,7 @@ class TypeRepresentationGenerator implements DartTypeVisitor {
|
| ResolutionDartType type,
|
| OnVariableCallback onVariable,
|
| ShouldEncodeTypedefCallback encodeTypedef) {
|
| + assert(typedefBindings == null);
|
| this.onVariable = onVariable;
|
| this.shouldEncodeTypedef = (encodeTypedef != null)
|
| ? encodeTypedef
|
| @@ -906,6 +909,10 @@ class TypeRepresentationGenerator implements DartTypeVisitor {
|
| visit(ResolutionDartType type, [_]) => type.accept(this, null);
|
|
|
| visitTypeVariableType(ResolutionTypeVariableType type, _) {
|
| + if (typedefBindings != null) {
|
| + assert(typedefBindings[type] != null);
|
| + return typedefBindings[type];
|
| + }
|
| return onVariable(type);
|
| }
|
|
|
| @@ -1001,6 +1008,42 @@ class TypeRepresentationGenerator implements DartTypeVisitor {
|
| visitTypedefType(ResolutionTypedefType type, _) {
|
| bool shouldEncode = shouldEncodeTypedef(type);
|
| ResolutionDartType unaliasedType = type.unaliased;
|
| +
|
| + var oldBindings = typedefBindings;
|
| + if (typedefBindings == null) {
|
| + // First level typedef - capture arguments for re-use within typedef body.
|
| + //
|
| + // The type `Map<T, Foo<Set<T>>>` contains one type variable referenced
|
| + // twice, so there are two inputs into the HTypeInfoExpression
|
| + // instruction.
|
| + //
|
| + // If Foo is a typedef, T can be reused, e.g.
|
| + //
|
| + // typedef E Foo<E>(E a, E b);
|
| + //
|
| + // As the typedef is expanded (to (Set<T>, Set<T>) => Set<T>) it should
|
| + // not consume additional types from the to-level input. We prevent this
|
| + // by capturing the types and using the captured type expressions inside
|
| + // the typedef expansion.
|
| + //
|
| + // TODO(sra): We should make the type subexpression Foo<...> be a second
|
| + // HTypeInfoExpression, with Set<T> as its input (a third
|
| + // HTypeInfoExpression). This would share all the Set<T> subexpressions
|
| + // instead of duplicating them. This would require HTypeInfoExpression
|
| + // inputs to correspond to type variables AND typedefs.
|
| + typedefBindings = <ResolutionTypeVariableType, jsAst.Expression>{};
|
| + type.forEachTypeVariable((variable) {
|
| + if (variable is! MethodTypeVariableType) {
|
| + typedefBindings[variable] = onVariable(variable);
|
| + }
|
| + });
|
| + }
|
| +
|
| + jsAst.Expression finish(jsAst.Expression result) {
|
| + typedefBindings = oldBindings;
|
| + return result;
|
| + }
|
| +
|
| if (shouldEncode) {
|
| jsAst.ObjectInitializer initializer = unaliasedType.accept(this, null);
|
| // We have to encode the aliased type.
|
| @@ -1011,9 +1054,9 @@ class TypeRepresentationGenerator implements DartTypeVisitor {
|
| // Add it to the function-type object.
|
| jsAst.LiteralString tag = js.string(namer.typedefTag);
|
| initializer.properties.add(new jsAst.Property(tag, encodedTypedef));
|
| - return initializer;
|
| + return finish(initializer);
|
| } else {
|
| - return unaliasedType.accept(this, null);
|
| + return finish(unaliasedType.accept(this, null));
|
| }
|
| }
|
| }
|
|
|