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

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

Issue 1962823002: fix #552, Object members on native types (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@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') | lib/src/compiler/nullable_type_inference.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 206 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 // TODO(jmesserly): find a cleaner design for this. 217 // TODO(jmesserly): find a cleaner design for this.
218 if (_isDartRuntime(library)) { 218 if (_isDartRuntime(library)) {
219 items.add(new JS.ExportDeclaration( 219 items.add(new JS.ExportDeclaration(
220 js.call('const # = Object.create(null)', [_dartxVar]))); 220 js.call('const # = Object.create(null)', [_dartxVar])));
221 } 221 }
222 } 222 }
223 223
224 // Collect all Element -> Node mappings, in case we need to forward declare 224 // Collect all Element -> Node mappings, in case we need to forward declare
225 // any nodes. 225 // any nodes.
226 var nodes = new HashMap<Element, AstNode>.identity(); 226 var nodes = new HashMap<Element, AstNode>.identity();
227 compilationUnits.map(_collectElements).forEach(nodes.addAll); 227 var sdkBootstrappingFns = new List<FunctionElement>();
228 for (var unit in compilationUnits) {
229 if (_isDartRuntime(unit.element.library)) {
230 sdkBootstrappingFns.addAll(unit.element.functions);
231 }
232 _collectElements(unit, nodes);
233 }
228 _loader = new ElementLoader(_emitModuleItem, nodes); 234 _loader = new ElementLoader(_emitModuleItem, nodes);
229 235
230 // Add implicit dart:core dependency so it is first. 236 // Add implicit dart:core dependency so it is first.
231 emitLibraryName(dartCoreLibrary); 237 emitLibraryName(dartCoreLibrary);
232 238
239 // Emit SDK bootstrapping functions first, if any.
240 sdkBootstrappingFns.forEach(_loader.emitDeclaration);
241
233 // Visit each compilation unit and emit its code. 242 // Visit each compilation unit and emit its code.
234 // 243 //
235 // NOTE: declarations are not necessarily emitted in this order. 244 // NOTE: declarations are not necessarily emitted in this order.
236 // Order will be changed as needed so the resulting code can execute. 245 // Order will be changed as needed so the resulting code can execute.
237 // This is done by forward declaring items. 246 // This is done by forward declaring items.
238 compilationUnits.forEach(visitCompilationUnit); 247 compilationUnits.forEach(visitCompilationUnit);
239 248
240 // Declare imports 249 // Declare imports
241 _finishImports(items); 250 _finishImports(items);
242 251
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
312 imports.add(new JS.NameSpecifier(_runtimeLibVar)); 321 imports.add(new JS.NameSpecifier(_runtimeLibVar));
313 imports.add(new JS.NameSpecifier(_dartxVar)); 322 imports.add(new JS.NameSpecifier(_dartxVar));
314 } 323 }
315 items.add(new JS.ImportDeclaration( 324 items.add(new JS.ImportDeclaration(
316 namedImports: imports, from: js.string(module, "'"))); 325 namedImports: imports, from: js.string(module, "'")));
317 }); 326 });
318 } 327 }
319 328
320 /// Collect toplevel elements and nodes we need to emit, and returns 329 /// Collect toplevel elements and nodes we need to emit, and returns
321 /// an ordered map of these. 330 /// an ordered map of these.
322 static Map<Element, AstNode> _collectElements(CompilationUnit unit) { 331 static void _collectElements(
323 var map = <Element, AstNode>{}; 332 CompilationUnit unit, Map<Element, AstNode> map) {
324 for (var declaration in unit.declarations) { 333 for (var declaration in unit.declarations) {
325 if (declaration is TopLevelVariableDeclaration) { 334 if (declaration is TopLevelVariableDeclaration) {
326 for (var field in declaration.variables.variables) { 335 for (var field in declaration.variables.variables) {
327 map[field.element] = field; 336 map[field.element] = field;
328 } 337 }
329 } else { 338 } else {
330 map[declaration.element] = declaration; 339 map[declaration.element] = declaration;
331 } 340 }
332 } 341 }
333 return map;
334 } 342 }
335 343
336 void _emitModuleItem(AstNode node) { 344 void _emitModuleItem(AstNode node) {
337 // TODO(jmesserly): ideally we could do this at a smaller granularity. 345 // TODO(jmesserly): ideally we could do this at a smaller granularity.
338 // We'll need to be consistent about when we're generating functions, and 346 // We'll need to be consistent about when we're generating functions, and
339 // only run this on the outermost function. 347 // only run this on the outermost function.
340 inferNullableTypes(node); 348 inferNullableTypes(node);
341 349
342 var code = _visit(node); 350 var code = _visit(node);
343 if (code != null) _moduleItems.add(code); 351 if (code != null) _moduleItems.add(code);
(...skipping 610 matching lines...) Expand 10 before | Expand all | Expand 10 after
954 JS.Method _emitSuperAccessorWrapper(MethodDeclaration method, 962 JS.Method _emitSuperAccessorWrapper(MethodDeclaration method,
955 InterfaceType type, List<ClassElement> superclasses) { 963 InterfaceType type, List<ClassElement> superclasses) {
956 var methodElement = method.element as PropertyAccessorElement; 964 var methodElement = method.element as PropertyAccessorElement;
957 var field = methodElement.variable; 965 var field = methodElement.variable;
958 if (!field.isSynthetic) return null; 966 if (!field.isSynthetic) return null;
959 var propertyOverrideResult = checkForPropertyOverride( 967 var propertyOverrideResult = checkForPropertyOverride(
960 methodElement.variable, superclasses, _extensionTypes); 968 methodElement.variable, superclasses, _extensionTypes);
961 969
962 // Generate a corresponding virtual getter / setter. 970 // Generate a corresponding virtual getter / setter.
963 var name = _elementMemberName(methodElement, 971 var name = _elementMemberName(methodElement,
964 allowExtensions: _extensionTypes.isNativeClass(type.element)); 972 useExtension: _extensionTypes.isNativeClass(type.element));
965 if (method.isGetter) { 973 if (method.isGetter) {
966 // Generate a setter 974 // Generate a setter
967 if (field.setter != null || !propertyOverrideResult.foundSetter) 975 if (field.setter != null || !propertyOverrideResult.foundSetter)
968 return null; 976 return null;
969 var fn = js.call('function(value) { super[#] = value; }', [name]); 977 var fn = js.call('function(value) { super[#] = value; }', [name]);
970 return new JS.Method(name, fn, isSetter: true); 978 return new JS.Method(name, fn, isSetter: true);
971 } else { 979 } else {
972 // Generate a getter 980 // Generate a getter
973 if (field.getter != null || !propertyOverrideResult.foundGetter) 981 if (field.getter != null || !propertyOverrideResult.foundGetter)
974 return null; 982 return null;
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
1109 1117
1110 /// If a concrete class implements one of our extensions, we might need to 1118 /// If a concrete class implements one of our extensions, we might need to
1111 /// add forwarders. 1119 /// add forwarders.
1112 void _defineExtensionMembers(List<ExecutableElement> extensions, 1120 void _defineExtensionMembers(List<ExecutableElement> extensions,
1113 JS.Expression className, List<JS.Statement> body) { 1121 JS.Expression className, List<JS.Statement> body) {
1114 // If a concrete class implements one of our extensions, we might need to 1122 // If a concrete class implements one of our extensions, we might need to
1115 // add forwarders. 1123 // add forwarders.
1116 if (extensions.isNotEmpty) { 1124 if (extensions.isNotEmpty) {
1117 var methodNames = <JS.Expression>[]; 1125 var methodNames = <JS.Expression>[];
1118 for (var e in extensions) { 1126 for (var e in extensions) {
1119 methodNames.add(_elementMemberName(e, allowExtensions: false)); 1127 methodNames.add(_elementMemberName(e, useExtension: false));
1120 } 1128 }
1121 body.add(js.statement('dart.defineExtensionMembers(#, #);', [ 1129 body.add(js.statement('dart.defineExtensionMembers(#, #);', [
1122 className, 1130 className,
1123 new JS.ArrayInitializer(methodNames, multiline: methodNames.length > 4) 1131 new JS.ArrayInitializer(methodNames, multiline: methodNames.length > 4)
1124 ])); 1132 ]));
1125 } 1133 }
1126 } 1134 }
1127 1135
1128 /// Emit the signature on the class recording the runtime type information 1136 /// Emit the signature on the class recording the runtime type information
1129 void _emitClassSignature( 1137 void _emitClassSignature(
(...skipping 17 matching lines...) Expand all
1147 for (MethodDeclaration node in methods) { 1155 for (MethodDeclaration node in methods) {
1148 if (!(node.isSetter || node.isGetter || node.isAbstract)) { 1156 if (!(node.isSetter || node.isGetter || node.isAbstract)) {
1149 var name = node.name.name; 1157 var name = node.name.name;
1150 var element = node.element; 1158 var element = node.element;
1151 var inheritedElement = 1159 var inheritedElement =
1152 classElem.lookUpInheritedConcreteMethod(name, currentLibrary); 1160 classElem.lookUpInheritedConcreteMethod(name, currentLibrary);
1153 if (inheritedElement != null && inheritedElement.type == element.type) { 1161 if (inheritedElement != null && inheritedElement.type == element.type) {
1154 continue; 1162 continue;
1155 } 1163 }
1156 var memberName = _elementMemberName(element, 1164 var memberName = _elementMemberName(element,
1157 allowExtensions: _extensionTypes.isNativeClass(classElem)); 1165 useExtension: _extensionTypes.isNativeClass(classElem));
1158 var parts = _emitFunctionTypeParts(element.type); 1166 var parts = _emitFunctionTypeParts(element.type);
1159 var property = 1167 var property =
1160 new JS.Property(memberName, new JS.ArrayInitializer(parts)); 1168 new JS.Property(memberName, new JS.ArrayInitializer(parts));
1161 if (node.isStatic) { 1169 if (node.isStatic) {
1162 tStatics.add(property); 1170 tStatics.add(property);
1163 sNames.add(memberName); 1171 sNames.add(memberName);
1164 } else { 1172 } else {
1165 tMethods.add(property); 1173 tMethods.add(property);
1166 } 1174 }
1167 } 1175 }
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1203 /// Ensure `dartx.` symbols we will use are present. 1211 /// Ensure `dartx.` symbols we will use are present.
1204 void _initExtensionSymbols( 1212 void _initExtensionSymbols(
1205 ClassElement classElem, 1213 ClassElement classElem,
1206 List<MethodDeclaration> methods, 1214 List<MethodDeclaration> methods,
1207 List<FieldDeclaration> fields, 1215 List<FieldDeclaration> fields,
1208 List<JS.Statement> body) { 1216 List<JS.Statement> body) {
1209 if (_extensionTypes.hasNativeSubtype(classElem.type)) { 1217 if (_extensionTypes.hasNativeSubtype(classElem.type)) {
1210 var dartxNames = <JS.Expression>[]; 1218 var dartxNames = <JS.Expression>[];
1211 for (var m in methods) { 1219 for (var m in methods) {
1212 if (!m.isAbstract && !m.isStatic && m.element.isPublic) { 1220 if (!m.isAbstract && !m.isStatic && m.element.isPublic) {
1213 dartxNames.add(_elementMemberName(m.element, allowExtensions: false)); 1221 dartxNames.add(_elementMemberName(m.element, useExtension: false));
1214 } 1222 }
1215 } 1223 }
1216 for (var f in fields) { 1224 for (var f in fields) {
1217 if (!f.isStatic) { 1225 if (!f.isStatic) {
1218 for (var d in f.fields.variables) { 1226 for (var d in f.fields.variables) {
1219 if (d.element.isPublic) { 1227 if (d.element.isPublic) {
1220 dartxNames.add( 1228 dartxNames.add(
1221 _elementMemberName(d.element.getter, allowExtensions: false)); 1229 _elementMemberName(d.element.getter, useExtension: false));
1222 } 1230 }
1223 } 1231 }
1224 } 1232 }
1225 } 1233 }
1226 if (dartxNames.isNotEmpty) { 1234 if (dartxNames.isNotEmpty) {
1227 body.add(js.statement('dart.defineExtensionNames(#)', 1235 body.add(js.statement('dart.defineExtensionNames(#)',
1228 [new JS.ArrayInitializer(dartxNames, multiline: true)])); 1236 [new JS.ArrayInitializer(dartxNames, multiline: true)]));
1229 } 1237 }
1230 } 1238 }
1231 } 1239 }
1232 1240
1233 List<ExecutableElement> _extensionsToImplement(ClassElement element) { 1241 List<ExecutableElement> _extensionsToImplement(ClassElement element) {
1234 var members = <ExecutableElement>[]; 1242 var members = <ExecutableElement>[];
1235 if (_extensionTypes.isNativeClass(element)) return members; 1243 if (_extensionTypes.isNativeClass(element)) return members;
1236 1244
1237 // Collect all extension types we implement. 1245 // Collect all extension types we implement.
1238 var type = element.type; 1246 var type = element.type;
1239 var types = _extensionTypes.collectNativeInterfaces(element); 1247 var types = _extensionTypes.collectNativeInterfaces(element);
1240 if (types.isEmpty) return members; 1248 if (types.isEmpty) return members;
1241 1249
1242 // Collect all possible extension method names. 1250 // Collect all possible extension method names.
1243 var extensionMembers = new HashSet<String>(); 1251 var extensionMembers = new HashSet<String>();
1244 for (var t in types) { 1252 for (var t in types) {
1245 for (var m in [t.methods, t.accessors].expand((e) => e)) { 1253 for (var m in [t.methods, t.accessors].expand((e) => e)) {
1246 if (!m.isStatic) extensionMembers.add(m.name); 1254 if (!m.isStatic && m.isPublic) extensionMembers.add(m.name);
1247 } 1255 }
1248 } 1256 }
1249 1257
1250 // Collect all of extension methods this type implements. 1258 // Collect all of extension methods this type implements.
1251 for (var m in [type.methods, type.accessors].expand((e) => e)) { 1259 for (var m in [type.methods, type.accessors].expand((e) => e)) {
1252 if (!m.isStatic && !m.isAbstract && extensionMembers.contains(m.name)) { 1260 if (!m.isStatic && !m.isAbstract && extensionMembers.contains(m.name)) {
1253 members.add(m); 1261 members.add(m);
1254 } 1262 }
1255 } 1263 }
1256 return members; 1264 return members;
(...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after
1670 // call sites, but it's cleaner to instead transform the operator method . 1678 // call sites, but it's cleaner to instead transform the operator method .
1671 fn = _alwaysReturnLastParameter(fn); 1679 fn = _alwaysReturnLastParameter(fn);
1672 } 1680 }
1673 1681
1674 fn = _makeGenericFunction(fn); 1682 fn = _makeGenericFunction(fn);
1675 } 1683 }
1676 1684
1677 return annotate( 1685 return annotate(
1678 new JS.Method( 1686 new JS.Method(
1679 _elementMemberName(node.element, 1687 _elementMemberName(node.element,
1680 allowExtensions: _extensionTypes.isNativeClass(type.element)), 1688 useExtension: _extensionTypes.isNativeClass(type.element)),
1681 fn, 1689 fn,
1682 isGetter: node.isGetter, 1690 isGetter: node.isGetter,
1683 isSetter: node.isSetter, 1691 isSetter: node.isSetter,
1684 isStatic: node.isStatic), 1692 isStatic: node.isStatic),
1685 node, 1693 node,
1686 node.element); 1694 node.element);
1687 } 1695 }
1688 1696
1689 /// Transform the function so the last parameter is always returned. 1697 /// Transform the function so the last parameter is always returned.
1690 /// 1698 ///
(...skipping 794 matching lines...) Expand 10 before | Expand all | Expand 10 after
2485 JS.Expression jsTarget = _visit(target); 2493 JS.Expression jsTarget = _visit(target);
2486 if (DynamicInvoke.get(target)) { 2494 if (DynamicInvoke.get(target)) {
2487 if (typeArgs != null) { 2495 if (typeArgs != null) {
2488 return js.call('dart.dgsend(#, #, #, #)', 2496 return js.call('dart.dgsend(#, #, #, #)',
2489 [jsTarget, new JS.ArrayInitializer(typeArgs), memberName, args]); 2497 [jsTarget, new JS.ArrayInitializer(typeArgs), memberName, args]);
2490 } else { 2498 } else {
2491 return js.call('dart.dsend(#, #, #)', [jsTarget, memberName, args]); 2499 return js.call('dart.dsend(#, #, #)', [jsTarget, memberName, args]);
2492 } 2500 }
2493 } 2501 }
2494 if (_isObjectMemberCall(target, name)) { 2502 if (_isObjectMemberCall(target, name)) {
2495 // Object methods require a helper for null checks & native types.
2496 assert(typeArgs == null); // Object methods don't take type args. 2503 assert(typeArgs == null); // Object methods don't take type args.
2497 return js.call('dart.#(#, #)', [memberName, jsTarget, args]); 2504 return js.call('dart.#(#, #)', [name, jsTarget, args]);
2498 } 2505 }
2499 2506
2500 jsTarget = new JS.PropertyAccess(jsTarget, memberName); 2507 jsTarget = new JS.PropertyAccess(jsTarget, memberName);
2501 2508
2502 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); 2509 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs);
2503 2510
2504 if (DynamicInvoke.get(node.methodName)) { 2511 if (DynamicInvoke.get(node.methodName)) {
2505 // This is a dynamic call to a statically known target. For example: 2512 // This is a dynamic call to a statically known target. For example:
2506 // class Foo { Function bar; } 2513 // class Foo { Function bar; }
2507 // new Foo().bar(); // dynamic call 2514 // new Foo().bar(); // dynamic call
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after
2838 // Static and instance fields are handled elsewhere. 2845 // Static and instance fields are handled elsewhere.
2839 assert(node.element is TopLevelVariableElement); 2846 assert(node.element is TopLevelVariableElement);
2840 return _emitTopLevelField(node); 2847 return _emitTopLevelField(node);
2841 } 2848 }
2842 2849
2843 var name = 2850 var name =
2844 new JS.Identifier(node.name.name, type: emitTypeRef(node.element.type)); 2851 new JS.Identifier(node.name.name, type: emitTypeRef(node.element.type));
2845 return new JS.VariableInitialization(name, _visitInitializer(node)); 2852 return new JS.VariableInitialization(name, _visitInitializer(node));
2846 } 2853 }
2847 2854
2848 bool _isFinalJSDecl(AstNode field) =>
2849 field is VariableDeclaration &&
2850 field.isFinal &&
2851 _isJSInvocation(field.initializer);
2852
2853 /// Try to emit a constant static field. 2855 /// Try to emit a constant static field.
2854 /// 2856 ///
2855 /// If the field's initializer does not cause side effects, and if all of 2857 /// If the field's initializer does not cause side effects, and if all of
2856 /// dependencies are safe to refer to while we are initializing the class, 2858 /// dependencies are safe to refer to while we are initializing the class,
2857 /// then we can initialize it eagerly: 2859 /// then we can initialize it eagerly:
2858 /// 2860 ///
2859 /// // Baz must be const constructor, and the name "Baz" must be defined 2861 /// // Baz must be const constructor, and the name "Baz" must be defined
2860 /// // by this point. 2862 /// // by this point.
2861 /// Foo.bar = dart.const(new Baz(42)); 2863 /// Foo.bar = dart.const(new Baz(42));
2862 /// 2864 ///
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
2908 jsInit = _visitInitializer(field); 2910 jsInit = _visitInitializer(field);
2909 _loader.finishTopLevel(element); 2911 _loader.finishTopLevel(element);
2910 eagerInit = _loader.isLoaded(element); 2912 eagerInit = _loader.isLoaded(element);
2911 } else { 2913 } else {
2912 // TODO(jmesserly): we're visiting the initializer here, and again 2914 // TODO(jmesserly): we're visiting the initializer here, and again
2913 // later on when we emit lazy fields. That seems busted. 2915 // later on when we emit lazy fields. That seems busted.
2914 jsInit = _visitInitializer(field); 2916 jsInit = _visitInitializer(field);
2915 eagerInit = false; 2917 eagerInit = false;
2916 } 2918 }
2917 2919
2918 // Treat `final x = JS('', '...')` as a const (non-lazy) to help compile 2920 // Treat dart:runtime stuff as safe to eagerly evaluate.
2919 // runtime helpers. 2921 // TODO(jmesserly): it'd be nice to avoid this special case.
2920 // TODO(jmesserly): we don't track dependencies correctly for these. 2922 var isJSTopLevel = field.isFinal && _isDartRuntime(element.library);
2921 var isJSTopLevel = field.isFinal && _isFinalJSDecl(field);
2922 if (eagerInit || isJSTopLevel) { 2923 if (eagerInit || isJSTopLevel) {
2923 // Remember that we emitted it this way, so re-export can take advantage 2924 // Remember that we emitted it this way, so re-export can take advantage
2924 // of this fact. 2925 // of this fact.
2925 _eagerTopLevelFields.add(element); 2926 _eagerTopLevelFields.add(element);
2926 2927
2927 return annotate( 2928 return annotate(
2928 js.statement('# = #;', [_emitTopLevelName(element), jsInit]), 2929 js.statement('# = #;', [_emitTopLevelName(element), jsInit]),
2929 field, 2930 field,
2930 element); 2931 element);
2931 } 2932 }
(...skipping 672 matching lines...) Expand 10 before | Expand all | Expand 10 after
3604 } 3605 }
3605 } 3606 }
3606 3607
3607 /// Everything in Dart is an Object and supports the 4 members on Object, 3608 /// Everything in Dart is an Object and supports the 4 members on Object,
3608 /// so we have to use a runtime helper to handle values such as `null` and 3609 /// so we have to use a runtime helper to handle values such as `null` and
3609 /// native types. 3610 /// native types.
3610 /// 3611 ///
3611 /// For example `null.toString()` is legal in Dart, so we need to generate 3612 /// For example `null.toString()` is legal in Dart, so we need to generate
3612 /// that as `dart.toString(obj)`. 3613 /// that as `dart.toString(obj)`.
3613 bool _isObjectMemberCall(Expression target, String memberName) { 3614 bool _isObjectMemberCall(Expression target, String memberName) {
3614 // Is this a member on `Object`? 3615 if (!isObjectMember(memberName)) {
3615 if (!isObjectProperty(memberName)) {
3616 return false; 3616 return false;
3617 } 3617 }
3618 3618
3619 // Check if the target could be `null`, is dynamic, or may be an extension 3619 // Check if the target could be `null`, is dynamic, or may be an extension
3620 // native type. In all of those cases we need defensive code generation. 3620 // native type. In all of those cases we need defensive code generation.
3621 var type = getStaticType(target); 3621 var type = getStaticType(target);
3622 return isNullable(target) || 3622 return isNullable(target) ||
3623 type.isDynamic || 3623 type.isDynamic ||
3624 (_extensionTypes.hasNativeSubtype(type) && target is! SuperExpression); 3624 (_extensionTypes.hasNativeSubtype(type) && target is! SuperExpression);
3625 } 3625 }
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
3683 // subclasses cannot override x. 3683 // subclasses cannot override x.
3684 jsTarget = new JS.This(); 3684 jsTarget = new JS.This();
3685 } 3685 }
3686 3686
3687 JS.Expression result; 3687 JS.Expression result;
3688 if (member != null && member is MethodElement && !isStatic) { 3688 if (member != null && member is MethodElement && !isStatic) {
3689 // Tear-off methods: explicitly bind it. 3689 // Tear-off methods: explicitly bind it.
3690 if (isSuper) { 3690 if (isSuper) {
3691 result = js.call('dart.bind(this, #, #.#)', [name, jsTarget, name]); 3691 result = js.call('dart.bind(this, #, #.#)', [name, jsTarget, name]);
3692 } else if (_isObjectMemberCall(target, memberName)) { 3692 } else if (_isObjectMemberCall(target, memberName)) {
3693 result = js.call('dart.bind(#, #, dart.#)', [jsTarget, name, name]); 3693 result = js.call('dart.bind(#, #, dart.#)',
3694 [jsTarget, _propertyName(memberName), memberName]);
3694 } else { 3695 } else {
3695 result = js.call('dart.bind(#, #)', [jsTarget, name]); 3696 result = js.call('dart.bind(#, #)', [jsTarget, name]);
3696 } 3697 }
3697 } else if (_isObjectMemberCall(target, memberName)) { 3698 } else if (_isObjectMemberCall(target, memberName)) {
3698 result = js.call('dart.#(#)', [name, jsTarget]); 3699 result = js.call('dart.#(#)', [memberName, jsTarget]);
3699 } else { 3700 } else {
3700 result = js.call('#.#', [jsTarget, name]); 3701 result = js.call('#.#', [jsTarget, name]);
3701 } 3702 }
3702 if (typeArgs == null) { 3703 if (typeArgs == null) {
3703 return result; 3704 return result;
3704 } 3705 }
3705 return js.call('dart.gbind(#, #)', [result, typeArgs]); 3706 return js.call('dart.gbind(#, #)', [result, typeArgs]);
3706 } 3707 }
3707 3708
3708 /// Emits a generic send, like an operator method. 3709 /// Emits a generic send, like an operator method.
(...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after
4154 JS.Expression _visitListToBinary(List<Expression> nodes, String operator) { 4155 JS.Expression _visitListToBinary(List<Expression> nodes, String operator) {
4155 if (nodes == null || nodes.isEmpty) return null; 4156 if (nodes == null || nodes.isEmpty) return null;
4156 return new JS.Expression.binary( 4157 return new JS.Expression.binary(
4157 _visitList(nodes) as List<JS.Expression>, operator); 4158 _visitList(nodes) as List<JS.Expression>, operator);
4158 } 4159 }
4159 4160
4160 /// Like [_emitMemberName], but for declaration sites. 4161 /// Like [_emitMemberName], but for declaration sites.
4161 /// 4162 ///
4162 /// Unlike call sites, we always have an element available, so we can use it 4163 /// Unlike call sites, we always have an element available, so we can use it
4163 /// directly rather than computing the relevant options for [_emitMemberName]. 4164 /// directly rather than computing the relevant options for [_emitMemberName].
4164 JS.Expression _elementMemberName(ExecutableElement e, 4165 JS.Expression _elementMemberName(ExecutableElement e, {bool useExtension}) {
4165 {bool allowExtensions: true}) {
4166 String name; 4166 String name;
4167 if (e is PropertyAccessorElement) { 4167 if (e is PropertyAccessorElement) {
4168 name = e.variable.name; 4168 name = e.variable.name;
4169 } else { 4169 } else {
4170 name = e.name; 4170 name = e.name;
4171 } 4171 }
4172 return _emitMemberName(name, 4172 return _emitMemberName(name,
4173 type: (e.enclosingElement as ClassElement).type, 4173 type: (e.enclosingElement as ClassElement).type,
4174 unary: e.parameters.isEmpty, 4174 unary: e.parameters.isEmpty,
4175 isStatic: e.isStatic, 4175 isStatic: e.isStatic,
4176 allowExtensions: allowExtensions); 4176 useExtension: useExtension);
4177 } 4177 }
4178 4178
4179 /// This handles member renaming for private names and operators. 4179 /// This handles member renaming for private names and operators.
4180 /// 4180 ///
4181 /// Private names are generated using ES6 symbols: 4181 /// Private names are generated using ES6 symbols:
4182 /// 4182 ///
4183 /// // At the top of the module: 4183 /// // At the top of the module:
4184 /// let _x = Symbol('_x'); 4184 /// let _x = Symbol('_x');
4185 /// let _y = Symbol('_y'); 4185 /// let _y = Symbol('_y');
4186 /// ... 4186 /// ...
(...skipping 27 matching lines...) Expand all
4214 /// Unary minus looks like: `x['unary-']()`. Note that [unary] must be passed 4214 /// Unary minus looks like: `x['unary-']()`. Note that [unary] must be passed
4215 /// for this transformation to happen, otherwise binary minus is assumed. 4215 /// for this transformation to happen, otherwise binary minus is assumed.
4216 /// 4216 ///
4217 /// Equality is a bit special, it is generated via the Dart `equals` runtime 4217 /// Equality is a bit special, it is generated via the Dart `equals` runtime
4218 /// helper, that checks for null. The user defined method is called '=='. 4218 /// helper, that checks for null. The user defined method is called '=='.
4219 /// 4219 ///
4220 JS.Expression _emitMemberName(String name, 4220 JS.Expression _emitMemberName(String name,
4221 {DartType type, 4221 {DartType type,
4222 bool unary: false, 4222 bool unary: false,
4223 bool isStatic: false, 4223 bool isStatic: false,
4224 bool allowExtensions: true}) { 4224 bool useExtension}) {
4225 // Static members skip the rename steps. 4225 // Static members skip the rename steps.
4226 if (isStatic) return _propertyName(name); 4226 if (isStatic) return _propertyName(name);
4227 4227
4228 if (name.startsWith('_')) { 4228 if (name.startsWith('_')) {
4229 return _emitPrivateNameSymbol(currentLibrary, name); 4229 return _emitPrivateNameSymbol(currentLibrary, name);
4230 } 4230 }
4231 4231
4232 if (name == '[]') { 4232 if (name == '[]') {
4233 name = 'get'; 4233 name = 'get';
4234 } else if (name == '[]=') { 4234 } else if (name == '[]=') {
4235 name = 'set'; 4235 name = 'set';
4236 } else if (name == '-' && unary) { 4236 } else if (name == '-' && unary) {
4237 name = 'unary-'; 4237 name = 'unary-';
4238 } else if (name == 'constructor' || name == 'prototype') { 4238 } else if (name == 'constructor' || name == 'prototype') {
4239 // This uses an illegal (in Dart) character for a member, avoiding the 4239 // This uses an illegal (in Dart) character for a member, avoiding the
4240 // conflict. We could use practically any character for this. 4240 // conflict. We could use practically any character for this.
4241 name = '+$name'; 4241 name = '+$name';
4242 } 4242 }
4243 4243
4244 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. 4244 var result = _propertyName(name);
4245 var baseType = type; 4245
4246 while (baseType is TypeParameterType) { 4246 if (useExtension == null) {
4247 baseType = baseType.element.bound; 4247 // Dart "extension" methods. Used for JS Array, Boolean, Number, String.
4248 } 4248 var baseType = type;
4249 if (allowExtensions && 4249 while (baseType is TypeParameterType) {
4250 baseType != null && 4250 baseType = baseType.element.bound;
4251 _extensionTypes.hasNativeSubtype(baseType) && 4251 }
4252 !isObjectProperty(name)) { 4252 useExtension = baseType != null &&
4253 return js.call('dartx.#', _propertyName(name)); 4253 _extensionTypes.hasNativeSubtype(baseType) &&
4254 !isObjectMember(name);
4254 } 4255 }
4255 4256
4256 return _propertyName(name); 4257 return useExtension ? js.call('dartx.#', result) : result;
4257 } 4258 }
4258 4259
4259 JS.TemporaryId _emitPrivateNameSymbol(LibraryElement library, String name) { 4260 JS.TemporaryId _emitPrivateNameSymbol(LibraryElement library, String name) {
4260 return _privateNames 4261 return _privateNames
4261 .putIfAbsent(library, () => new HashMap()) 4262 .putIfAbsent(library, () => new HashMap())
4262 .putIfAbsent(name, () { 4263 .putIfAbsent(name, () {
4263 var id = new JS.TemporaryId(name); 4264 var id = new JS.TemporaryId(name);
4264 _moduleItems.add( 4265 _moduleItems.add(
4265 js.statement('const # = Symbol(#);', [id, js.string(id.name, "'")])); 4266 js.statement('const # = Symbol(#);', [id, js.string(id.name, "'")]));
4266 return id; 4267 return id;
(...skipping 25 matching lines...) Expand all
4292 } 4293 }
4293 4294
4294 /// Returns true if this is any kind of object represented by `Number` in JS. 4295 /// Returns true if this is any kind of object represented by `Number` in JS.
4295 /// 4296 ///
4296 /// In practice, this is 4 types: num, int, double, and JSNumber. 4297 /// In practice, this is 4 types: num, int, double, and JSNumber.
4297 /// 4298 ///
4298 /// JSNumber is the type that actually "implements" all numbers, hence it's 4299 /// JSNumber is the type that actually "implements" all numbers, hence it's
4299 /// a subtype of int and double (and num). It's in our "dart:_interceptors". 4300 /// a subtype of int and double (and num). It's in our "dart:_interceptors".
4300 bool _isNumberInJS(DartType t) => rules.isSubtypeOf(t, types.numType); 4301 bool _isNumberInJS(DartType t) => rules.isSubtypeOf(t, types.numType);
4301 4302
4302 bool _isObjectGetter(String name) { 4303 /// Return true if this is one of the methods/properties on all Dart Objects
4303 PropertyAccessorElement element = types.objectType.element.getGetter(name); 4304 /// (toString, hashCode, noSuchMethod, runtimeType).
4304 return (element != null && !element.isStatic); 4305 ///
4305 } 4306 /// Operator == is excluded, as it is handled as part of the equality binary
4306 4307 /// operator.
4307 bool _isObjectMethod(String name) { 4308 bool isObjectMember(String name) {
4308 MethodElement element = types.objectType.element.getMethod(name); 4309 // We could look these up on Object, but we have hard coded runtime helpers
4309 return (element != null && !element.isStatic); 4310 // so it's not really providing any benefit.
4310 } 4311 switch (name) {
4311 4312 case 'hashCode':
4312 bool isObjectProperty(String name) { 4313 case 'toString':
4313 return _isObjectGetter(name) || _isObjectMethod(name); 4314 case 'noSuchMethod':
4315 case 'runtimeType':
4316 return true;
4317 }
4318 return false;
4314 } 4319 }
4315 4320
4316 // TODO(leafp): Various analyzer pieces computed similar things. 4321 // TODO(leafp): Various analyzer pieces computed similar things.
4317 // Share this logic somewhere? 4322 // Share this logic somewhere?
4318 DartType _getExpectedReturnType(ExecutableElement element) { 4323 DartType _getExpectedReturnType(ExecutableElement element) {
4319 FunctionType functionType = element.type; 4324 FunctionType functionType = element.type;
4320 if (functionType == null) { 4325 if (functionType == null) {
4321 return DynamicTypeImpl.instance; 4326 return DynamicTypeImpl.instance;
4322 } 4327 }
4323 var type = functionType.returnType; 4328 var type = functionType.returnType;
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
4403 } 4408 }
4404 4409
4405 bool isLibraryPrefix(Expression node) => 4410 bool isLibraryPrefix(Expression node) =>
4406 node is SimpleIdentifier && node.staticElement is PrefixElement; 4411 node is SimpleIdentifier && node.staticElement is PrefixElement;
4407 4412
4408 LibraryElement _getLibrary(AnalysisContext c, String uri) => 4413 LibraryElement _getLibrary(AnalysisContext c, String uri) =>
4409 c.computeLibraryElement(c.sourceFactory.forUri(uri)); 4414 c.computeLibraryElement(c.sourceFactory.forUri(uri));
4410 4415
4411 bool _isDartRuntime(LibraryElement l) => 4416 bool _isDartRuntime(LibraryElement l) =>
4412 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; 4417 l.isInSdk && l.source.uri.toString() == 'dart:_runtime';
OLDNEW
« no previous file with comments | « lib/runtime/dart_sdk.js ('k') | lib/src/compiler/nullable_type_inference.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698