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

Side by Side Diff: lib/src/compiler/code_generator.dart

Issue 1993023003: Better boolean conversion tests. (Closed) Base URL: https://github.com/dart-lang/dev_compiler@master
Patch Set: Created 4 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
« no previous file with comments | « lib/runtime/dart_sdk.js ('k') | tool/input_sdk/private/ddc_runtime/operations.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 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 438 matching lines...) Expand 10 before | Expand all | Expand 10 after
449 if (export is ClassElement && export.typeParameters.isNotEmpty) { 449 if (export is ClassElement && export.typeParameters.isNotEmpty) {
450 // Export the generic name as well. 450 // Export the generic name as well.
451 // TODO(jmesserly): revisit generic classes 451 // TODO(jmesserly): revisit generic classes
452 emitExport(export, suffix: r'$'); 452 emitExport(export, suffix: r'$');
453 } 453 }
454 emitExport(export); 454 emitExport(export);
455 } 455 }
456 } 456 }
457 457
458 @override 458 @override
459 visitAsExpression(AsExpression node) => 459 visitAsExpression(AsExpression node) {
460 _emitCast(node.expression, to: node.type.type); 460 Expression fromExpr = node.expression;
461 var from = getStaticType(fromExpr);
462 var to = node.type.type;
461 463
462 /// Emits a cast and/or a null check (i.e. a cast to a non-null type).
463 JS.Expression _emitCast(Expression fromExpr,
464 {DartType to, bool checkNull: false}) {
465 var jsFrom = _visit(fromExpr); 464 var jsFrom = _visit(fromExpr);
466 var from = getStaticType(fromExpr);
467
468 JS.Expression maybeCheckNull(JS.Expression jsExpr) {
469 if (checkNull && isNullable(fromExpr)) {
470 return js.call('dart.notNull(#)', jsExpr);
471 }
472 return jsExpr;
473 }
474 465
475 // Skip the cast if it's not needed. 466 // Skip the cast if it's not needed.
476 if (to == null || rules.isSubtypeOf(from, to)) { 467 if (rules.isSubtypeOf(from, to)) return jsFrom;
477 return maybeCheckNull(jsFrom);
478 }
479 468
480 // All Dart number types map to a JS double. 469 // All Dart number types map to a JS double.
481 if (_isNumberInJS(from) && _isNumberInJS(to)) { 470 if (_isNumberInJS(from) && _isNumberInJS(to)) {
482 // Make sure to check when converting to int. 471 // Make sure to check when converting to int.
483 if (from != types.intType && to == types.intType) { 472 if (from != types.intType && to == types.intType) {
484 // TODO(jmesserly): fuse this with notNull check. 473 return js.call('dart.asInt(#)', jsFrom);
Jennifer Messerly 2016/05/19 17:45:38 Why remove this TODO? We still want to be smarter
sra1 2016/05/19 18:57:56 I'll add it back.
485 return maybeCheckNull(js.call('dart.asInt(#)', [jsFrom]));
486 } 474 }
487 475
488 // A no-op in JavaScript. 476 // A no-op in JavaScript.
489 return maybeCheckNull(jsFrom); 477 return jsFrom;
490 } 478 }
491 479
492 if (to == types.boolType && checkNull) { 480 return js.call('dart.as(#, #)', [jsFrom, _emitType(to)]);
493 return js.call('dart.test(#)', _visit(fromExpr));
494 }
495
496 return maybeCheckNull(js.call('dart.as(#, #)', [jsFrom, _emitType(to)]));
497 } 481 }
498 482
499 @override 483 @override
500 visitIsExpression(IsExpression node) { 484 visitIsExpression(IsExpression node) {
501 // Generate `is` as `dart.is` or `typeof` depending on the RHS type. 485 // Generate `is` as `dart.is` or `typeof` depending on the RHS type.
502 JS.Expression result; 486 JS.Expression result;
503 var type = node.type.type; 487 var type = node.type.type;
504 var lhs = _visit(node.expression); 488 var lhs = _visit(node.expression);
505 var typeofName = _jsTypeofName(type); 489 var typeofName = _jsTypeofName(type);
506 if (typeofName != null) { 490 if (typeofName != null) {
(...skipping 2614 matching lines...) Expand 10 before | Expand all | Expand 10 after
3121 bool typeIsPrimitiveInJS(DartType t) => 3105 bool typeIsPrimitiveInJS(DartType t) =>
3122 _isNumberInJS(t) || t == types.boolType; 3106 _isNumberInJS(t) || t == types.boolType;
3123 3107
3124 bool binaryOperationIsPrimitive(DartType leftT, DartType rightT) => 3108 bool binaryOperationIsPrimitive(DartType leftT, DartType rightT) =>
3125 typeIsPrimitiveInJS(leftT) && typeIsPrimitiveInJS(rightT); 3109 typeIsPrimitiveInJS(leftT) && typeIsPrimitiveInJS(rightT);
3126 3110
3127 bool unaryOperationIsPrimitive(DartType t) => typeIsPrimitiveInJS(t); 3111 bool unaryOperationIsPrimitive(DartType t) => typeIsPrimitiveInJS(t);
3128 3112
3129 JS.Expression notNull(Expression expr) { 3113 JS.Expression notNull(Expression expr) {
3130 if (expr == null) return null; 3114 if (expr == null) return null;
3131 if (expr is AsExpression) { 3115 var jsExpr = _visit(expr);
3132 return _emitCast(expr.expression, to: expr.type.type, checkNull: true); 3116 if (!isNullable(expr)) return jsExpr;
3133 } 3117 return js.call('dart.notNull(#)', jsExpr);
3134 return _emitCast(expr, checkNull: true);
3135 } 3118 }
3136 3119
3137 @override 3120 @override
3138 JS.Expression visitBinaryExpression(BinaryExpression node) { 3121 JS.Expression visitBinaryExpression(BinaryExpression node) {
3139 var op = node.operator; 3122 var op = node.operator;
3140 var left = node.leftOperand; 3123 var left = node.leftOperand;
3141 var right = node.rightOperand; 3124 var right = node.rightOperand;
3142 3125
3143 var leftType = getStaticType(left); 3126 var leftType = getStaticType(left);
3144 var rightType = getStaticType(right); 3127 var rightType = getStaticType(right);
(...skipping 687 matching lines...) Expand 10 before | Expand all | Expand 10 after
3832 Expression _getTarget(node) { 3815 Expression _getTarget(node) {
3833 assert(node is IndexExpression || 3816 assert(node is IndexExpression ||
3834 node is PropertyAccess || 3817 node is PropertyAccess ||
3835 node is MethodInvocation); 3818 node is MethodInvocation);
3836 return node.isCascaded ? _cascadeTarget : node.target; 3819 return node.isCascaded ? _cascadeTarget : node.target;
3837 } 3820 }
3838 3821
3839 @override 3822 @override
3840 visitConditionalExpression(ConditionalExpression node) { 3823 visitConditionalExpression(ConditionalExpression node) {
3841 return js.call('# ? # : #', [ 3824 return js.call('# ? # : #', [
3842 notNull(node.condition), 3825 _visitTest(node.condition),
3843 _visit(node.thenExpression), 3826 _visit(node.thenExpression),
3844 _visit(node.elseExpression) 3827 _visit(node.elseExpression)
3845 ]); 3828 ]);
3846 } 3829 }
3847 3830
3848 @override 3831 @override
3849 visitThrowExpression(ThrowExpression node) { 3832 visitThrowExpression(ThrowExpression node) {
3850 var expr = _visit(node.expression); 3833 var expr = _visit(node.expression);
3851 if (node.parent is ExpressionStatement) { 3834 if (node.parent is ExpressionStatement) {
3852 return js.statement('dart.throw(#);', expr); 3835 return js.statement('dart.throw(#);', expr);
(...skipping 21 matching lines...) Expand all
3874 var result = _visit(stmt); 3857 var result = _visit(stmt);
3875 if (result is JS.ExpressionStatement && 3858 if (result is JS.ExpressionStatement &&
3876 result.expression is JS.VariableDeclarationList) { 3859 result.expression is JS.VariableDeclarationList) {
3877 return new JS.Block([result]); 3860 return new JS.Block([result]);
3878 } 3861 }
3879 return result; 3862 return result;
3880 } 3863 }
3881 3864
3882 @override 3865 @override
3883 JS.If visitIfStatement(IfStatement node) { 3866 JS.If visitIfStatement(IfStatement node) {
3884 return new JS.If(notNull(node.condition), _visitScope(node.thenStatement), 3867 return new JS.If(_visitTest(node.condition),
3885 _visitScope(node.elseStatement)); 3868 _visitScope(node.thenStatement), _visitScope(node.elseStatement));
3886 } 3869 }
3887 3870
3888 @override 3871 @override
3889 JS.For visitForStatement(ForStatement node) { 3872 JS.For visitForStatement(ForStatement node) {
3890 var init = _visit(node.initialization); 3873 var init = _visit(node.initialization);
3891 if (init == null) init = _visit(node.variables); 3874 if (init == null) init = _visit(node.variables);
3892 var update = _visitListToBinary(node.updaters, ','); 3875 var update = _visitListToBinary(node.updaters, ',');
3893 if (update != null) update = update.toVoidExpression(); 3876 if (update != null) update = update.toVoidExpression();
3894 return new JS.For( 3877 var condition = node.condition == null ? null : _visitTest(node.condition);
3895 init, notNull(node.condition), update, _visitScope(node.body)); 3878 return new JS.For(init, condition, update, _visitScope(node.body));
3896 } 3879 }
3897 3880
3898 @override 3881 @override
3899 JS.While visitWhileStatement(WhileStatement node) { 3882 JS.While visitWhileStatement(WhileStatement node) {
3900 return new JS.While(notNull(node.condition), _visitScope(node.body)); 3883 return new JS.While(_visitTest(node.condition), _visitScope(node.body));
3901 } 3884 }
3902 3885
3903 @override 3886 @override
3904 JS.Do visitDoStatement(DoStatement node) { 3887 JS.Do visitDoStatement(DoStatement node) {
3905 return new JS.Do(_visitScope(node.body), notNull(node.condition)); 3888 return new JS.Do(_visitScope(node.body), _visitTest(node.condition));
3906 } 3889 }
3907 3890
3908 @override 3891 @override
3909 JS.Statement visitForEachStatement(ForEachStatement node) { 3892 JS.Statement visitForEachStatement(ForEachStatement node) {
3910 if (node.awaitKeyword != null) { 3893 if (node.awaitKeyword != null) {
3911 return _emitAwaitFor(node); 3894 return _emitAwaitFor(node);
3912 } 3895 }
3913 3896
3914 var init = _visit(node.identifier); 3897 var init = _visit(node.identifier);
3915 if (init == null) { 3898 if (init == null) {
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after
4232 return result; 4215 return result;
4233 } 4216 }
4234 4217
4235 /// Visits a list of expressions, creating a comma expression if needed in JS. 4218 /// Visits a list of expressions, creating a comma expression if needed in JS.
4236 JS.Expression _visitListToBinary(List<Expression> nodes, String operator) { 4219 JS.Expression _visitListToBinary(List<Expression> nodes, String operator) {
4237 if (nodes == null || nodes.isEmpty) return null; 4220 if (nodes == null || nodes.isEmpty) return null;
4238 return new JS.Expression.binary( 4221 return new JS.Expression.binary(
4239 _visitList(nodes) as List<JS.Expression>, operator); 4222 _visitList(nodes) as List<JS.Expression>, operator);
4240 } 4223 }
4241 4224
4225 /// Generates an expression for a boolean conversion context (if, while, &&,
4226 /// etc.), where conversions and null checks are implemented via `dart.test`
4227 /// to give a more helpful message.
4228 // TODO(sra): When nullablility is available earlier, it would be cleaner to
4229 // build an input AST where the boolean conversion is a single AST node.
4230 JS.Expression _visitTest(Expression node) {
4231 JS.Expression finish(JS.Expression result) {
4232 return annotate(result, node);
4233 }
4234 if (node is PrefixExpression && node.operator.lexeme == '!') {
4235 return finish(js.call('!#', _visitTest(node.operand)));
4236 }
4237 if (node is BinaryExpression) {
4238 JS.Expression shortCircuit(String code) {
4239 return finish(js.call(code,
4240 [_visitTest(node.leftOperand), _visitTest(node.rightOperand)]));
4241 }
4242 var op = node.operator.type.lexeme;
4243 if (op == '&&') return shortCircuit('# && #');
4244 if (op == '||') return shortCircuit('# || #');
4245 }
4246 // Offset 0 from start of file is syntactically impossible for normal code.
4247 // TODO(sra): Find a better way to recognize reified coercion, since we
4248 // can't set the isSynthetic attribute.
Jennifer Messerly 2016/05/19 17:45:38 FYI -- we can send a patch to Analyzer if we need
sra1 2016/05/19 18:57:56 Acknowledged.
4249 if (node is AsExpression && node.asOperator.offset == 0) {
4250 assert(node.staticType == types.boolType);
4251 return js.call('dart.test(#)', _visit(node.expression));
4252 }
4253 JS.Expression result = _visit(node);
4254 if (isNullable(node)) result = js.call('dart.test(#)', result);
4255 return result;
4256 }
4257
4242 /// Like [_emitMemberName], but for declaration sites. 4258 /// Like [_emitMemberName], but for declaration sites.
4243 /// 4259 ///
4244 /// Unlike call sites, we always have an element available, so we can use it 4260 /// Unlike call sites, we always have an element available, so we can use it
4245 /// directly rather than computing the relevant options for [_emitMemberName]. 4261 /// directly rather than computing the relevant options for [_emitMemberName].
4246 JS.Expression _elementMemberName(ExecutableElement e, {bool useExtension}) { 4262 JS.Expression _elementMemberName(ExecutableElement e, {bool useExtension}) {
4247 String name; 4263 String name;
4248 if (e is PropertyAccessorElement) { 4264 if (e is PropertyAccessorElement) {
4249 name = e.variable.name; 4265 name = e.variable.name;
4250 } else { 4266 } else {
4251 name = e.name; 4267 name = e.name;
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after
4489 } 4505 }
4490 4506
4491 bool isLibraryPrefix(Expression node) => 4507 bool isLibraryPrefix(Expression node) =>
4492 node is SimpleIdentifier && node.staticElement is PrefixElement; 4508 node is SimpleIdentifier && node.staticElement is PrefixElement;
4493 4509
4494 LibraryElement _getLibrary(AnalysisContext c, String uri) => 4510 LibraryElement _getLibrary(AnalysisContext c, String uri) =>
4495 c.computeLibraryElement(c.sourceFactory.forUri(uri)); 4511 c.computeLibraryElement(c.sourceFactory.forUri(uri));
4496 4512
4497 bool _isDartRuntime(LibraryElement l) => 4513 bool _isDartRuntime(LibraryElement l) =>
4498 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; 4514 l.isInSdk && l.source.uri.toString() == 'dart:_runtime';
OLDNEW
« no previous file with comments | « lib/runtime/dart_sdk.js ('k') | tool/input_sdk/private/ddc_runtime/operations.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698