OLD | NEW |
---|---|
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 import 'dart:collection' show HashMap, HashSet; | 5 import 'dart:collection' show HashMap, HashSet; |
6 import 'dart:math' show min, max; | 6 import 'dart:math' show min, max; |
7 | 7 |
8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
9 import 'package:analyzer/dart/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; | 10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; |
(...skipping 428 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
439 if (export is ClassElement && export.typeParameters.isNotEmpty) { | 439 if (export is ClassElement && export.typeParameters.isNotEmpty) { |
440 // Export the generic name as well. | 440 // Export the generic name as well. |
441 // TODO(jmesserly): revisit generic classes | 441 // TODO(jmesserly): revisit generic classes |
442 emitExport(export, suffix: r'$'); | 442 emitExport(export, suffix: r'$'); |
443 } | 443 } |
444 emitExport(export); | 444 emitExport(export); |
445 } | 445 } |
446 } | 446 } |
447 | 447 |
448 @override | 448 @override |
449 visitAsExpression(AsExpression node) { | 449 visitAsExpression(AsExpression node) => |
450 var from = getStaticType(node.expression); | 450 _emitCast(node.expression, to: node.type.type); |
451 var to = node.type.type; | |
452 | 451 |
453 var fromExpr = _visit(node.expression); | 452 /// Emits a cast and/or a null check (i.e. a cast to a non-null type). |
453 JS.Expression _emitCast(Expression fromExpr, | |
454 {DartType to, bool checkNull: false}) { | |
455 | |
456 var jsFrom = _visit(fromExpr); | |
457 var from = getStaticType(fromExpr); | |
458 | |
459 JS.Expression maybeCheckNull(JS.Expression jsExpr) { | |
Jennifer Messerly
2016/05/10 23:42:12
aside: it might be a better architecture to fuse t
| |
460 if (checkNull && isNullable(fromExpr)) { | |
461 return js.call('dart.notNull(#)', jsExpr); | |
462 } | |
463 return jsExpr; | |
464 } | |
454 | 465 |
455 // Skip the cast if it's not needed. | 466 // Skip the cast if it's not needed. |
456 if (rules.isSubtypeOf(from, to)) return fromExpr; | 467 if (to == null || rules.isSubtypeOf(from, to)) { |
468 return maybeCheckNull(jsFrom); | |
469 } | |
457 | 470 |
458 // All Dart number types map to a JS double. | 471 // All Dart number types map to a JS double. |
459 if (_isNumberInJS(from) && _isNumberInJS(to)) { | 472 if (_isNumberInJS(from) && _isNumberInJS(to)) { |
460 // Make sure to check when converting to int. | 473 // Make sure to check when converting to int. |
461 if (from != types.intType && to == types.intType) { | 474 if (from != types.intType && to == types.intType) { |
462 return js.call('dart.asInt(#)', [fromExpr]); | 475 // TODO(jmesserly): fuse this with notNull check. |
476 return maybeCheckNull(js.call('dart.asInt(#)', [jsFrom])); | |
463 } | 477 } |
464 | 478 |
465 // A no-op in JavaScript. | 479 // A no-op in JavaScript. |
466 return fromExpr; | 480 return maybeCheckNull(jsFrom); |
467 } | 481 } |
468 | 482 |
469 return js.call('dart.as(#, #)', [fromExpr, _emitType(to)]); | 483 if (to == types.boolType && checkNull) { |
484 return js.call('dart.test(#)', _visit(fromExpr)); | |
485 } | |
486 | |
487 if (checkNull && isNullable(fromExpr)) { | |
488 return js.call('dart.asNotNull(#, #)', [jsFrom, _emitType(to)]); | |
489 } else { | |
490 return js.call('dart.as(#, #)', [jsFrom, _emitType(to)]); | |
491 } | |
470 } | 492 } |
471 | 493 |
472 @override | 494 @override |
473 visitIsExpression(IsExpression node) { | 495 visitIsExpression(IsExpression node) { |
474 // Generate `is` as `dart.is` or `typeof` depending on the RHS type. | 496 // Generate `is` as `dart.is` or `typeof` depending on the RHS type. |
475 JS.Expression result; | 497 JS.Expression result; |
476 var type = node.type.type; | 498 var type = node.type.type; |
477 var lhs = _visit(node.expression); | 499 var lhs = _visit(node.expression); |
478 var typeofName = _jsTypeofName(type); | 500 var typeofName = _jsTypeofName(type); |
479 if (typeofName != null) { | 501 if (typeofName != null) { |
(...skipping 2572 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3052 bool typeIsPrimitiveInJS(DartType t) => | 3074 bool typeIsPrimitiveInJS(DartType t) => |
3053 _isNumberInJS(t) || t == types.boolType; | 3075 _isNumberInJS(t) || t == types.boolType; |
3054 | 3076 |
3055 bool binaryOperationIsPrimitive(DartType leftT, DartType rightT) => | 3077 bool binaryOperationIsPrimitive(DartType leftT, DartType rightT) => |
3056 typeIsPrimitiveInJS(leftT) && typeIsPrimitiveInJS(rightT); | 3078 typeIsPrimitiveInJS(leftT) && typeIsPrimitiveInJS(rightT); |
3057 | 3079 |
3058 bool unaryOperationIsPrimitive(DartType t) => typeIsPrimitiveInJS(t); | 3080 bool unaryOperationIsPrimitive(DartType t) => typeIsPrimitiveInJS(t); |
3059 | 3081 |
3060 JS.Expression notNull(Expression expr) { | 3082 JS.Expression notNull(Expression expr) { |
3061 if (expr == null) return null; | 3083 if (expr == null) return null; |
3062 var jsExpr = _visit(expr); | 3084 if (expr is AsExpression) { |
3063 if (!isNullable(expr)) return jsExpr; | 3085 return _emitCast(expr.expression, to: expr.type.type, checkNull: true); |
3064 return js.call('dart.notNull(#)', jsExpr); | 3086 } |
3087 return _emitCast(expr, checkNull: true); | |
3065 } | 3088 } |
3066 | 3089 |
3067 @override | 3090 @override |
3068 JS.Expression visitBinaryExpression(BinaryExpression node) { | 3091 JS.Expression visitBinaryExpression(BinaryExpression node) { |
3069 var op = node.operator; | 3092 var op = node.operator; |
3070 var left = node.leftOperand; | 3093 var left = node.leftOperand; |
3071 var right = node.rightOperand; | 3094 var right = node.rightOperand; |
3072 | 3095 |
3073 var leftType = getStaticType(left); | 3096 var leftType = getStaticType(left); |
3074 var rightType = getStaticType(right); | 3097 var rightType = getStaticType(right); |
(...skipping 1333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4408 } | 4431 } |
4409 | 4432 |
4410 bool isLibraryPrefix(Expression node) => | 4433 bool isLibraryPrefix(Expression node) => |
4411 node is SimpleIdentifier && node.staticElement is PrefixElement; | 4434 node is SimpleIdentifier && node.staticElement is PrefixElement; |
4412 | 4435 |
4413 LibraryElement _getLibrary(AnalysisContext c, String uri) => | 4436 LibraryElement _getLibrary(AnalysisContext c, String uri) => |
4414 c.computeLibraryElement(c.sourceFactory.forUri(uri)); | 4437 c.computeLibraryElement(c.sourceFactory.forUri(uri)); |
4415 | 4438 |
4416 bool _isDartRuntime(LibraryElement l) => | 4439 bool _isDartRuntime(LibraryElement l) => |
4417 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; | 4440 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; |
OLD | NEW |