Chromium Code Reviews| 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); |