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

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

Issue 977153002: Fix increment on nullable (Closed) Base URL: https://github.com/dart-lang/dev_compiler.git@master
Patch Set: Remove assignments Created 5 years, 9 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 | « no previous file | test/codegen/expect/BenchmarkBase.js » ('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 library dev_compiler.src.codegen.js_codegen; 5 library dev_compiler.src.codegen.js_codegen;
6 6
7 import 'dart:collection' show HashSet; 7 import 'dart:collection' show HashSet;
8 import 'dart:io' show Directory, File; 8 import 'dart:io' show Directory, File;
9 9
10 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; 10 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
(...skipping 1047 matching lines...) Expand 10 before | Expand all | Expand 10 after
1058 1058
1059 bool typeIsNonNullablePrimitiveInJS(DartType t) => 1059 bool typeIsNonNullablePrimitiveInJS(DartType t) =>
1060 typeIsPrimitiveInJS(t) && rules.isNonNullableType(t); 1060 typeIsPrimitiveInJS(t) && rules.isNonNullableType(t);
1061 1061
1062 bool binaryOperationIsPrimitive(DartType leftT, DartType rightT) => 1062 bool binaryOperationIsPrimitive(DartType leftT, DartType rightT) =>
1063 typeIsPrimitiveInJS(leftT) && typeIsPrimitiveInJS(rightT); 1063 typeIsPrimitiveInJS(leftT) && typeIsPrimitiveInJS(rightT);
1064 1064
1065 bool unaryOperationIsPrimitive(DartType t) => typeIsPrimitiveInJS(t); 1065 bool unaryOperationIsPrimitive(DartType t) => typeIsPrimitiveInJS(t);
1066 1066
1067 bool _isNonNullableExpression(Expression expr) { 1067 bool _isNonNullableExpression(Expression expr) {
1068 // If the type is non-nullable, no further checking needed.
1069 if (rules.isNonNullableType(rules.getStaticType(expr))) return true;
1070
1068 // TODO(vsm): Revisit whether we really need this when we get 1071 // TODO(vsm): Revisit whether we really need this when we get
1069 // better non-nullability in the type system. 1072 // better non-nullability in the type system.
1070 1073
1071 if (expr is Literal && expr is! NullLiteral) { 1074 if (expr is Literal && expr is! NullLiteral) {
1072 return true; 1075 return true;
1073 } 1076 }
1074 if (expr is ParenthesizedExpression) { 1077 if (expr is ParenthesizedExpression) {
1075 return _isNonNullableExpression(expr.expression); 1078 return _isNonNullableExpression(expr.expression);
1076 } 1079 }
1077 DartType type = null; 1080 DartType type = null;
(...skipping 27 matching lines...) Expand all
1105 if (!types.split('|').contains('Null')) { 1108 if (!types.split('|').contains('Null')) {
1106 return true; 1109 return true;
1107 } 1110 }
1108 } 1111 }
1109 } 1112 }
1110 } 1113 }
1111 return false; 1114 return false;
1112 } 1115 }
1113 1116
1114 JS.Expression notNull(Expression expr) { 1117 JS.Expression notNull(Expression expr) {
1115 var type = rules.getStaticType(expr); 1118 if (_isNonNullableExpression(expr)) {
1116 if (rules.isNonNullableType(type) || _isNonNullableExpression(expr)) {
1117 return _visit(expr); 1119 return _visit(expr);
1118 } else { 1120 } else {
1119 return js.call('dart.notNull(#)', _visit(expr)); 1121 return js.call('dart.notNull(#)', _visit(expr));
1120 } 1122 }
1121 } 1123 }
1122 1124
1123 @override 1125 @override
1124 JS.Expression visitBinaryExpression(BinaryExpression node) { 1126 JS.Expression visitBinaryExpression(BinaryExpression node) {
1125 var op = node.operator; 1127 var op = node.operator;
1126 var left = node.leftOperand; 1128 var left = node.leftOperand;
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
1189 // TODO(jmesserly, vsm): Refactor this logic. 1191 // TODO(jmesserly, vsm): Refactor this logic.
1190 SimpleIdentifier _createTemporary(String name, DartType type) { 1192 SimpleIdentifier _createTemporary(String name, DartType type) {
1191 var id = 1193 var id =
1192 new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, name, 0)); 1194 new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, name, 0));
1193 id.staticElement = new LocalVariableElementImpl.forNode(id); 1195 id.staticElement = new LocalVariableElementImpl.forNode(id);
1194 id.staticType = type; 1196 id.staticType = type;
1195 return id; 1197 return id;
1196 } 1198 }
1197 1199
1198 JS.Expression _emitPostfixIncrement(Expression expr, Token op) { 1200 JS.Expression _emitPostfixIncrement(Expression expr, Token op) {
1199 var tmp = _createTemporary('\$tmp', rules.getStaticType(expr)); 1201 var type = rules.getStaticType(expr);
1202 assert(type != null);
1203 var tmp = _createTemporary('\$tmp', type);
1200 1204
1201 // Increment and write 1205 // Increment and write
1202 var one = AstBuilder.integerLiteral(1); 1206 var one = AstBuilder.integerLiteral(1);
1207 one.staticType = rules.provider.intType;
1203 var increment = AstBuilder.binaryExpression(tmp, op.lexeme[0], one); 1208 var increment = AstBuilder.binaryExpression(tmp, op.lexeme[0], one);
1209 increment.staticType = type;
1204 var write = _emitAssignment(expr, increment); 1210 var write = _emitAssignment(expr, increment);
1205 1211
1206 var bindThis = _maybeBindThis(expr); 1212 var bindThis = _maybeBindThis(expr);
1207 return js.call("((#) => (#, #))$bindThis(#)", [ 1213 return js.call("((#) => (#, #))$bindThis(#)", [
1208 tmp.name, 1214 tmp.name,
1209 write, 1215 write,
1210 _visit(tmp), 1216 _visit(tmp),
1211 _visit(expr) 1217 _visit(expr)
1212 ]); 1218 ]);
1213 } 1219 }
1214 1220
1215 @override 1221 @override
1216 JS.Expression visitPostfixExpression(PostfixExpression node) { 1222 JS.Expression visitPostfixExpression(PostfixExpression node) {
1217 var op = node.operator; 1223 var op = node.operator;
1218 var expr = node.operand; 1224 var expr = node.operand;
1219 1225
1226 if (node.parent is Statement) {
1227 // Prefix code is simpler. If the expr result isn't used, fall to that.
1228 return _emitPrefixExpression(op, expr);
1229 }
1230
1220 var dispatchType = rules.getStaticType(expr); 1231 var dispatchType = rules.getStaticType(expr);
1221 if (unaryOperationIsPrimitive(dispatchType)) { 1232 if (unaryOperationIsPrimitive(dispatchType)) {
1222 // TODO(vsm): When do Dart ops not map to JS? 1233 if (_isNonNullableExpression(expr)) {
1223 return js.call('#$op', notNull(expr)); 1234 return js.call('#$op', _visit(expr));
1224 } else { 1235 }
1225 assert(op.lexeme == '++' || op.lexeme == '--');
1226 return _emitPostfixIncrement(expr, op);
1227 } 1236 }
1237
1238 assert(op.lexeme == '++' || op.lexeme == '--');
1239 return _emitPostfixIncrement(expr, op);
1228 } 1240 }
1229 1241
1230 JS.Expression _emitPrefixIncrement(Token op, Expression expr) { 1242 JS.Expression _emitPrefixIncrement(Token op, Expression expr) {
1231 var one = AstBuilder.integerLiteral(1); 1243 var one = AstBuilder.integerLiteral(1);
1232 var increment = AstBuilder.binaryExpression(expr, op.lexeme[0], one); 1244 var increment = AstBuilder.binaryExpression(expr, op.lexeme[0], one);
1233 return _emitAssignment(expr, increment); 1245 return _emitAssignment(expr, increment);
1234 } 1246 }
1235 1247
1236 @override 1248 @override
1237 JS.Expression visitPrefixExpression(PrefixExpression node) { 1249 JS.Expression visitPrefixExpression(PrefixExpression node) {
1238 var op = node.operator; 1250 return _emitPrefixExpression(node.operator, node.operand);
1239 var expr = node.operand; 1251 }
1240 1252
1253 JS.Expression _emitPrefixExpression(Token op, Expression expr) {
1241 var dispatchType = rules.getStaticType(expr); 1254 var dispatchType = rules.getStaticType(expr);
1242 if (unaryOperationIsPrimitive(dispatchType)) { 1255 if (unaryOperationIsPrimitive(dispatchType)) {
1243 // TODO(vsm): When do Dart ops not map to JS? 1256 if (_isNonNullableExpression(expr)) {
1244 return js.call('$op#', notNull(expr)); 1257 return js.call('$op#', _visit(expr));
1258 } else if (op.lexeme == '++' || op.lexeme == '--') {
1259 // We need a null check, so the increment must be expanded out.
1260 var mathop = op.lexeme[0];
1261 return js.call('# = # $mathop 1', [_visit(expr), notNull(expr)]);
1262 } else {
1263 return js.call('$op#', notNull(expr));
1264 }
1245 } else { 1265 } else {
1246 // Increment or decrement requires expansion 1266 // Increment or decrement requires expansion.
1247 if (op.lexeme == '++' || op.lexeme == '--') { 1267 if (op.lexeme == '++' || op.lexeme == '--') {
1248 return _emitPrefixIncrement(op, expr); 1268 return _emitPrefixIncrement(op, expr);
1249 } 1269 }
1250 } 1270 }
1251 1271
1252 // Call the operator 1272 // Call the operator
1253 var opString = _jsMemberName(op.lexeme, unary: true); 1273 var opString = _jsMemberName(op.lexeme, unary: true);
1254 if (rules.isDynamicTarget(expr)) { 1274 if (rules.isDynamicTarget(expr)) {
1255 // dynamic dispatch 1275 // dynamic dispatch
1256 return js.call('dart.dunary(#, #)', [opString, _visit(expr)]); 1276 return js.call('dart.dunary(#, #)', [opString, _visit(expr)]);
(...skipping 764 matching lines...) Expand 10 before | Expand all | Expand 10 after
2021 2041
2022 // TODO(jmesserly): in many cases marking the end will be unncessary. 2042 // TODO(jmesserly): in many cases marking the end will be unncessary.
2023 printer.mark(_location(node.end)); 2043 printer.mark(_location(node.end));
2024 } 2044 }
2025 2045
2026 String _getIdentifier(AstNode node) { 2046 String _getIdentifier(AstNode node) {
2027 if (node is SimpleIdentifier) return node.name; 2047 if (node is SimpleIdentifier) return node.name;
2028 return null; 2048 return null;
2029 } 2049 }
2030 } 2050 }
OLDNEW
« no previous file with comments | « no previous file | test/codegen/expect/BenchmarkBase.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698