Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(688)

Side by Side Diff: lib/src/codegen/js_codegen.dart

Issue 1117793002: add checks needed for covariant generics, and List<E> (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library dev_compiler.src.codegen.js_codegen; 5 library dev_compiler.src.codegen.js_codegen;
6 6
7 import 'dart:collection' show HashSet, HashMap; 7 import 'dart:collection' show HashSet, HashMap;
8 8
9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; 10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator;
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after
325 if (member is ConstructorDeclaration) { 325 if (member is ConstructorDeclaration) {
326 ctors.add(member); 326 ctors.add(member);
327 } else if (member is FieldDeclaration) { 327 } else if (member is FieldDeclaration) {
328 (member.isStatic ? staticFields : fields).add(member); 328 (member.isStatic ? staticFields : fields).add(member);
329 } 329 }
330 } 330 }
331 331
332 var classExpr = new JS.ClassExpression(new JS.Identifier(type.name), 332 var classExpr = new JS.ClassExpression(new JS.Identifier(type.name),
333 _classHeritage(node), _emitClassMethods(node, ctors, fields)); 333 _classHeritage(node), _emitClassMethods(node, ctors, fields));
334 334
335 var body = 335 String jsPeerName;
336 _finishClassMembers(classElem, classExpr, ctors, fields, staticFields); 336 var jsPeer = getAnnotationValue(node, _isJsPeerInterface);
337 if (jsPeer != null) {
338 jsPeerName = getConstantField(jsPeer, 'name', types.stringType);
339 }
340
341 var body = _finishClassMembers(
342 classElem, classExpr, ctors, fields, staticFields, jsPeerName);
337 343
338 var result = _finishClassDef(type, body); 344 var result = _finishClassDef(type, body);
339 345
340 var jsPeer = getAnnotationValue(node, _isJsPeerInterface); 346 if (jsPeerName != null) {
341 if (jsPeer != null) { 347 // This class isn't allowed to be lazy, because we need to set up
342 var jsPeerName = getConstantField(jsPeer, 'name', types.stringType); 348 // the native JS type eagerly at this point.
343 if (jsPeerName != null) { 349 // If we wanted to support laziness, we could defer the hookup until
344 // This class isn't allowed to be lazy, because we need to set up 350 // the end of the Dart library cycle load.
345 // the native JS type eagerly at this point. 351 assert(!_lazyClass(type));
346 // If we wanted to support laziness, we could defer the hookup until
347 // the end of the Dart library cycle load.
348 assert(!_lazyClass(type));
349 352
350 // TODO(jmesserly): this copies the dynamic members. 353 // TODO(jmesserly): this copies the dynamic members.
351 // Probably fine for objects coming from JS, but not if we actually 354 // Probably fine for objects coming from JS, but not if we actually
352 // want to support construction of instances with generic types other 355 // want to support construction of instances with generic types other
353 // than dynamic. See issue #154 for Array and List<E> related bug. 356 // than dynamic. See issue #154 for Array and List<E> related bug.
354 var copyMembers = js.statement( 357 var copyMembers = js.statement(
355 'dart.registerExtension(dart.global.#, #);', [ 358 'dart.registerExtension(dart.global.#, #);', [
356 _propertyName(jsPeerName), 359 _propertyName(jsPeerName),
357 classElem.name 360 classElem.name
358 ]); 361 ]);
359 return _statement([result, copyMembers]); 362 return _statement([result, copyMembers]);
360 }
361 } 363 }
362 return result; 364 return result;
363 } 365 }
364 366
365 @override 367 @override
366 JS.Statement visitEnumDeclaration(EnumDeclaration node) => 368 JS.Statement visitEnumDeclaration(EnumDeclaration node) =>
367 _unimplementedCall("Unimplemented enum: $node").toStatement(); 369 _unimplementedCall("Unimplemented enum: $node").toStatement();
368 370
369 /// Given a class element and body, complete the class declaration. 371 /// Given a class element and body, complete the class declaration.
370 /// This handles generic type parameters, laziness (in library-cycle cases), 372 /// This handles generic type parameters, laziness (in library-cycle cases),
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after
595 jsMethods.add(new JS.Method(js.call('$_SYMBOL.iterator'), body)); 597 jsMethods.add(new JS.Method(js.call('$_SYMBOL.iterator'), body));
596 } 598 }
597 return jsMethods.where((m) => m != null).toList(growable: false); 599 return jsMethods.where((m) => m != null).toList(growable: false);
598 } 600 }
599 601
600 /// Emit class members that need to come after the class declaration, such 602 /// Emit class members that need to come after the class declaration, such
601 /// as static fields. See [_emitClassMethods] for things that are emitted 603 /// as static fields. See [_emitClassMethods] for things that are emitted
602 /// inside the ES6 `class { ... }` node. 604 /// inside the ES6 `class { ... }` node.
603 JS.Statement _finishClassMembers(ClassElement classElem, 605 JS.Statement _finishClassMembers(ClassElement classElem,
604 JS.ClassExpression cls, List<ConstructorDeclaration> ctors, 606 JS.ClassExpression cls, List<ConstructorDeclaration> ctors,
605 List<FieldDeclaration> fields, List<FieldDeclaration> staticFields) { 607 List<FieldDeclaration> fields, List<FieldDeclaration> staticFields,
608 String jsPeerName) {
606 var name = classElem.name; 609 var name = classElem.name;
607 var body = <JS.Statement>[]; 610 var body = <JS.Statement>[];
608 body.add(new JS.ClassDeclaration(cls)); 611 body.add(new JS.ClassDeclaration(cls));
609 612
613 // TODO(jmesserly): we should really just extend native Array.
614 if (jsPeerName != null && classElem.typeParameters.isNotEmpty) {
615 body.add(js.statement('dart.setBaseClass(#, dart.global.#);', [
616 classElem.name,
617 _propertyName(jsPeerName)
618 ]));
619 }
620
610 // Interfaces 621 // Interfaces
611 if (classElem.interfaces.isNotEmpty) { 622 if (classElem.interfaces.isNotEmpty) {
612 body.add(js.statement('#[dart.implements] = () => #;', [ 623 body.add(js.statement('#[dart.implements] = () => #;', [
613 name, 624 name,
614 new JS.ArrayInitializer( 625 new JS.ArrayInitializer(
615 classElem.interfaces.map(_emitTypeName).toList()) 626 classElem.interfaces.map(_emitTypeName).toList())
616 ])); 627 ]));
617 } 628 }
618 629
619 // Named constructors 630 // Named constructors
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after
895 // could handle argument initializers more consistently in a separate 906 // could handle argument initializers more consistently in a separate
896 // lowering pass. 907 // lowering pass.
897 if (node is MethodDeclaration) return node.parameters; 908 if (node is MethodDeclaration) return node.parameters;
898 if (node is FunctionDeclaration) node = node.functionExpression; 909 if (node is FunctionDeclaration) node = node.functionExpression;
899 if (node is FunctionExpression) return node.parameters; 910 if (node is FunctionExpression) return node.parameters;
900 return null; 911 return null;
901 } 912 }
902 913
903 bool _hasArgumentInitializers(FormalParameterList parameters) { 914 bool _hasArgumentInitializers(FormalParameterList parameters) {
904 if (parameters == null) return false; 915 if (parameters == null) return false;
905 return parameters.parameters.any((p) => p.kind != ParameterKind.REQUIRED); 916 return parameters.parameters.any((p) => p.kind != ParameterKind.REQUIRED ||
917 p.element.type is TypeParameterType);
906 } 918 }
907 919
920 /// Emits argument initializers, which handles optional/named args, as well
921 /// as generic type checks needed due to our covariance.
908 JS.Statement _emitArgumentInitializers(FormalParameterList parameters) { 922 JS.Statement _emitArgumentInitializers(FormalParameterList parameters) {
909 if (parameters == null || !_hasArgumentInitializers(parameters)) { 923 if (parameters == null || !_hasArgumentInitializers(parameters)) {
910 return null; 924 return null;
911 } 925 }
912 926
913 var body = []; 927 var body = [];
914 for (var param in parameters.parameters) { 928 for (var param in parameters.parameters) {
915 var jsParam = _visit(param.identifier); 929 var jsParam = _visit(param.identifier);
916 930
917 if (param.kind == ParameterKind.NAMED) { 931 if (param.kind == ParameterKind.NAMED) {
918 // Parameters will be passed using their real names, not the (possibly 932 // Parameters will be passed using their real names, not the (possibly
919 // renamed) local variable. 933 // renamed) local variable.
920 var paramName = js.string(param.identifier.name, "'"); 934 var paramName = js.string(param.identifier.name, "'");
921 body.add(js.statement('let # = # && # in # ? #.# : #;', [ 935 body.add(js.statement('let # = # && # in # ? #.# : #;', [
922 jsParam, 936 jsParam,
923 _namedArgTemp, 937 _namedArgTemp,
924 paramName, 938 paramName,
925 _namedArgTemp, 939 _namedArgTemp,
926 _namedArgTemp, 940 _namedArgTemp,
927 paramName, 941 paramName,
928 _defaultParamValue(param), 942 _defaultParamValue(param),
929 ])); 943 ]));
930 } else if (param.kind == ParameterKind.POSITIONAL) { 944 } else if (param.kind == ParameterKind.POSITIONAL) {
931 body.add(js.statement('if (# === void 0) # = #;', [ 945 body.add(js.statement('if (# === void 0) # = #;', [
932 jsParam, 946 jsParam,
933 jsParam, 947 jsParam,
934 _defaultParamValue(param) 948 _defaultParamValue(param)
935 ])); 949 ]));
936 } 950 }
951
952 // TODO(jmesserly): we could merge this with the named/optional code.
953 var paramType = param.element.type;
954 if (_hasTypeParameter(paramType)) {
955 body.add(js.statement(
956 '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
957 }
937 } 958 }
938 return _statement(body); 959 return _statement(body);
939 } 960 }
940 961
962 bool _hasTypeParameter(DartType t) => t is TypeParameterType ||
963 t is ParameterizedType && t.typeArguments.any(_hasTypeParameter);
964
941 JS.Expression _defaultParamValue(FormalParameter param) { 965 JS.Expression _defaultParamValue(FormalParameter param) {
942 if (param is DefaultFormalParameter && param.defaultValue != null) { 966 if (param is DefaultFormalParameter && param.defaultValue != null) {
943 return _visit(param.defaultValue); 967 return _visit(param.defaultValue);
944 } else { 968 } else {
945 return new JS.LiteralNull(); 969 return new JS.LiteralNull();
946 } 970 }
947 } 971 }
948 972
949 JS.Method _emitMethodDeclaration(DartType type, MethodDeclaration node) { 973 JS.Method _emitMethodDeclaration(DartType type, MethodDeclaration node) {
950 if (node.isAbstract || _externalOrNative(node)) { 974 if (node.isAbstract || _externalOrNative(node)) {
(...skipping 599 matching lines...) Expand 10 before | Expand all | Expand 10 after
1550 if (expr is Literal && expr is! NullLiteral) return true; 1574 if (expr is Literal && expr is! NullLiteral) return true;
1551 if (expr is IsExpression) return true; 1575 if (expr is IsExpression) return true;
1552 if (expr is ThisExpression) return true; 1576 if (expr is ThisExpression) return true;
1553 if (expr is SuperExpression) return true; 1577 if (expr is SuperExpression) return true;
1554 if (expr is ParenthesizedExpression) { 1578 if (expr is ParenthesizedExpression) {
1555 return _isNonNullableExpression(expr.expression); 1579 return _isNonNullableExpression(expr.expression);
1556 } 1580 }
1557 if (expr is Conversion) { 1581 if (expr is Conversion) {
1558 return _isNonNullableExpression(expr.expression); 1582 return _isNonNullableExpression(expr.expression);
1559 } 1583 }
1584 if (expr is SimpleIdentifier) {
1585 // Type literals are not null.
1586 Element e = expr.staticElement;
1587 if (e is ClassElement || e is FunctionTypeAliasElement) return true;
1588 }
1560 DartType type = null; 1589 DartType type = null;
1561 if (expr is BinaryExpression) { 1590 if (expr is BinaryExpression) {
1562 type = getStaticType(expr.leftOperand); 1591 type = getStaticType(expr.leftOperand);
1563 } else if (expr is PrefixExpression) { 1592 } else if (expr is PrefixExpression) {
1564 type = getStaticType(expr.operand); 1593 type = getStaticType(expr.operand);
1565 } else if (expr is PostfixExpression) { 1594 } else if (expr is PostfixExpression) {
1566 type = getStaticType(expr.operand); 1595 type = getStaticType(expr.operand);
1567 } 1596 }
1568 if (type != null && _isJSBuiltinType(type)) { 1597 if (type != null && _isJSBuiltinType(type)) {
1569 return true; 1598 return true;
(...skipping 950 matching lines...) Expand 10 before | Expand all | Expand 10 after
2520 // TODO(jmesserly): validate the library. See issue #135. 2549 // TODO(jmesserly): validate the library. See issue #135.
2521 bool _isJsNameAnnotation(DartObjectImpl value) => value.type.name == 'JsName'; 2550 bool _isJsNameAnnotation(DartObjectImpl value) => value.type.name == 'JsName';
2522 2551
2523 bool _isJsPeerInterface(DartObjectImpl value) => 2552 bool _isJsPeerInterface(DartObjectImpl value) =>
2524 value.type.name == 'JsPeerInterface'; 2553 value.type.name == 'JsPeerInterface';
2525 2554
2526 // TODO(jacobr): we would like to do something like the following 2555 // TODO(jacobr): we would like to do something like the following
2527 // but we don't have summary support yet. 2556 // but we don't have summary support yet.
2528 // bool _supportJsExtensionMethod(AnnotatedNode node) => 2557 // bool _supportJsExtensionMethod(AnnotatedNode node) =>
2529 // _getAnnotation(node, "SupportJsExtensionMethod") != null; 2558 // _getAnnotation(node, "SupportJsExtensionMethod") != null;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698