Skip to content
This repository was archived by the owner on Feb 22, 2018. It is now read-only.

Commit e1aa512

Browse files
optimize self-references in generic type definitions
fixes #556 [email protected] Review URL: https://codereview.chromium.org/1958193002 .
1 parent f8f9140 commit e1aa512

File tree

2 files changed

+55
-27
lines changed

2 files changed

+55
-27
lines changed

lib/src/compiler/code_generator.dart

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ class CodeGenerator extends GeneralizingAstVisitor
458458
return fromExpr;
459459
}
460460

461-
return js.call('dart.as(#, #)', [fromExpr, _emitTypeName(to)]);
461+
return js.call('dart.as(#, #)', [fromExpr, _emitType(to)]);
462462
}
463463

464464
@override
@@ -472,7 +472,7 @@ class CodeGenerator extends GeneralizingAstVisitor
472472
result = js.call('typeof # == #', [lhs, js.string(typeofName, "'")]);
473473
} else {
474474
// Always go through a runtime helper, because implicit interfaces.
475-
result = js.call('dart.is(#, #)', [lhs, _emitTypeName(type)]);
475+
result = js.call('dart.is(#, #)', [lhs, _emitType(type)]);
476476
}
477477

478478
if (node.notOperator != null) {
@@ -495,7 +495,7 @@ class CodeGenerator extends GeneralizingAstVisitor
495495
JS.Expression body = annotate(
496496
js.call('dart.typedef(#, () => #)', [
497497
js.string(element.name, "'"),
498-
_emitTypeName(element.type, lowerTypedef: true)
498+
_emitType(element.type, lowerTypedef: true)
499499
]),
500500
node,
501501
element);
@@ -513,7 +513,7 @@ class CodeGenerator extends GeneralizingAstVisitor
513513
JS.Expression visitTypeName(TypeName node) {
514514
// TODO(jmesserly): should only happen for erroneous code.
515515
if (node.type == null) return js.call('dart.dynamic');
516-
return _emitTypeName(node.type);
516+
return _emitType(node.type);
517517
}
518518

519519
@override
@@ -741,7 +741,7 @@ class CodeGenerator extends GeneralizingAstVisitor
741741
var values = new JS.ArrayInitializer(new List<JS.Expression>.from(
742742
fields.map((f) => js.call('#.#', [id, f.name]))));
743743
result.add(js.statement('#.values = dart.const(dart.list(#, #));',
744-
[id, values, _emitTypeName(type)]));
744+
[id, values, _emitType(type)]));
745745

746746
return _statement(result);
747747
}
@@ -759,7 +759,7 @@ class CodeGenerator extends GeneralizingAstVisitor
759759
]);
760760

761761
var dynType = fillDynamicTypeArgs(element.type);
762-
var genericInst = _emitTypeName(dynType, lowerGeneric: true);
762+
var genericInst = _emitType(dynType, lowerGeneric: true);
763763
return js.statement(
764764
'{ #; # = #; }', [genericDef, _emitTopLevelName(element), genericInst]);
765765
}
@@ -804,10 +804,10 @@ class CodeGenerator extends GeneralizingAstVisitor
804804
supertype = fillDynamicTypeArgs(supertype.element.type);
805805
_hasDeferredSupertype.add(element);
806806
}
807-
heritage = _emitTypeName(supertype);
807+
heritage = _emitType(supertype);
808808

809809
if (type.mixins.isNotEmpty) {
810-
var mixins = type.mixins.map(_emitTypeName).toList();
810+
var mixins = type.mixins.map(_emitType).toList();
811811
mixins.insert(0, heritage);
812812
heritage = js.call('dart.mixin(#)', [mixins]);
813813
}
@@ -1051,7 +1051,8 @@ class CodeGenerator extends GeneralizingAstVisitor
10511051
// TODO(jmesserly): we should really just extend Array in the first place.
10521052
newBaseClass = js.call('dart.global.#', [jsPeerName]);
10531053
} else if (_hasDeferredSupertype.contains(classElem)) {
1054-
newBaseClass = _emitTypeName(classElem.type.superclass);
1054+
newBaseClass = _emitType(classElem.type.superclass,
1055+
subClass: classElem, className: className);
10551056
}
10561057
if (newBaseClass != null) {
10571058
body.add(
@@ -1136,7 +1137,7 @@ class CodeGenerator extends GeneralizingAstVisitor
11361137
body.add(js.statement('#[dart.implements] = () => #;', [
11371138
className,
11381139
new JS.ArrayInitializer(new List<JS.Expression>.from(
1139-
classElem.interfaces.map(_emitTypeName)))
1140+
classElem.interfaces.map(_emitType)))
11401141
]));
11411142
}
11421143

