Index: lib/src/codegen/js_codegen.dart |
diff --git a/lib/src/codegen/js_codegen.dart b/lib/src/codegen/js_codegen.dart |
index c533eb4e0fa548cd439354c802d7383e160b3a68..f11569eb29c27dade60b2acc5ed7fb38f10cc129 100644 |
--- a/lib/src/codegen/js_codegen.dart |
+++ b/lib/src/codegen/js_codegen.dart |
@@ -332,32 +332,34 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { |
var classExpr = new JS.ClassExpression(new JS.Identifier(type.name), |
_classHeritage(node), _emitClassMethods(node, ctors, fields)); |
- var body = |
- _finishClassMembers(classElem, classExpr, ctors, fields, staticFields); |
+ String jsPeerName; |
+ var jsPeer = getAnnotationValue(node, _isJsPeerInterface); |
+ if (jsPeer != null) { |
+ jsPeerName = getConstantField(jsPeer, 'name', types.stringType); |
+ } |
+ |
+ var body = _finishClassMembers( |
+ classElem, classExpr, ctors, fields, staticFields, jsPeerName); |
var result = _finishClassDef(type, body); |
- var jsPeer = getAnnotationValue(node, _isJsPeerInterface); |
- if (jsPeer != null) { |
- var jsPeerName = getConstantField(jsPeer, 'name', types.stringType); |
- if (jsPeerName != null) { |
- // This class isn't allowed to be lazy, because we need to set up |
- // the native JS type eagerly at this point. |
- // If we wanted to support laziness, we could defer the hookup until |
- // the end of the Dart library cycle load. |
- assert(!_lazyClass(type)); |
- |
- // TODO(jmesserly): this copies the dynamic members. |
- // Probably fine for objects coming from JS, but not if we actually |
- // want to support construction of instances with generic types other |
- // than dynamic. See issue #154 for Array and List<E> related bug. |
- var copyMembers = js.statement( |
- 'dart.registerExtension(dart.global.#, #);', [ |
- _propertyName(jsPeerName), |
- classElem.name |
- ]); |
- return _statement([result, copyMembers]); |
- } |
+ if (jsPeerName != null) { |
+ // This class isn't allowed to be lazy, because we need to set up |
+ // the native JS type eagerly at this point. |
+ // If we wanted to support laziness, we could defer the hookup until |
+ // the end of the Dart library cycle load. |
+ assert(!_lazyClass(type)); |
+ |
+ // TODO(jmesserly): this copies the dynamic members. |
+ // Probably fine for objects coming from JS, but not if we actually |
+ // want to support construction of instances with generic types other |
+ // than dynamic. See issue #154 for Array and List<E> related bug. |
+ var copyMembers = js.statement( |
+ 'dart.registerExtension(dart.global.#, #);', [ |
+ _propertyName(jsPeerName), |
+ classElem.name |
+ ]); |
+ return _statement([result, copyMembers]); |
} |
return result; |
} |
@@ -602,11 +604,20 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { |
/// inside the ES6 `class { ... }` node. |
JS.Statement _finishClassMembers(ClassElement classElem, |
JS.ClassExpression cls, List<ConstructorDeclaration> ctors, |
- List<FieldDeclaration> fields, List<FieldDeclaration> staticFields) { |
+ List<FieldDeclaration> fields, List<FieldDeclaration> staticFields, |
+ String jsPeerName) { |
var name = classElem.name; |
var body = <JS.Statement>[]; |
body.add(new JS.ClassDeclaration(cls)); |
+ // TODO(jmesserly): we should really just extend native Array. |
+ if (jsPeerName != null && classElem.typeParameters.isNotEmpty) { |
+ body.add(js.statement('dart.setBaseClass(#, dart.global.#);', [ |
+ classElem.name, |
+ _propertyName(jsPeerName) |
+ ])); |
+ } |
+ |
// Interfaces |
if (classElem.interfaces.isNotEmpty) { |
body.add(js.statement('#[dart.implements] = () => #;', [ |
@@ -902,9 +913,12 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { |
bool _hasArgumentInitializers(FormalParameterList parameters) { |
if (parameters == null) return false; |
- return parameters.parameters.any((p) => p.kind != ParameterKind.REQUIRED); |
+ return parameters.parameters.any((p) => p.kind != ParameterKind.REQUIRED || |
+ p.element.type is TypeParameterType); |
} |
+ /// Emits argument initializers, which handles optional/named args, as well |
+ /// as generic type checks needed due to our covariance. |
JS.Statement _emitArgumentInitializers(FormalParameterList parameters) { |
if (parameters == null || !_hasArgumentInitializers(parameters)) { |
return null; |
@@ -934,10 +948,20 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { |
_defaultParamValue(param) |
])); |
} |
+ |
+ // TODO(jmesserly): we could merge this with the named/optional code. |
+ var paramType = param.element.type; |
+ if (_hasTypeParameter(paramType)) { |
+ body.add(js.statement( |
+ 'dart.as(#, #);', [jsParam, _emitTypeName(paramType)])); |
vsm
2015/04/30 14:00:51
At some point, it'd be cleaner to hoist this befor
Jennifer Messerly
2015/05/01 20:43:04
agreed, discussed offline, filed https://github.co
|
+ } |
} |
return _statement(body); |
} |
+ bool _hasTypeParameter(DartType t) => t is TypeParameterType || |
+ t is ParameterizedType && t.typeArguments.any(_hasTypeParameter); |
+ |
JS.Expression _defaultParamValue(FormalParameter param) { |
if (param is DefaultFormalParameter && param.defaultValue != null) { |
return _visit(param.defaultValue); |
@@ -1557,6 +1581,11 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { |
if (expr is Conversion) { |
return _isNonNullableExpression(expr.expression); |
} |
+ if (expr is SimpleIdentifier) { |
+ // Type literals are not null. |
+ Element e = expr.staticElement; |
+ if (e is ClassElement || e is FunctionTypeAliasElement) return true; |
+ } |
DartType type = null; |
if (expr is BinaryExpression) { |
type = getStaticType(expr.leftOperand); |