Chromium Code Reviews| 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; | 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 582 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 593 var name = node.name.name; | 593 var name = node.name.name; |
| 594 var element = node.element; | 594 var element = node.element; |
| 595 var inheritedElement = | 595 var inheritedElement = |
| 596 classElem.lookUpInheritedConcreteMethod(name, currentLibrary); | 596 classElem.lookUpInheritedConcreteMethod(name, currentLibrary); |
| 597 if (inheritedElement != null && | 597 if (inheritedElement != null && |
| 598 inheritedElement.type == element.type) continue; | 598 inheritedElement.type == element.type) continue; |
| 599 var unary = node.parameters.parameters.isEmpty; | 599 var unary = node.parameters.parameters.isEmpty; |
| 600 var memberName = _emitMemberName(name, | 600 var memberName = _emitMemberName(name, |
| 601 type: cType, unary: unary, isStatic: node.isStatic); | 601 type: cType, unary: unary, isStatic: node.isStatic); |
| 602 var property = | 602 var property = |
| 603 new JS.Property(memberName, _emitTypeName(element.type)); | 603 new JS.Property(memberName, _emitFunctionRTTI(element.type)); |
| 604 if (node.isStatic) { | 604 if (node.isStatic) { |
| 605 tStatics.add(property); | 605 tStatics.add(property); |
| 606 sNames.add(memberName); | 606 sNames.add(memberName); |
| 607 } else tMethods.add(property); | 607 } else tMethods.add(property); |
| 608 } | 608 } |
| 609 } | 609 } |
| 610 build(name, elements) { | 610 build(name, elements) { |
| 611 var o = | 611 var o = |
| 612 new JS.ObjectInitializer(elements, vertical: elements.length > 1); | 612 new JS.ObjectInitializer(elements, vertical: elements.length > 1); |
| 613 var e = js.call('() => #', o); | 613 var e = js.call('() => #', o); |
| (...skipping 404 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1018 var lazy = topLevel && !_typeIsLoaded(type); | 1018 var lazy = topLevel && !_typeIsLoaded(type); |
| 1019 | 1019 |
| 1020 if (type is FunctionType && (name == '' || name == null)) { | 1020 if (type is FunctionType && (name == '' || name == null)) { |
| 1021 if (type.returnType.isDynamic && | 1021 if (type.returnType.isDynamic && |
| 1022 type.optionalParameterTypes.isEmpty && | 1022 type.optionalParameterTypes.isEmpty && |
| 1023 type.namedParameterTypes.isEmpty && | 1023 type.namedParameterTypes.isEmpty && |
| 1024 type.normalParameterTypes.every((t) => t.isDynamic)) { | 1024 type.normalParameterTypes.every((t) => t.isDynamic)) { |
| 1025 return js.call('dart.fn(#)', [clos]); | 1025 return js.call('dart.fn(#)', [clos]); |
| 1026 } | 1026 } |
| 1027 if (lazy) { | 1027 if (lazy) { |
| 1028 return js.call('dart.fn(#, () => #)', [clos, _emitTypeName(type)]); | 1028 return js.call('dart.fn(#, () => #)', [clos, _emitFunctionRTTI(type)]); |
| 1029 } | 1029 } |
| 1030 return js.call('dart.fn(#, #)', [clos, _emitFunctionTypeParts(type)]); | 1030 return js.call('dart.fn(#, #)', [ |
| 1031 clos, | |
| 1032 _emitFunctionTypeParts(type, dynamicIsObject: true) | |
| 1033 ]); | |
| 1031 } | 1034 } |
| 1032 throw 'Function has non function type: $type'; | 1035 throw 'Function has non function type: $type'; |
| 1033 } | 1036 } |
| 1034 | 1037 |
| 1035 @override | 1038 @override |
| 1036 JS.Expression visitFunctionExpression(FunctionExpression node) { | 1039 JS.Expression visitFunctionExpression(FunctionExpression node) { |
| 1037 var params = _visit(node.parameters); | 1040 var params = _visit(node.parameters); |
| 1038 if (params == null) params = []; | 1041 if (params == null) params = []; |
| 1039 | 1042 |
| 1040 var parent = node.parent; | 1043 var parent = node.parent; |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1152 return _getTemp(element, name); | 1155 return _getTemp(element, name); |
| 1153 } | 1156 } |
| 1154 } | 1157 } |
| 1155 | 1158 |
| 1156 return new JS.Identifier(name); | 1159 return new JS.Identifier(name); |
| 1157 } | 1160 } |
| 1158 | 1161 |
| 1159 JS.TemporaryId _getTemp(Object key, String name) => | 1162 JS.TemporaryId _getTemp(Object key, String name) => |
| 1160 _temps.putIfAbsent(key, () => new JS.TemporaryId(name)); | 1163 _temps.putIfAbsent(key, () => new JS.TemporaryId(name)); |
| 1161 | 1164 |
| 1162 JS.ArrayInitializer _emitTypeNames(List<DartType> types) { | 1165 JS.ArrayInitializer _emitTypeNames(List<DartType> types, |
| 1163 return new JS.ArrayInitializer(types.map(_emitTypeName).toList()); | 1166 {dynamicIsBottom: false}) { |
| 1167 var build = (t) => _emitTypeName(t, dynamicIsBottom: dynamicIsBottom); | |
| 1168 return new JS.ArrayInitializer(types.map(build).toList()); | |
| 1164 } | 1169 } |
| 1165 | 1170 |
| 1166 JS.ObjectInitializer _emitTypeProperties(Map<String, DartType> types) { | 1171 JS.ObjectInitializer _emitTypeProperties(Map<String, DartType> types, |
| 1172 {dynamicIsBottom: false}) { | |
| 1167 var properties = <JS.Property>[]; | 1173 var properties = <JS.Property>[]; |
| 1168 types.forEach((name, type) { | 1174 types.forEach((name, type) { |
| 1169 var key = new JS.LiteralString(name); | 1175 var key = new JS.LiteralString(name); |
| 1170 var value = _emitTypeName(type); | 1176 var value = _emitTypeName(type, dynamicIsBottom: dynamicIsBottom); |
| 1171 properties.add(new JS.Property(key, value)); | 1177 properties.add(new JS.Property(key, value)); |
| 1172 }); | 1178 }); |
| 1173 return new JS.ObjectInitializer(properties); | 1179 return new JS.ObjectInitializer(properties); |
| 1174 } | 1180 } |
| 1175 | 1181 |
| 1176 List<JS.Expression> _emitFunctionTypeParts(FunctionType type) { | 1182 /// Emit the pieces of a function type, as an array of return type, |
| 1183 /// regular args, and optional/named args. | |
| 1184 /// If [dynamicIsObject] is set, then dynamics in argument positions | |
| 1185 /// will be lowered to Object instead of bottom. | |
| 1186 List<JS.Expression> _emitFunctionTypeParts(FunctionType type, | |
| 1187 {bool dynamicIsObject: false}) { | |
|
vsm
2015/05/20 23:03:10
Perhaps use either dynamicIsBottom here or dynamic
Leaf
2015/05/20 23:35:28
Done.
| |
| 1177 var returnType = type.returnType; | 1188 var returnType = type.returnType; |
| 1178 var parameterTypes = type.normalParameterTypes; | 1189 var parameterTypes = type.normalParameterTypes; |
| 1179 var optionalTypes = type.optionalParameterTypes; | 1190 var optionalTypes = type.optionalParameterTypes; |
| 1180 var namedTypes = type.namedParameterTypes; | 1191 var namedTypes = type.namedParameterTypes; |
| 1181 var rt = _emitTypeName(returnType); | 1192 var rt = _emitTypeName(returnType); |
| 1182 var ra = _emitTypeNames(parameterTypes); | 1193 var ra = _emitTypeNames(parameterTypes, dynamicIsBottom: !dynamicIsObject); |
| 1183 if (!namedTypes.isEmpty) { | 1194 if (!namedTypes.isEmpty) { |
| 1184 assert(optionalTypes.isEmpty); | 1195 assert(optionalTypes.isEmpty); |
| 1185 var na = _emitTypeProperties(namedTypes); | 1196 var na = |
| 1197 _emitTypeProperties(namedTypes, dynamicIsBottom: !dynamicIsObject); | |
| 1186 return [rt, ra, na]; | 1198 return [rt, ra, na]; |
| 1187 } | 1199 } |
| 1188 if (!optionalTypes.isEmpty) { | 1200 if (!optionalTypes.isEmpty) { |
| 1189 assert(namedTypes.isEmpty); | 1201 assert(namedTypes.isEmpty); |
| 1190 var oa = _emitTypeNames(optionalTypes); | 1202 var oa = _emitTypeNames(optionalTypes, dynamicIsBottom: !dynamicIsObject); |
| 1191 return [rt, ra, oa]; | 1203 return [rt, ra, oa]; |
| 1192 } | 1204 } |
| 1193 return [rt, ra]; | 1205 return [rt, ra]; |
| 1194 } | 1206 } |
| 1195 | 1207 |
| 1208 JS.Expression _emitFunctionRTTI(FunctionType type) { | |
| 1209 var parts = _emitFunctionTypeParts(type, dynamicIsObject: true); | |
| 1210 return js.call('dart.functionType(#)', [parts]); | |
| 1211 } | |
| 1212 | |
| 1196 /// Emits a Dart [type] into code. | 1213 /// Emits a Dart [type] into code. |
| 1197 /// | 1214 /// |
| 1198 /// If [lowerTypedef] is set, a typedef will be expanded as if it were a | 1215 /// If [lowerTypedef] is set, a typedef will be expanded as if it were a |
| 1199 /// function type. Similarly if [lowerGeneric] is set, the `List$()` form | 1216 /// function type. Similarly if [lowerGeneric] is set, the `List$()` form |
| 1200 /// will be used instead of `List`. These flags are used when generating | 1217 /// will be used instead of `List`. These flags are used when generating |
| 1201 /// the definitions for typedefs and generic types, respectively. | 1218 /// the definitions for typedefs and generic types, respectively. |
| 1202 JS.Expression _emitTypeName(DartType type, | 1219 JS.Expression _emitTypeName(DartType type, {bool lowerTypedef: false, |
| 1203 {bool lowerTypedef: false, bool lowerGeneric: false}) { | 1220 bool lowerGeneric: false, bool dynamicIsBottom: false}) { |
| 1204 | 1221 |
| 1205 // The void and dynamic types are not defined in core. | 1222 // The void and dynamic types are not defined in core. |
| 1206 if (type.isVoid) { | 1223 if (type.isVoid) { |
| 1207 return js.call('dart.void'); | 1224 return js.call('dart.void'); |
| 1208 } else if (type.isDynamic) { | 1225 } else if (type.isDynamic) { |
| 1209 return js.call('dart.dynamic'); | 1226 if (dynamicIsBottom) return js.call('dart.bottom'); |
| 1227 return _emitTypeName(types.objectType); | |
| 1210 } else if (type.isBottom) { | 1228 } else if (type.isBottom) { |
| 1211 return js.call('dart.bottom'); | 1229 return js.call('dart.bottom'); |
| 1212 } | 1230 } |
| 1213 | 1231 |
| 1214 _loader.declareBeforeUse(type.element); | 1232 _loader.declareBeforeUse(type.element); |
| 1215 | 1233 |
| 1216 // TODO(jmesserly): like constants, should we hoist function types out of | 1234 // TODO(jmesserly): like constants, should we hoist function types out of |
| 1217 // methods? Similar issue with generic types. For all of these, we may want | 1235 // methods? Similar issue with generic types. For all of these, we may want |
| 1218 // to canonicalize them too, at least when inside the same library. | 1236 // to canonicalize them too, at least when inside the same library. |
| 1219 var name = type.name; | 1237 var name = type.name; |
| (...skipping 1362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2582 | 2600 |
| 2583 /// A special kind of element created by the compiler, signifying a temporary | 2601 /// A special kind of element created by the compiler, signifying a temporary |
| 2584 /// variable. These objects use instance equality, and should be shared | 2602 /// variable. These objects use instance equality, and should be shared |
| 2585 /// everywhere in the tree where they are treated as the same variable. | 2603 /// everywhere in the tree where they are treated as the same variable. |
| 2586 class TemporaryVariableElement extends LocalVariableElementImpl { | 2604 class TemporaryVariableElement extends LocalVariableElementImpl { |
| 2587 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); | 2605 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); |
| 2588 | 2606 |
| 2589 int get hashCode => identityHashCode(this); | 2607 int get hashCode => identityHashCode(this); |
| 2590 bool operator ==(Object other) => identical(this, other); | 2608 bool operator ==(Object other) => identical(this, other); |
| 2591 } | 2609 } |
| OLD | NEW |