@@ -1608,7 +1609,7 @@ class CodeGenerator extends GeneralizingAstVisitor
16081609
var paramType = param.element.type;
16091610
if (!constructor && _hasUnsoundTypeParameter(paramType)) {
16101611
body.add(js
1611-
.statement('dart.as(#, #);', [jsParam, _emitTypeName(paramType)]));
1612+
.statement('dart.as(#, #);', [jsParam, _emitType(paramType)]));
16121613
}
16131614
}
16141615
return body.isEmpty ? null : _statement(body);
@@ -1989,7 +1990,7 @@ class CodeGenerator extends GeneralizingAstVisitor
19891990
gen = js.call('#.bind(this)', gen);
19901991
}
19911992

1992-
var T = _emitTypeName(returnType);
1993+
var T = _emitType(returnType);
19931994
return js.call('dart.#(#)', [
19941995
kind,
19951996
[gen, T]..addAll(visitFormalParameterList(parameters, destructure: false))
@@ -2052,7 +2053,7 @@ class CodeGenerator extends GeneralizingAstVisitor
20522053

20532054
// type literal
20542055
if (element is TypeDefiningElement) {
2055-
var typeName = _emitTypeName(fillDynamicTypeArgs(element.type));
2056+
var typeName = _emitType(fillDynamicTypeArgs(element.type));
20562057

20572058
// If the type is a type literal expression in Dart code, wrap the raw
20582059
// runtime type in a "Type" instance.
@@ -2081,7 +2082,7 @@ class CodeGenerator extends GeneralizingAstVisitor
20812082
// library prefix. We don't need those because static calls can't use
20822083
// the generic type.
20832084
if (isStatic) {
2084-
var dynType = _emitTypeName(fillDynamicTypeArgs(type));
2085+
var dynType = _emitType(fillDynamicTypeArgs(type));
20852086
return new JS.PropertyAccess(dynType, member);
20862087
}
20872088

@@ -2157,7 +2158,7 @@ class CodeGenerator extends GeneralizingAstVisitor
21572158
for (int i = 0; i < types.length; ++i) {
21582159
var metadata =
21592160
parameters != null ? _parameterMetadata(parameters[i]) : [];
2160-
var typeName = _emitTypeName(types[i]);
2161+
var typeName = _emitType(types[i]);
21612162
var value = typeName;
21622163
// TODO(vsm): Make this optional per #268.
21632164
if (metadata.isNotEmpty) {
@@ -2173,7 +2174,7 @@ class CodeGenerator extends GeneralizingAstVisitor
21732174
var properties = <JS.Property>[];
21742175
types.forEach((name, type) {
21752176
var key = _propertyName(name);
2176-
var value = _emitTypeName(type);
2177+
var value = _emitType(type);
21772178
properties.add(new JS.Property(key, value));
21782179
});
21792180
return new JS.ObjectInitializer(properties);
@@ -2186,7 +2187,7 @@ class CodeGenerator extends GeneralizingAstVisitor
21862187
var parameterTypes = type.normalParameterTypes;
21872188
var optionalTypes = type.optionalParameterTypes;
21882189
var namedTypes = type.namedParameterTypes;
2189-
var rt = _emitTypeName(type.returnType);
2190+
var rt = _emitType(type.returnType);
21902191
var ra = _emitTypeNames(parameterTypes, parameters);
21912192

21922193
List<JS.Expression> typeParts;
@@ -2221,8 +2222,15 @@ class CodeGenerator extends GeneralizingAstVisitor
22212222
/// function type. Similarly if [lowerGeneric] is set, the `List$()` form
22222223
/// will be used instead of `List`. These flags are used when generating
22232224
/// the definitions for typedefs and generic types, respectively.
2224-
JS.Expression _emitTypeName(DartType type,
2225-
{bool lowerTypedef: false, bool lowerGeneric: false}) {
2225+
///
2226+
/// If [subClass] is set, then we are setting the base class for the given
2227+
/// class and should emit the given [className], which will already be
2228+
/// defined.
2229+
JS.Expression _emitType(DartType type,
2230+
{bool lowerTypedef: false,
2231+
bool lowerGeneric: false,
2232+
ClassElement subClass,
2233+
JS.Expression className}) {
22262234
// The void and dynamic types are not defined in core.
22272235
if (type.isVoid) {
22282236
return js.call('dart.void');
@@ -2252,11 +2260,16 @@ class CodeGenerator extends GeneralizingAstVisitor
22522260
return new JS.Identifier(name);
22532261
}
22542262

2263+
if (type == subClass?.type) {
2264+
return className;
2265+
}
2266+
22552267
if (type is ParameterizedType) {
22562268
var args = type.typeArguments;
22572269
Iterable jsArgs = null;
22582270
if (args.any((a) => !a.isDynamic)) {
2259-
jsArgs = args.map(_emitTypeName);
2271+
jsArgs = args.map(
2272+
(x) => _emitType(x, subClass: subClass, className: className));
22602273
} else if (lowerGeneric) {
22612274
jsArgs = [];
22622275
}
@@ -2537,7 +2550,7 @@ class CodeGenerator extends GeneralizingAstVisitor
25372550
f is FunctionType &&
25382551
f.typeFormals.isEmpty) {
25392552
return _recoverTypeArguments(g, f)
2540-
.map(_emitTypeName)
2553+
.map(_emitType)
25412554
.toList(growable: false);
25422555
} else if (typeArgs != null) {
25432556
// Dynamic calls may have type arguments, even though the function types
@@ -2979,7 +2992,7 @@ class CodeGenerator extends GeneralizingAstVisitor
29792992

29802993
JS.Expression _emitConstructorName(
29812994
ConstructorElement element, DartType type, SimpleIdentifier name) {
2982-
var typeName = _emitTypeName(type);
2995+
var typeName = _emitType(type);
29832996
if (name != null || element.isFactory) {
29842997
var namedCtor = _constructorName(element);
29852998
return new JS.PropertyAccess(typeName, namedCtor);
@@ -3005,7 +3018,7 @@ class CodeGenerator extends GeneralizingAstVisitor
30053018
if (element == null) {
30063019
// TODO(jmesserly): this only happens if we had a static error.
30073020
// Should we generate a throw instead?
3008-
ctor = _emitTypeName(type);
3021+
ctor = _emitType(type);
30093022
if (name != null) {
30103023
ctor = new JS.PropertyAccess(ctor, _propertyName(name.name));
30113024
}
@@ -3931,7 +3944,7 @@ class CodeGenerator extends GeneralizingAstVisitor
39313944
return new JS.If(
39323945
js.call('dart.is(#, #)', [
39333946
_visit(_catchParameter),
3934-
_emitTypeName(clause.exceptionType.type),
3947+
_emitType(clause.exceptionType.type),
39353948
]),
39363949
then,
39373950
otherwise);
@@ -4021,7 +4034,7 @@ class CodeGenerator extends GeneralizingAstVisitor
40214034
// TODO(vsm): When we canonicalize, we need to treat private symbols
40224035
// correctly.
40234036
var name = js.string(node.components.join('.'), "'");
4024-
return js.call('#.new(#)', [_emitTypeName(types.symbolType), name]);
4037+
return js.call('#.new(#)', [_emitType(types.symbolType), name]);
40254038
}
40264039
return _emitConst(emitSymbol);
40274040
}
@@ -4039,7 +4052,7 @@ class CodeGenerator extends GeneralizingAstVisitor
40394052
if (!elementType.isDynamic) {
40404053
// dart.list helper internally depends on _interceptors.JSArray.
40414054
_loader.declareBeforeUse(_jsArray);
4042-
list = js.call('dart.list(#, #)', [list, _emitTypeName(elementType)]);
4055+
list = js.call('dart.list(#, #)', [list, _emitType(elementType)]);
40434056
}
40444057
return list;
40454058
}
@@ -4075,7 +4088,7 @@ class CodeGenerator extends GeneralizingAstVisitor
40754088
}
40764089
var types = <JS.Expression>[];
40774090
if (typeArgs != null) {
4078-
types.addAll(typeArgs.arguments.map((e) => _emitTypeName(e.type)));
4091+
types.addAll(typeArgs.arguments.map((e) => _emitType(e.type)));
40794092
}
40804093
return js.call('dart.map(#, #)', [mapArguments, types]);
40814094
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import "package:expect/expect.dart";
6+
7+
class Bar<T> {
8+
}
9+
10+
class Foo<T> extends Bar<Foo<T>> {
11+
}
12+
13+
void main() {
14+
print(new Foo<int>());
15+
}

0 commit comments

Comments
 (0)