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

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
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(CompilationUnit unit, Map<Element, AstNode> map) {
323 var map = <Element, AstNode>{};
324 for (var declaration in unit.declarations) { 332 for (var declaration in unit.declarations) {
325 if (declaration is TopLevelVariableDeclaration) { 333 if (declaration is TopLevelVariableDeclaration) {
326 for (var field in declaration.variables.variables) { 334 for (var field in declaration.variables.variables) {
327 map[field.element] = field; 335 map[field.element] = field;
328 } 336 }
329 } else { 337 } else {
330 map[declaration.element] = declaration; 338 map[declaration.element] = declaration;
331 } 339 }
332 } 340 }
333 return map;
334 } 341 }
335 342
336 void _emitModuleItem(AstNode node) { 343 void _emitModuleItem(AstNode node) {
337 // TODO(jmesserly): ideally we could do this at a smaller granularity. 344 // 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 345 // We'll need to be consistent about when we're generating functions, and
339 // only run this on the outermost function. 346 // only run this on the outermost function.
340 inferNullableTypes(node); 347 inferNullableTypes(node);
341 348
342 var code = _visit(node); 349 var code = _visit(node);
343 if (code != null) _moduleItems.add(code); 350 if (code != null) _moduleItems.add(code);
(...skipping 610 matching lines...) Expand 10 before | Expand all | Expand 10 after
954 JS.Method _emitSuperAccessorWrapper(MethodDeclaration method, 961 JS.Method _emitSuperAccessorWrapper(MethodDeclaration method,
955 InterfaceType type, List<ClassElement> superclasses) { 962 InterfaceType type, List<ClassElement> superclasses) {
956 var methodElement = method.element as PropertyAccessorElement; 963 var methodElement = method.element as PropertyAccessorElement;
957 var field = methodElement.variable; 964 var field = methodElement.variable;
958 if (!field.isSynthetic) return null; 965 if (!field.isSynthetic) return null;
959 var propertyOverrideResult = checkForPropertyOverride( 966 var propertyOverrideResult = checkForPropertyOverride(
960 methodElement.variable, superclasses, _extensionTypes); 967 methodElement.variable, superclasses, _extensionTypes);
961 968
962 // Generate a corresponding virtual getter / setter. 969 // Generate a corresponding virtual getter / setter.
963 var name = _elementMemberName(methodElement, 970 var name = _elementMemberName(methodElement,
964 allowExtensions: _extensionTypes.isNativeClass(type.element)); 971 useExtension: _extensionTypes.isNativeClass(type.element));
965 if (method.isGetter) { 972 if (method.isGetter) {
966 // Generate a setter 973 // Generate a setter
967 if (field.setter != null || !propertyOverrideResult.foundSetter) 974 if (field.setter != null || !propertyOverrideResult.foundSetter)
968 return null; 975 return null;
969 var fn = js.call('function(value) { super[#] = value; }', [name]); 976 var fn = js.call('function(value) { super[#] = value; }', [name]);
970 return new JS.Method(name, fn, isSetter: true); 977 return new JS.Method(name, fn, isSetter: true);
971 } else { 978 } else {
972 // Generate a getter 979 // Generate a getter
973 if (field.getter != null || !propertyOverrideResult.foundGetter) 980 if (field.getter != null || !propertyOverrideResult.foundGetter)
974 return null; 981 return null;
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
1108 1115
1109 /// If a concrete class implements one of our extensions, we might need to 1116 /// If a concrete class implements one of our extensions, we might need to
1110 /// add forwarders. 1117 /// add forwarders.
1111 void _defineExtensionMembers(List<ExecutableElement> extensions, 1118 void _defineExtensionMembers(List<ExecutableElement> extensions,
1112 JS.Expression className, List<JS.Statement> body) { 1119 JS.Expression className, List<JS.Statement> body) {
1113 // If a concrete class implements one of our extensions, we might need to 1120 // If a concrete class implements one of our extensions, we might need to
1114 // add forwarders. 1121 // add forwarders.
1115 if (extensions.isNotEmpty) { 1122 if (extensions.isNotEmpty) {
1116 var methodNames = <JS.Expression>[]; 1123 var methodNames = <JS.Expression>[];
1117 for (var e in extensions) { 1124 for (var e in extensions) {
1118 methodNames.add(_elementMemberName(e, allowExtensions: false)); 1125 methodNames.add(_elementMemberName(e, useExtension: false));
1119 } 1126 }
1120 body.add(js.statement('dart.defineExtensionMembers(#, #);', [ 1127 body.add(js.statement('dart.defineExtensionMembers(#, #);', [
1121 className, 1128 className,
1122 new JS.ArrayInitializer(methodNames, multiline: methodNames.length > 4) 1129 new JS.ArrayInitializer(methodNames, multiline: methodNames.length > 4)
1123 ])); 1130 ]));
1124 } 1131 }
1125 } 1132 }
1126 1133
1127 /// Emit the signature on the class recording the runtime type information 1134 /// Emit the signature on the class recording the runtime type information
1128 void _emitClassSignature( 1135 void _emitClassSignature(
(...skipping 17 matching lines...) Expand all
1146 for (MethodDeclaration node in methods) { 1153 for (MethodDeclaration node in methods) {
1147 if (!(node.isSetter || node.isGetter || node.isAbstract)) { 1154 if (!(node.isSetter || node.isGetter || node.isAbstract)) {
1148 var name = node.name.name; 1155 var name = node.name.name;
1149 var element = node.element; 1156 var element = node.element;
1150 var inheritedElement = 1157 var inheritedElement =
1151 classElem.lookUpInheritedConcreteMethod(name, currentLibrary); 1158 classElem.lookUpInheritedConcreteMethod(name, currentLibrary);
1152 if (inheritedElement != null && inheritedElement.type == element.type) { 1159 if (inheritedElement != null && inheritedElement.type == element.type) {
1153 continue; 1160 continue;
1154 } 1161 }
1155 var memberName = _elementMemberName(element, 1162 var memberName = _elementMemberName(element,
1156 allowExtensions: _extensionTypes.isNativeClass(classElem)); 1163 useExtension: _extensionTypes.isNativeClass(classElem));
1157 var parts = _emitFunctionTypeParts(element.type); 1164 var parts = _emitFunctionTypeParts(element.type);
1158 var property = 1165 var property =
1159 new JS.Property(memberName, new JS.ArrayInitializer(parts)); 1166 new JS.Property(memberName, new JS.ArrayInitializer(parts));
1160 if (node.isStatic) { 1167 if (node.isStatic) {
1161 tStatics.add(property); 1168 tStatics.add(property);
1162 sNames.add(memberName); 1169 sNames.add(memberName);
1163 } else { 1170 } else {
1164 tMethods.add(property); 1171 tMethods.add(property);
1165 } 1172 }
1166 } 1173 }
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1202 /// Ensure `dartx.` symbols we will use are present. 1209 /// Ensure `dartx.` symbols we will use are present.
1203 void _initExtensionSymbols( 1210 void _initExtensionSymbols(
1204 ClassElement classElem, 1211 ClassElement classElem,
1205 List<MethodDeclaration> methods, 1212 List<MethodDeclaration> methods,
1206 List<FieldDeclaration> fields, 1213 List<FieldDeclaration> fields,
1207 List<JS.Statement> body) { 1214 List<JS.Statement> body) {
1208 if (_extensionTypes.hasNativeSubtype(classElem.type)) { 1215 if (_extensionTypes.hasNativeSubtype(classElem.type)) {
1209 var dartxNames = <JS.Expression>[]; 1216 var dartxNames = <JS.Expression>[];
1210 for (var m in methods) { 1217 for (var m in methods) {
1211 if (!m.isAbstract && !m.isStatic && m.element.isPublic) { 1218 if (!m.isAbstract && !m.isStatic && m.element.isPublic) {
1212 dartxNames.add(_elementMemberName(m.element, allowExtensions: false)); 1219 dartxNames.add(_elementMemberName(m.element, useExtension: false));
1213 } 1220 }
1214 } 1221 }
1215 for (var f in fields) { 1222 for (var f in fields) {
1216 if (!f.isStatic) { 1223 if (!f.isStatic) {
1217 for (var d in f.fields.variables) { 1224 for (var d in f.fields.variables) {
1218 if (d.element.isPublic) { 1225 if (d.element.isPublic) {
1219 dartxNames.add( 1226 dartxNames.add(
1220 _elementMemberName(d.element.getter, allowExtensions: false)); 1227 _elementMemberName(d.element.getter, useExtension: false));
1221 } 1228 }
1222 } 1229 }
1223 } 1230 }
1224 } 1231 }
1225 if (dartxNames.isNotEmpty) { 1232 if (dartxNames.isNotEmpty) {
1226 body.add(js.statement('dart.defineExtensionNames(#)', 1233 body.add(js.statement('dart.defineExtensionNames(#)',
1227 [new JS.ArrayInitializer(dartxNames, multiline: true)])); 1234 [new JS.ArrayInitializer(dartxNames, multiline: true)]));
1228 } 1235 }
1229 } 1236 }
1230 } 1237 }
1231 1238
1232 List<ExecutableElement> _extensionsToImplement(ClassElement element) { 1239 List<ExecutableElement> _extensionsToImplement(ClassElement element) {
1233 var members = <ExecutableElement>[]; 1240 var members = <ExecutableElement>[];
1234 if (_extensionTypes.isNativeClass(element)) return members; 1241 if (_extensionTypes.isNativeClass(element)) return members;
1235 1242
1236 // Collect all extension types we implement. 1243 // Collect all extension types we implement.
1237 var type = element.type; 1244 var type = element.type;
1238 var types = _extensionTypes.collectNativeInterfaces(element); 1245 var types = _extensionTypes.collectNativeInterfaces(element);
1239 if (types.isEmpty) return members; 1246 if (types.isEmpty) return members;
1240 1247
1241 // Collect all possible extension method names. 1248 // Collect all possible extension method names.
1242 var extensionMembers = new HashSet<String>(); 1249 var extensionMembers = new HashSet<String>();
1243 for (var t in types) { 1250 for (var t in types) {
1244 for (var m in [t.methods, t.accessors].expand((e) => e)) { 1251 for (var m in [t.methods, t.accessors].expand((e) => e)) {
1245 if (!m.isStatic) extensionMembers.add(m.name); 1252 if (!m.isStatic && m.isPublic) extensionMembers.add(m.name);
1246 } 1253 }
1247 } 1254 }
1248 1255
1249 // Collect all of extension methods this type implements. 1256 // Collect all of extension methods this type implements.
1250 for (var m in [type.methods, type.accessors].expand((e) => e)) { 1257 for (var m in [type.methods, type.accessors].expand((e) => e)) {
1251 if (!m.isStatic && !m.isAbstract && extensionMembers.contains(m.name)) { 1258 if (!m.isStatic && !m.isAbstract && extensionMembers.contains(m.name)) {
1252 members.add(m); 1259 members.add(m);
1253 } 1260 }
1254 } 1261 }
1255 return members; 1262 return members;
(...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after
1669 // call sites, but it's cleaner to instead transform the operator method . 1676 // call sites, but it's cleaner to instead transform the operator method .
1670 fn = _alwaysReturnLastParameter(fn); 1677 fn = _alwaysReturnLastParameter(fn);
1671 } 1678 }
1672 1679
1673 fn = _makeGenericFunction(fn); 1680 fn = _makeGenericFunction(fn);
1674 } 1681 }
1675 1682
1676 return annotate( 1683 return annotate(
1677 new JS.Method( 1684 new JS.Method(
1678 _elementMemberName(node.element, 1685 _elementMemberName(node.element,
1679 allowExtensions: _extensionTypes.isNativeClass(type.element)), 1686 useExtension: _extensionTypes.isNativeClass(type.element)),
1680 fn, 1687 fn,
1681 isGetter: node.isGetter, 1688 isGetter: node.isGetter,
1682 isSetter: node.isSetter, 1689 isSetter: node.isSetter,
1683 isStatic: node.isStatic), 1690 isStatic: node.isStatic),
1684 node, 1691 node,
1685 node.element); 1692 node.element);
1686 } 1693 }
1687 1694
1688 /// Transform the function so the last parameter is always returned. 1695 /// Transform the function so the last parameter is always returned.
1689 /// 1696 ///
(...skipping 782 matching lines...) Expand 10 before | Expand all | Expand 10 after
2472 JS.Expression jsTarget = _visit(target); 2479 JS.Expression jsTarget = _visit(target);
2473 if (DynamicInvoke.get(target)) { 2480 if (DynamicInvoke.get(target)) {
2474 if (typeArgs != null) { 2481 if (typeArgs != null) {
2475 return js.call('dart.dgsend(#, #, #, #)', 2482 return js.call('dart.dgsend(#, #, #, #)',
2476 [jsTarget, new JS.ArrayInitializer(typeArgs), memberName, args]); 2483 [jsTarget, new JS.ArrayInitializer(typeArgs), memberName, args]);
2477 } else { 2484 } else {
2478 return js.call('dart.dsend(#, #, #)', [jsTarget, memberName, args]); 2485 return js.call('dart.dsend(#, #, #)', [jsTarget, memberName, args]);
2479 } 2486 }
2480 } 2487 }
2481 if (_isObjectMemberCall(target, name)) { 2488 if (_isObjectMemberCall(target, name)) {
2482 // Object methods require a helper for null checks & native types.
2483 assert(typeArgs == null); // Object methods don't take type args. 2489 assert(typeArgs == null); // Object methods don't take type args.
2484 return js.call('dart.#(#, #)', [memberName, jsTarget, args]); 2490 return js.call('dart.#(#, #)', [name, jsTarget, args]);
2485 } 2491 }
2486 2492
2487 jsTarget = new JS.PropertyAccess(jsTarget, memberName); 2493 jsTarget = new JS.PropertyAccess(jsTarget, memberName);
2488 2494
2489 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); 2495 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs);
2490 2496
2491 if (DynamicInvoke.get(node.methodName)) { 2497 if (DynamicInvoke.get(node.methodName)) {
2492 // This is a dynamic call to a statically known target. For example: 2498 // This is a dynamic call to a statically known target. For example:
2493 // class Foo { Function bar; } 2499 // class Foo { Function bar; }
2494 // new Foo().bar(); // dynamic call 2500 // new Foo().bar(); // dynamic call
(...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after
2827 // Static and instance fields are handled elsewhere. 2833 // Static and instance fields are handled elsewhere.
2828 assert(node.element is TopLevelVariableElement); 2834 assert(node.element is TopLevelVariableElement);
2829 return _emitTopLevelField(node); 2835 return _emitTopLevelField(node);
2830 } 2836 }
2831 2837
2832 var name = 2838 var name =
2833 new JS.Identifier(node.name.name, type: emitTypeRef(node.element.type)); 2839 new JS.Identifier(node.name.name, type: emitTypeRef(node.element.type));
2834 return new JS.VariableInitialization(name, _visitInitializer(node)); 2840 return new JS.VariableInitialization(name, _visitInitializer(node));
2835 } 2841 }
2836 2842
2837 bool _isFinalJSDecl(AstNode field) =>
2838 field is VariableDeclaration &&
2839 field.isFinal &&
2840 _isJSInvocation(field.initializer);
2841
2842 /// Try to emit a constant static field. 2843 /// Try to emit a constant static field.
2843 /// 2844 ///
2844 /// If the field's initializer does not cause side effects, and if all of 2845 /// If the field's initializer does not cause side effects, and if all of
2845 /// dependencies are safe to refer to while we are initializing the class, 2846 /// dependencies are safe to refer to while we are initializing the class,
2846 /// then we can initialize it eagerly: 2847 /// then we can initialize it eagerly:
2847 /// 2848 ///
2848 /// // Baz must be const constructor, and the name "Baz" must be defined 2849 /// // Baz must be const constructor, and the name "Baz" must be defined
2849 /// // by this point. 2850 /// // by this point.
2850 /// Foo.bar = dart.const(new Baz(42)); 2851 /// Foo.bar = dart.const(new Baz(42));
2851 /// 2852 ///
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
2897 jsInit = _visitInitializer(field); 2898 jsInit = _visitInitializer(field);
2898 _loader.finishTopLevel(element); 2899 _loader.finishTopLevel(element);
2899 eagerInit = _loader.isLoaded(element); 2900 eagerInit = _loader.isLoaded(element);
2900 } else { 2901 } else {
2901 // TODO(jmesserly): we're visiting the initializer here, and again 2902 // TODO(jmesserly): we're visiting the initializer here, and again
2902 // later on when we emit lazy fields. That seems busted. 2903 // later on when we emit lazy fields. That seems busted.
2903 jsInit = _visitInitializer(field); 2904 jsInit = _visitInitializer(field);
2904 eagerInit = false; 2905 eagerInit = false;
2905 } 2906 }
2906 2907
2907 // Treat `final x = JS('', '...')` as a const (non-lazy) to help compile 2908 // Treat dart:runtime stuff as safe to eagerly evaluate.
2908 // runtime helpers. 2909 // TODO(jmesserly): it'd be nice to avoid this special case.
2909 // TODO(jmesserly): we don't track dependencies correctly for these. 2910 var isJSTopLevel = field.isFinal && _isDartRuntime(element.library);
2910 var isJSTopLevel = field.isFinal && _isFinalJSDecl(field);
2911 if (eagerInit || isJSTopLevel) { 2911 if (eagerInit || isJSTopLevel) {
2912 // Remember that we emitted it this way, so re-export can take advantage 2912 // Remember that we emitted it this way, so re-export can take advantage
2913 // of this fact. 2913 // of this fact.
2914 _eagerTopLevelFields.add(element); 2914 _eagerTopLevelFields.add(element);
2915 2915
2916 return annotate( 2916 return annotate(
2917 js.statement('# = #;', [_emitTopLevelName(element), jsInit]), 2917 js.statement('# = #;', [_emitTopLevelName(element), jsInit]),
2918 field, 2918 field,
2919 element); 2919 element);
2920 } 2920 }
(...skipping 672 matching lines...) Expand 10 before | Expand all | Expand 10 after
3593 } 3593 }
3594 } 3594 }
3595 3595
3596 /// Everything in Dart is an Object and supports the 4 members on Object, 3596 /// Everything in Dart is an Object and supports the 4 members on Object,
3597 /// so we have to use a runtime helper to handle values such as `null` and 3597 /// so we have to use a runtime helper to handle values such as `null` and
3598 /// native types. 3598 /// native types.
3599 /// 3599 ///
3600 /// For example `null.toString()` is legal in Dart, so we need to generate 3600 /// For example `null.toString()` is legal in Dart, so we need to generate
3601 /// that as `dart.toString(obj)`. 3601 /// that as `dart.toString(obj)`.
3602 bool _isObjectMemberCall(Expression target, String memberName) { 3602 bool _isObjectMemberCall(Expression target, String memberName) {
3603 // Is this a member on `Object`? 3603 if (!isObjectMember(memberName)) {
3604 if (!isObjectProperty(memberName)) {
3605 return false; 3604 return false;
3606 } 3605 }
3607 3606
3608 // Check if the target could be `null`, is dynamic, or may be an extension 3607 // Check if the target could be `null`, is dynamic, or may be an extension
3609 // native type. In all of those cases we need defensive code generation. 3608 // native type. In all of those cases we need defensive code generation.
3610 var type = getStaticType(target); 3609 var type = getStaticType(target);
3611 return isNullable(target) || 3610 return isNullable(target) ||
3612 type.isDynamic || 3611 type.isDynamic ||
3613 (_extensionTypes.hasNativeSubtype(type) && target is! SuperExpression); 3612 (_extensionTypes.hasNativeSubtype(type) && target is! SuperExpression);
3614 } 3613 }
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
3672 // subclasses cannot override x. 3671 // subclasses cannot override x.
3673 jsTarget = new JS.This(); 3672 jsTarget = new JS.This();
3674 } 3673 }
3675 3674
3676 JS.Expression result; 3675 JS.Expression result;
3677 if (member != null && member is MethodElement && !isStatic) { 3676 if (member != null && member is MethodElement && !isStatic) {
3678 // Tear-off methods: explicitly bind it. 3677 // Tear-off methods: explicitly bind it.
3679 if (isSuper) { 3678 if (isSuper) {
3680 result = js.call('dart.bind(this, #, #.#)', [name, jsTarget, name]); 3679 result = js.call('dart.bind(this, #, #.#)', [name, jsTarget, name]);
3681 } else if (_isObjectMemberCall(target, memberName)) { 3680 } else if (_isObjectMemberCall(target, memberName)) {
3682 result = js.call('dart.bind(#, #, dart.#)', [jsTarget, name, name]); 3681 result = js.call('dart.bind(#, #, dart.#)',
3682 [jsTarget, _propertyName(memberName), memberName]);
3683 } else { 3683 } else {
3684 result = js.call('dart.bind(#, #)', [jsTarget, name]); 3684 result = js.call('dart.bind(#, #)', [jsTarget, name]);
3685 } 3685 }
3686 } else if (_isObjectMemberCall(target, memberName)) { 3686 } else if (_isObjectMemberCall(target, memberName)) {
3687 result = js.call('dart.#(#)', [name, jsTarget]); 3687 result = js.call('dart.#(#)', [memberName, jsTarget]);
3688 } else { 3688 } else {
3689 result = js.call('#.#', [jsTarget, name]); 3689 result = js.call('#.#', [jsTarget, name]);
3690 } 3690 }
3691 if (typeArgs == null) { 3691 if (typeArgs == null) {
3692 return result; 3692 return result;
3693 } 3693 }
3694 return js.call('dart.gbind(#, #)', [result, typeArgs]); 3694 return js.call('dart.gbind(#, #)', [result, typeArgs]);
3695 } 3695 }
3696 3696
3697 /// Emits a generic send, like an operator method. 3697 /// Emits a generic send, like an operator method.
(...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after
4145 JS.Expression _visitListToBinary(List<Expression> nodes, String operator) { 4145 JS.Expression _visitListToBinary(List<Expression> nodes, String operator) {
4146 if (nodes == null || nodes.isEmpty) return null; 4146 if (nodes == null || nodes.isEmpty) return null;
4147 return new JS.Expression.binary( 4147 return new JS.Expression.binary(
4148 _visitList(nodes) as List<JS.Expression>, operator); 4148 _visitList(nodes) as List<JS.Expression>, operator);
4149 } 4149 }
4150 4150
4151 /// Like [_emitMemberName], but for declaration sites. 4151 /// Like [_emitMemberName], but for declaration sites.
4152 /// 4152 ///
4153 /// Unlike call sites, we always have an element available, so we can use it 4153 /// Unlike call sites, we always have an element available, so we can use it
4154 /// directly rather than computing the relevant options for [_emitMemberName]. 4154 /// directly rather than computing the relevant options for [_emitMemberName].
4155 JS.Expression _elementMemberName(ExecutableElement e, 4155 JS.Expression _elementMemberName(ExecutableElement e, {bool useExtension}) {
4156 {bool allowExtensions: true}) {
4157 String name; 4156 String name;
4158 if (e is PropertyAccessorElement) { 4157 if (e is PropertyAccessorElement) {
4159 name = e.variable.name; 4158 name = e.variable.name;
4160 } else { 4159 } else {
4161 name = e.name; 4160 name = e.name;
4162 } 4161 }
4163 return _emitMemberName(name, 4162 return _emitMemberName(name,
4164 type: (e.enclosingElement as ClassElement).type, 4163 type: (e.enclosingElement as ClassElement).type,
4165 unary: e.parameters.isEmpty, 4164 unary: e.parameters.isEmpty,
4166 isStatic: e.isStatic, 4165 isStatic: e.isStatic,
4167 allowExtensions: allowExtensions); 4166 useExtension: useExtension);
4168 } 4167 }
4169 4168
4170 /// This handles member renaming for private names and operators. 4169 /// This handles member renaming for private names and operators.
4171 /// 4170 ///
4172 /// Private names are generated using ES6 symbols: 4171 /// Private names are generated using ES6 symbols:
4173 /// 4172 ///
4174 /// // At the top of the module: 4173 /// // At the top of the module:
4175 /// let _x = Symbol('_x'); 4174 /// let _x = Symbol('_x');
4176 /// let _y = Symbol('_y'); 4175 /// let _y = Symbol('_y');
4177 /// ... 4176 /// ...
(...skipping 27 matching lines...) Expand all
4205 /// Unary minus looks like: `x['unary-']()`. Note that [unary] must be passed 4204 /// Unary minus looks like: `x['unary-']()`. Note that [unary] must be passed
4206 /// for this transformation to happen, otherwise binary minus is assumed. 4205 /// for this transformation to happen, otherwise binary minus is assumed.
4207 /// 4206 ///
4208 /// Equality is a bit special, it is generated via the Dart `equals` runtime 4207 /// Equality is a bit special, it is generated via the Dart `equals` runtime
4209 /// helper, that checks for null. The user defined method is called '=='. 4208 /// helper, that checks for null. The user defined method is called '=='.
4210 /// 4209 ///
4211 JS.Expression _emitMemberName(String name, 4210 JS.Expression _emitMemberName(String name,
4212 {DartType type, 4211 {DartType type,
4213 bool unary: false, 4212 bool unary: false,
4214 bool isStatic: false, 4213 bool isStatic: false,
4215 bool allowExtensions: true}) { 4214 bool useExtension}) {
4216 // Static members skip the rename steps. 4215 // Static members skip the rename steps.
4217 if (isStatic) return _propertyName(name); 4216 if (isStatic) return _propertyName(name);
4218 4217
4219 if (name.startsWith('_')) { 4218 if (name.startsWith('_')) {
4220 return _emitPrivateNameSymbol(currentLibrary, name); 4219 return _emitPrivateNameSymbol(currentLibrary, name);
4221 } 4220 }
4222 4221
4223 if (name == '[]') { 4222 if (name == '[]') {
4224 name = 'get'; 4223 name = 'get';
4225 } else if (name == '[]=') { 4224 } else if (name == '[]=') {
4226 name = 'set'; 4225 name = 'set';
4227 } else if (name == '-' && unary) { 4226 } else if (name == '-' && unary) {
4228 name = 'unary-'; 4227 name = 'unary-';
4229 } else if (name == 'constructor' || name == 'prototype') { 4228 } else if (name == 'constructor' || name == 'prototype') {
4230 // This uses an illegal (in Dart) character for a member, avoiding the 4229 // This uses an illegal (in Dart) character for a member, avoiding the
4231 // conflict. We could use practically any character for this. 4230 // conflict. We could use practically any character for this.
4232 name = '+$name'; 4231 name = '+$name';
4233 } 4232 }
4234 4233
4235 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. 4234 var result = _propertyName(name);
4236 var baseType = type; 4235
4237 while (baseType is TypeParameterType) { 4236 if (useExtension == null) {
4238 baseType = baseType.element.bound; 4237 // Dart "extension" methods. Used for JS Array, Boolean, Number, String.
4239 } 4238 var baseType = type;
4240 if (allowExtensions && 4239 while (baseType is TypeParameterType) {
4241 baseType != null && 4240 baseType = baseType.element.bound;
4242 _extensionTypes.hasNativeSubtype(baseType) && 4241 }
4243 !isObjectProperty(name)) { 4242 useExtension = baseType != null &&
4244 return js.call('dartx.#', _propertyName(name)); 4243 _extensionTypes.hasNativeSubtype(baseType) &&
4244 !isObjectMember(name);
4245 } 4245 }
4246 4246
4247 return _propertyName(name); 4247 return useExtension ? js.call('dartx.#', result) : result;
4248 } 4248 }
4249 4249
4250 JS.TemporaryId _emitPrivateNameSymbol(LibraryElement library, String name) { 4250 JS.TemporaryId _emitPrivateNameSymbol(LibraryElement library, String name) {
4251 return _privateNames 4251 return _privateNames
4252 .putIfAbsent(library, () => new HashMap()) 4252 .putIfAbsent(library, () => new HashMap())
4253 .putIfAbsent(name, () { 4253 .putIfAbsent(name, () {
4254 var id = new JS.TemporaryId(name); 4254 var id = new JS.TemporaryId(name);
4255 _moduleItems.add( 4255 _moduleItems.add(
4256 js.statement('const # = Symbol(#);', [id, js.string(id.name, "'")])); 4256 js.statement('const # = Symbol(#);', [id, js.string(id.name, "'")]));
4257 return id; 4257 return id;
(...skipping 25 matching lines...) Expand all
4283 } 4283 }
4284 4284
4285 /// Returns true if this is any kind of object represented by `Number` in JS. 4285 /// Returns true if this is any kind of object represented by `Number` in JS.
4286 /// 4286 ///
4287 /// In practice, this is 4 types: num, int, double, and JSNumber. 4287 /// In practice, this is 4 types: num, int, double, and JSNumber.
4288 /// 4288 ///
4289 /// JSNumber is the type that actually "implements" all numbers, hence it's 4289 /// JSNumber is the type that actually "implements" all numbers, hence it's
4290 /// a subtype of int and double (and num). It's in our "dart:_interceptors". 4290 /// a subtype of int and double (and num). It's in our "dart:_interceptors".
4291 bool _isNumberInJS(DartType t) => rules.isSubtypeOf(t, types.numType); 4291 bool _isNumberInJS(DartType t) => rules.isSubtypeOf(t, types.numType);
4292 4292
4293 bool _isObjectGetter(String name) { 4293 /// Return true if this is one of the methods/properties on all Dart Objects
4294 PropertyAccessorElement element = types.objectType.element.getGetter(name); 4294 /// (toString, hashCode, noSuchMethod, runtimeType).
4295 return (element != null && !element.isStatic); 4295 ///
4296 } 4296 /// Operator == is excluded, as it is handled as part of the equality binary
4297 4297 /// operator.
4298 bool _isObjectMethod(String name) { 4298 bool isObjectMember(String name) {
4299 MethodElement element = types.objectType.element.getMethod(name); 4299 // We could look these up on Object, but we have hard coded runtime helpers
4300 return (element != null && !element.isStatic); 4300 // so it's not really providing any benefit.
4301 } 4301 switch (name) {
4302 4302 case 'hashCode':
4303 bool isObjectProperty(String name) { 4303 case 'toString':
4304 return _isObjectGetter(name) || _isObjectMethod(name); 4304 case 'noSuchMethod':
4305 case 'runtimeType':
4306 return true;
4307 }
4308 return false;
4305 } 4309 }
4306 4310
4307 // TODO(leafp): Various analyzer pieces computed similar things. 4311 // TODO(leafp): Various analyzer pieces computed similar things.
4308 // Share this logic somewhere? 4312 // Share this logic somewhere?
4309 DartType _getExpectedReturnType(ExecutableElement element) { 4313 DartType _getExpectedReturnType(ExecutableElement element) {
4310 FunctionType functionType = element.type; 4314 FunctionType functionType = element.type;
4311 if (functionType == null) { 4315 if (functionType == null) {
4312 return DynamicTypeImpl.instance; 4316 return DynamicTypeImpl.instance;
4313 } 4317 }
4314 var type = functionType.returnType; 4318 var type = functionType.returnType;
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
4394 } 4398 }
4395 4399
4396 bool isLibraryPrefix(Expression node) => 4400 bool isLibraryPrefix(Expression node) =>
4397 node is SimpleIdentifier && node.staticElement is PrefixElement; 4401 node is SimpleIdentifier && node.staticElement is PrefixElement;
4398 4402
4399 LibraryElement _getLibrary(AnalysisContext c, String uri) => 4403 LibraryElement _getLibrary(AnalysisContext c, String uri) =>
4400 c.computeLibraryElement(c.sourceFactory.forUri(uri)); 4404 c.computeLibraryElement(c.sourceFactory.forUri(uri));
4401 4405
4402 bool _isDartRuntime(LibraryElement l) => 4406 bool _isDartRuntime(LibraryElement l) =>
4403 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; 4407 l.isInSdk && l.source.uri.toString() == 'dart:_runtime';
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698