| 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 library dev_compiler.src.codegen.js_codegen; | 5 library dev_compiler.src.codegen.js_codegen; |
| 6 | 6 |
| 7 import 'dart:collection' show HashSet, HashMap, SplayTreeSet; | 7 import 'dart:collection' show HashSet, HashMap, SplayTreeSet; |
| 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 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 318 // Skip the cast if it's not needed. | 318 // Skip the cast if it's not needed. |
| 319 if (rules.isSubTypeOf(from, to)) return fromExpr; | 319 if (rules.isSubTypeOf(from, to)) return fromExpr; |
| 320 | 320 |
| 321 // All Dart number types map to a JS double. | 321 // All Dart number types map to a JS double. |
| 322 if (_isNumberInJS(from) && _isNumberInJS(to)) { | 322 if (_isNumberInJS(from) && _isNumberInJS(to)) { |
| 323 // Make sure to check when converting to int. | 323 // Make sure to check when converting to int. |
| 324 if (from != _types.intType && to == _types.intType) { | 324 if (from != _types.intType && to == _types.intType) { |
| 325 return js.call('dart.asInt(#)', [fromExpr]); | 325 return js.call('dart.asInt(#)', [fromExpr]); |
| 326 } | 326 } |
| 327 | 327 |
| 328 if (!rules.isNonNullableType(from) && rules.isNonNullableType(to)) { | 328 // A no-op in JavaScript. |
| 329 // Converting from a nullable number to a non-nullable number | 329 return fromExpr; |
| 330 // only requires a null check. | |
| 331 // TODO(jmesserly): a lot of these checks are meaningless, as people use | |
| 332 // `num` to mean "any kind of number" rather than "could be null". | |
| 333 // The core libraries especially suffer from this problem, with many of | |
| 334 // the `num` methods returning `num`. | |
| 335 return js.call('dart.notNull(#)', fromExpr); | |
| 336 } else { | |
| 337 // A no-op in JavaScript. | |
| 338 return fromExpr; | |
| 339 } | |
| 340 } | 330 } |
| 341 | 331 |
| 342 return js.call('dart.as(#, #)', [fromExpr, _emitTypeName(to)]); | 332 return js.call('dart.as(#, #)', [fromExpr, _emitTypeName(to)]); |
| 343 } | 333 } |
| 344 | 334 |
| 345 @override | 335 @override |
| 346 visitIsExpression(IsExpression node) { | 336 visitIsExpression(IsExpression node) { |
| 347 // Generate `is` as `dart.is` or `typeof` depending on the RHS type. | 337 // Generate `is` as `dart.is` or `typeof` depending on the RHS type. |
| 348 JS.Expression result; | 338 JS.Expression result; |
| 349 var type = node.type.type; | 339 var type = node.type.type; |
| (...skipping 769 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1119 } | 1109 } |
| 1120 | 1110 |
| 1121 for (var f in fields.keys) unsetFields.remove(f); | 1111 for (var f in fields.keys) unsetFields.remove(f); |
| 1122 | 1112 |
| 1123 // Initialize all remaining fields | 1113 // Initialize all remaining fields |
| 1124 unsetFields.forEach((element, fieldNode) { | 1114 unsetFields.forEach((element, fieldNode) { |
| 1125 JS.Expression value; | 1115 JS.Expression value; |
| 1126 if (fieldNode.initializer != null) { | 1116 if (fieldNode.initializer != null) { |
| 1127 value = _visit(fieldNode.initializer); | 1117 value = _visit(fieldNode.initializer); |
| 1128 } else { | 1118 } else { |
| 1129 var type = rules.elementType(element); | |
| 1130 value = new JS.LiteralNull(); | 1119 value = new JS.LiteralNull(); |
| 1131 if (rules.maybeNonNullableType(type)) { | |
| 1132 value = js.call('dart.as(#, #)', [value, _emitTypeName(type)]); | |
| 1133 } | |
| 1134 } | 1120 } |
| 1135 fields[element] = value; | 1121 fields[element] = value; |
| 1136 }); | 1122 }); |
| 1137 | 1123 |
| 1138 var body = <JS.Statement>[]; | 1124 var body = <JS.Statement>[]; |
| 1139 fields.forEach((FieldElement e, JS.Expression initialValue) { | 1125 fields.forEach((FieldElement e, JS.Expression initialValue) { |
| 1140 var access = _emitMemberName(e.name, type: e.enclosingElement.type); | 1126 var access = _emitMemberName(e.name, type: e.enclosingElement.type); |
| 1141 body.add(js.statement('this.# = #;', [access, initialValue])); | 1127 body.add(js.statement('this.# = #;', [access, initialValue])); |
| 1142 }); | 1128 }); |
| 1143 | 1129 |
| (...skipping 1024 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2168 /// True if this type is built-in to JS, and we use the values unwrapped. | 2154 /// True if this type is built-in to JS, and we use the values unwrapped. |
| 2169 /// For these types we generate a calling convention via static | 2155 /// For these types we generate a calling convention via static |
| 2170 /// "extension methods". This allows types to be extended without adding | 2156 /// "extension methods". This allows types to be extended without adding |
| 2171 /// extensions directly on the prototype. | 2157 /// extensions directly on the prototype. |
| 2172 bool _isJSBuiltinType(DartType t) => | 2158 bool _isJSBuiltinType(DartType t) => |
| 2173 typeIsPrimitiveInJS(t) || t == _types.stringType; | 2159 typeIsPrimitiveInJS(t) || t == _types.stringType; |
| 2174 | 2160 |
| 2175 bool typeIsPrimitiveInJS(DartType t) => | 2161 bool typeIsPrimitiveInJS(DartType t) => |
| 2176 _isNumberInJS(t) || t == _types.boolType; | 2162 _isNumberInJS(t) || t == _types.boolType; |
| 2177 | 2163 |
| 2178 bool typeIsNonNullablePrimitiveInJS(DartType t) => | |
| 2179 typeIsPrimitiveInJS(t) && rules.isNonNullableType(t); | |
| 2180 | |
| 2181 bool binaryOperationIsPrimitive(DartType leftT, DartType rightT) => | 2164 bool binaryOperationIsPrimitive(DartType leftT, DartType rightT) => |
| 2182 typeIsPrimitiveInJS(leftT) && typeIsPrimitiveInJS(rightT); | 2165 typeIsPrimitiveInJS(leftT) && typeIsPrimitiveInJS(rightT); |
| 2183 | 2166 |
| 2184 bool unaryOperationIsPrimitive(DartType t) => typeIsPrimitiveInJS(t); | 2167 bool unaryOperationIsPrimitive(DartType t) => typeIsPrimitiveInJS(t); |
| 2185 | 2168 |
| 2186 bool _isNonNullableExpression(Expression expr) { | 2169 bool _isNonNullableExpression(Expression expr) { |
| 2187 // If the type is non-nullable, no further checking needed. | |
| 2188 if (rules.isNonNullableType(getStaticType(expr))) return true; | |
| 2189 | |
| 2190 // TODO(vsm): Revisit whether we really need this when we get | 2170 // TODO(vsm): Revisit whether we really need this when we get |
| 2191 // better non-nullability in the type system. | 2171 // better non-nullability in the type system. |
| 2192 // TODO(jmesserly): we do recursive calls in a few places. This could | 2172 // TODO(jmesserly): we do recursive calls in a few places. This could |
| 2193 // leads to O(depth) cost for calling this function. We could store the | 2173 // leads to O(depth) cost for calling this function. We could store the |
| 2194 // resulting value if that becomes an issue, so we maintain the invariant | 2174 // resulting value if that becomes an issue, so we maintain the invariant |
| 2195 // that each node is visited once. | 2175 // that each node is visited once. |
| 2196 | 2176 |
| 2197 if (expr is Literal && expr is! NullLiteral) return true; | 2177 if (expr is Literal && expr is! NullLiteral) return true; |
| 2198 if (expr is IsExpression) return true; | 2178 if (expr is IsExpression) return true; |
| 2199 if (expr is ThisExpression) return true; | 2179 if (expr is ThisExpression) return true; |
| (...skipping 1133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3333 | 3313 |
| 3334 /// A special kind of element created by the compiler, signifying a temporary | 3314 /// A special kind of element created by the compiler, signifying a temporary |
| 3335 /// variable. These objects use instance equality, and should be shared | 3315 /// variable. These objects use instance equality, and should be shared |
| 3336 /// everywhere in the tree where they are treated as the same variable. | 3316 /// everywhere in the tree where they are treated as the same variable. |
| 3337 class TemporaryVariableElement extends LocalVariableElementImpl { | 3317 class TemporaryVariableElement extends LocalVariableElementImpl { |
| 3338 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); | 3318 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); |
| 3339 | 3319 |
| 3340 int get hashCode => identityHashCode(this); | 3320 int get hashCode => identityHashCode(this); |
| 3341 bool operator ==(Object other) => identical(this, other); | 3321 bool operator ==(Object other) => identical(this, other); |
| 3342 } | 3322 } |
| OLD | NEW |