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

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

Issue 2435223002: fix #27644, allow "dart" and "dartx" to be renamed if needed (Closed)
Patch Set: Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | pkg/dev_compiler/lib/src/compiler/type_utilities.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 2
3 // for details. All rights reserved. Use of this source code is governed by a 3 // for details. All rights reserved. Use of this source code is governed by a
4 // BSD-style license that can be found in the LICENSE file. 4 // BSD-style license that can be found in the LICENSE file.
5 5
6 import 'dart:collection' show HashMap, HashSet; 6 import 'dart:collection' show HashMap, HashSet;
7 import 'dart:math' show min, max; 7 import 'dart:math' show min, max;
8 8
9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
10 import 'package:analyzer/dart/ast/ast.dart'; 10 import 'package:analyzer/dart/ast/ast.dart';
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 /// name scoping requirements. 67 /// name scoping requirements.
68 final _libraries = new Map<LibraryElement, JS.Identifier>(); 68 final _libraries = new Map<LibraryElement, JS.Identifier>();
69 69
70 /// Imported libraries, and the temporaries used to refer to them. 70 /// Imported libraries, and the temporaries used to refer to them.
71 final _imports = new Map<LibraryElement, JS.TemporaryId>(); 71 final _imports = new Map<LibraryElement, JS.TemporaryId>();
72 72
73 /// The list of output module items, in the order they need to be emitted in. 73 /// The list of output module items, in the order they need to be emitted in.
74 final _moduleItems = <JS.ModuleItem>[]; 74 final _moduleItems = <JS.ModuleItem>[];
75 75
76 /// Table of named and possibly hoisted types. 76 /// Table of named and possibly hoisted types.
77 final _typeTable = new TypeTable(); 77 TypeTable _typeTable;
78 78
79 /// The global extension type table. 79 /// The global extension type table.
80 final ExtensionTypeSet _extensionTypes; 80 final ExtensionTypeSet _extensionTypes;
81 81
82 /// The variable for the target of the current `..` cascade expression. 82 /// The variable for the target of the current `..` cascade expression.
83 /// 83 ///
84 /// Usually a [SimpleIdentifier], but it can also be other expressions 84 /// Usually a [SimpleIdentifier], but it can also be other expressions
85 /// that are safe to evaluate multiple times, such as `this`. 85 /// that are safe to evaluate multiple times, such as `this`.
86 Expression _cascadeTarget; 86 Expression _cascadeTarget;
87 87
88 /// The variable for the current catch clause 88 /// The variable for the current catch clause
89 SimpleIdentifier _catchParameter; 89 SimpleIdentifier _catchParameter;
90 90
91 /// In an async* function, this represents the stream controller parameter. 91 /// In an async* function, this represents the stream controller parameter.
92 JS.TemporaryId _asyncStarController; 92 JS.TemporaryId _asyncStarController;
93 93
94 // TODO(jmesserly): fuse this with notNull check. 94 // TODO(jmesserly): fuse this with notNull check.
95 final _privateNames = 95 final _privateNames =
96 new HashMap<LibraryElement, HashMap<String, JS.TemporaryId>>(); 96 new HashMap<LibraryElement, HashMap<String, JS.TemporaryId>>();
97 final _initializingFormalTemps = 97 final _initializingFormalTemps =
98 new HashMap<ParameterElement, JS.TemporaryId>(); 98 new HashMap<ParameterElement, JS.TemporaryId>();
99 99
100 final _dartxVar = new JS.Identifier('dartx'); 100 JS.Identifier _extensionSymbolsModule;
101 final _runtimeLibVar = new JS.Identifier('dart'); 101 JS.Identifier _runtimeModule;
102 final namedArgumentTemp = new JS.TemporaryId('opts'); 102 final namedArgumentTemp = new JS.TemporaryId('opts');
103 103
104 final _hasDeferredSupertype = new HashSet<ClassElement>(); 104 final _hasDeferredSupertype = new HashSet<ClassElement>();
105 105
106 final _eagerTopLevelFields = new HashSet<Element>.identity(); 106 final _eagerTopLevelFields = new HashSet<Element>.identity();
107 107
108 /// The type provider from the current Analysis [context]. 108 /// The type provider from the current Analysis [context].
109 final TypeProvider types; 109 final TypeProvider types;
110 110
111 final LibraryElement dartCoreLibrary; 111 final LibraryElement dartCoreLibrary;
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
224 } 224 }
225 225
226 JS.Program _emitModule(List<CompilationUnit> compilationUnits) { 226 JS.Program _emitModule(List<CompilationUnit> compilationUnits) {
227 if (_moduleItems.isNotEmpty) { 227 if (_moduleItems.isNotEmpty) {
228 throw new StateError('Can only call emitModule once.'); 228 throw new StateError('Can only call emitModule once.');
229 } 229 }
230 230
231 // Transform the AST to make coercions explicit. 231 // Transform the AST to make coercions explicit.
232 compilationUnits = CoercionReifier.reify(compilationUnits); 232 compilationUnits = CoercionReifier.reify(compilationUnits);
233 233
234 if (compilationUnits.any((u) => _isDartRuntime(u.element.library))) {
235 // Don't allow these to be renamed when we're building the SDK.
236 // There is JS code in dart:* that depends on their names.
237 _runtimeModule = new JS.Identifier('dart');
238 _extensionSymbolsModule = new JS.Identifier('dartx');
239 } else {
240 // Otherwise allow these to be renamed so users can write them.
241 _runtimeModule = new JS.TemporaryId('dart');
242 _extensionSymbolsModule = new JS.TemporaryId('dartx');
243 }
244 _typeTable = new TypeTable(_runtimeModule);
245
234 // Initialize our library variables. 246 // Initialize our library variables.
235 var items = <JS.ModuleItem>[]; 247 var items = <JS.ModuleItem>[];
236 for (var unit in compilationUnits) { 248 for (var unit in compilationUnits) {
237 var library = unit.element.library; 249 var library = unit.element.library;
238 if (unit.element != library.definingCompilationUnit) continue; 250 if (unit.element != library.definingCompilationUnit) continue;
239 251
240 var libraryTemp = _isDartRuntime(library) 252 var libraryTemp = _isDartRuntime(library)
241 ? _runtimeLibVar 253 ? _runtimeModule
242 : new JS.TemporaryId(jsLibraryName(_libraryRoot, library)); 254 : new JS.TemporaryId(jsLibraryName(_libraryRoot, library));
243 _libraries[library] = libraryTemp; 255 _libraries[library] = libraryTemp;
244 items.add(new JS.ExportDeclaration( 256 items.add(new JS.ExportDeclaration(
245 js.call('const # = Object.create(null)', [libraryTemp]))); 257 js.call('const # = Object.create(null)', [libraryTemp])));
246 258
247 // dart:_runtime has a magic module that holds extension method symbols. 259 // dart:_runtime has a magic module that holds extension method symbols.
248 // TODO(jmesserly): find a cleaner design for this. 260 // TODO(jmesserly): find a cleaner design for this.
249 if (_isDartRuntime(library)) { 261 if (_isDartRuntime(library)) {
250 items.add(new JS.ExportDeclaration( 262 items.add(new JS.ExportDeclaration(js
251 js.call('const # = Object.create(null)', [_dartxVar]))); 263 .call('const # = Object.create(null)', [_extensionSymbolsModule])));
252 } 264 }
253 } 265 }
254 266
255 // Collect all Element -> Node mappings, in case we need to forward declare 267 // Collect all Element -> Node mappings, in case we need to forward declare
256 // any nodes. 268 // any nodes.
257 var nodes = new HashMap<Element, AstNode>.identity(); 269 var nodes = new HashMap<Element, AstNode>.identity();
258 var sdkBootstrappingFns = new List<FunctionElement>(); 270 var sdkBootstrappingFns = new List<FunctionElement>();
259 for (var unit in compilationUnits) { 271 for (var unit in compilationUnits) {
260 if (_isDartRuntime(unit.element.library)) { 272 if (_isDartRuntime(unit.element.library)) {
261 sdkBootstrappingFns.addAll(unit.element.functions); 273 sdkBootstrappingFns.addAll(unit.element.functions);
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
325 elementJSParts.add(e.name); 337 elementJSParts.add(e.name);
326 } 338 }
327 339
328 return libraryPrefix..addAll(elementJSParts); 340 return libraryPrefix..addAll(elementJSParts);
329 } 341 }
330 342
331 JS.Expression _emitJSInterop(Element e) { 343 JS.Expression _emitJSInterop(Element e) {
332 var jsName = _getJSName(e); 344 var jsName = _getJSName(e);
333 if (jsName == null) return null; 345 if (jsName == null) return null;
334 var fullName = ['global']..addAll(jsName); 346 var fullName = ['global']..addAll(jsName);
335 JS.Expression access = _runtimeLibVar; 347 JS.Expression access = _runtimeModule;
336 for (var part in fullName) { 348 for (var part in fullName) {
337 access = new JS.PropertyAccess(access, js.string(part)); 349 access = new JS.PropertyAccess(access, js.string(part));
338 } 350 }
339 return access; 351 return access;
340 } 352 }
341 353
342 /// Flattens blocks in [items] to a single list. 354 /// Flattens blocks in [items] to a single list.
343 /// 355 ///
344 /// This will not flatten blocks that are marked as being scopes. 356 /// This will not flatten blocks that are marked as being scopes.
345 void _copyAndFlattenBlocks( 357 void _copyAndFlattenBlocks(
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
384 // Our import variables are temps and can get renamed. Since our renaming 396 // Our import variables are temps and can get renamed. Since our renaming
385 // is integrated into js_ast, it is aware of this possibility and will 397 // is integrated into js_ast, it is aware of this possibility and will
386 // generate an "as" if needed. For example: 398 // generate an "as" if needed. For example:
387 // 399 //
388 // import {foo} from 'foo'; // if no rename needed 400 // import {foo} from 'foo'; // if no rename needed
389 // import {foo as foo$} from 'foo'; // if rename was needed 401 // import {foo as foo$} from 'foo'; // if rename was needed
390 // 402 //
391 var imports = 403 var imports =
392 libraries.map((l) => new JS.NameSpecifier(_imports[l])).toList(); 404 libraries.map((l) => new JS.NameSpecifier(_imports[l])).toList();
393 if (module == coreModuleName) { 405 if (module == coreModuleName) {
394 imports.add(new JS.NameSpecifier(_runtimeLibVar)); 406 imports.add(new JS.NameSpecifier(_runtimeModule));
395 imports.add(new JS.NameSpecifier(_dartxVar)); 407 imports.add(new JS.NameSpecifier(_extensionSymbolsModule));
396 } 408 }
397 items.add(new JS.ImportDeclaration( 409 items.add(new JS.ImportDeclaration(
398 namedImports: imports, from: js.string(module, "'"))); 410 namedImports: imports, from: js.string(module, "'")));
399 }); 411 });
400 } 412 }
401 413
402 /// Collect toplevel elements and nodes we need to emit, and returns 414 /// Collect toplevel elements and nodes we need to emit, and returns
403 /// an ordered map of these. 415 /// an ordered map of these.
404 static void _collectElements( 416 static void _collectElements(
405 CompilationUnit unit, Map<Element, AstNode> map) { 417 CompilationUnit unit, Map<Element, AstNode> map) {
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
501 _eagerTopLevelFields.contains(export)) { 513 _eagerTopLevelFields.contains(export)) {
502 // classes, typedefs, functions, and eager init fields can be assigned 514 // classes, typedefs, functions, and eager init fields can be assigned
503 // directly. 515 // directly.
504 // TODO(jmesserly): we don't know about eager init fields from other 516 // TODO(jmesserly): we don't know about eager init fields from other
505 // modules we import, so we will never go down this code path for them. 517 // modules we import, so we will never go down this code path for them.
506 _moduleItems 518 _moduleItems
507 .add(js.statement('#.# = #;', [libraryName, name.selector, name])); 519 .add(js.statement('#.# = #;', [libraryName, name.selector, name]));
508 } else { 520 } else {
509 // top-level fields, getters, setters need to copy the property 521 // top-level fields, getters, setters need to copy the property
510 // descriptor. 522 // descriptor.
511 _moduleItems.add(js.statement('dart.export(#, #, #);', 523 _moduleItems.add(_callHelperStatement(
512 [libraryName, name.receiver, name.selector])); 524 'export(#, #, #);', [libraryName, name.receiver, name.selector]));
513 } 525 }
514 } 526 }
515 527
516 for (var export in exportedNames.definedNames.values) { 528 for (var export in exportedNames.definedNames.values) {
517 if (export is PropertyAccessorElement) { 529 if (export is PropertyAccessorElement) {
518 export = (export as PropertyAccessorElement).variable; 530 export = (export as PropertyAccessorElement).variable;
519 } 531 }
520 532
521 // Don't allow redefining names from this library. 533 // Don't allow redefining names from this library.
522 if (currentNames.containsKey(export.name)) continue; 534 if (currentNames.containsKey(export.name)) continue;
(...skipping 23 matching lines...) Expand all
546 if (_inWhitelistCode(node)) return jsFrom; 558 if (_inWhitelistCode(node)) return jsFrom;
547 559
548 // Skip the cast if it's not needed. 560 // Skip the cast if it's not needed.
549 if (rules.isSubtypeOf(from, to)) return jsFrom; 561 if (rules.isSubtypeOf(from, to)) return jsFrom;
550 562
551 // All Dart number types map to a JS double. 563 // All Dart number types map to a JS double.
552 if (_isNumberInJS(from) && _isNumberInJS(to)) { 564 if (_isNumberInJS(from) && _isNumberInJS(to)) {
553 // Make sure to check when converting to int. 565 // Make sure to check when converting to int.
554 if (from != types.intType && to == types.intType) { 566 if (from != types.intType && to == types.intType) {
555 // TODO(jmesserly): fuse this with notNull check. 567 // TODO(jmesserly): fuse this with notNull check.
556 return js.call('dart.asInt(#)', jsFrom); 568 return _callHelper('asInt(#)', jsFrom);
557 } 569 }
558 570
559 // A no-op in JavaScript. 571 // A no-op in JavaScript.
560 return jsFrom; 572 return jsFrom;
561 } 573 }
562 574
563 var type = _emitType(to, 575 var type = _emitType(to,
564 nameType: options.nameTypeTests || options.hoistTypeTests, 576 nameType: options.nameTypeTests || options.hoistTypeTests,
565 hoistType: options.hoistTypeTests); 577 hoistType: options.hoistTypeTests);
566 if (CoercionReifier.isImplicitCast(node)) { 578 if (CoercionReifier.isImplicitCast(node)) {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
600 if (t == types.stringType) return 'string'; 612 if (t == types.stringType) return 'string';
601 if (t == types.boolType) return 'boolean'; 613 if (t == types.boolType) return 'boolean';
602 return null; 614 return null;
603 } 615 }
604 616
605 @override 617 @override
606 visitFunctionTypeAlias(FunctionTypeAlias node) { 618 visitFunctionTypeAlias(FunctionTypeAlias node) {
607 FunctionTypeAliasElement element = node.element; 619 FunctionTypeAliasElement element = node.element;
608 620
609 JS.Expression body = annotate( 621 JS.Expression body = annotate(
610 js.call('dart.typedef(#, () => #)', [ 622 _callHelper('typedef(#, () => #)', [
611 js.string(element.name, "'"), 623 js.string(element.name, "'"),
612 _emitType(element.type, nameType: false, lowerTypedef: true) 624 _emitType(element.type, nameType: false, lowerTypedef: true)
613 ]), 625 ]),
614 node, 626 node,
615 element); 627 element);
616 628
617 var typeFormals = element.typeParameters; 629 var typeFormals = element.typeParameters;
618 if (typeFormals.isNotEmpty) { 630 if (typeFormals.isNotEmpty) {
619 return _defineClassTypeArguments(element, typeFormals, 631 return _defineClassTypeArguments(element, typeFormals,
620 js.statement('const # = #;', [element.name, body])); 632 js.statement('const # = #;', [element.name, body]));
621 } else { 633 } else {
622 return js.statement('# = #;', [_emitTopLevelName(element), body]); 634 return js.statement('# = #;', [_emitTopLevelName(element), body]);
623 } 635 }
624 } 636 }
625 637
626 @override 638 @override
627 JS.Expression visitTypeName(TypeName node) { 639 JS.Expression visitTypeName(TypeName node) {
628 if (node.type == null) { 640 if (node.type == null) {
629 // TODO(jmesserly): if the type fails to resolve, should we generate code 641 // TODO(jmesserly): if the type fails to resolve, should we generate code
630 // that throws instead? 642 // that throws instead?
631 assert(options.unsafeForceCompile || options.replCompile); 643 assert(options.unsafeForceCompile || options.replCompile);
632 return js.call('dart.dynamic'); 644 return _callHelper('dynamic');
633 } 645 }
634 return _emitType(node.type); 646 return _emitType(node.type);
635 } 647 }
636 648
637 @override 649 @override
638 JS.Statement visitClassTypeAlias(ClassTypeAlias node) { 650 JS.Statement visitClassTypeAlias(ClassTypeAlias node) {
639 ClassElement element = node.element; 651 ClassElement element = node.element;
640 652
641 // Forward all generative constructors from the base class. 653 // Forward all generative constructors from the base class.
642 var methods = <JS.Method>[]; 654 var methods = <JS.Method>[];
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
787 /// constructor. 799 /// constructor.
788 /// 800 ///
789 /// This ensures instances created by the unnamed constructor are functions. 801 /// This ensures instances created by the unnamed constructor are functions.
790 /// Named constructors are handled elsewhere, see [_defineNamedConstructors]. 802 /// Named constructors are handled elsewhere, see [_defineNamedConstructors].
791 JS.Expression _emitCallableClass( 803 JS.Expression _emitCallableClass(
792 JS.ClassExpression classExpr, ConstructorElement unnamedCtor) { 804 JS.ClassExpression classExpr, ConstructorElement unnamedCtor) {
793 var ctor = new JS.NamedFunction( 805 var ctor = new JS.NamedFunction(
794 classExpr.name, _emitCallableClassConstructor(unnamedCtor)); 806 classExpr.name, _emitCallableClassConstructor(unnamedCtor));
795 807
796 // Name the constructor function the same as the class. 808 // Name the constructor function the same as the class.
797 return js.call('dart.callableClass(#, #)', [ctor, classExpr]); 809 return _callHelper('callableClass(#, #)', [ctor, classExpr]);
798 } 810 }
799 811
800 /// Emits a constructor that ensures instances of this class are callable as 812 /// Emits a constructor that ensures instances of this class are callable as
801 /// functions in JavaScript. 813 /// functions in JavaScript.
802 JS.Fun _emitCallableClassConstructor(ConstructorElement ctor) { 814 JS.Fun _emitCallableClassConstructor(ConstructorElement ctor) {
803 return js.call( 815 return js.call(
804 r'''function (...args) { 816 r'''function (...args) {
805 function call(...args) { 817 function call(...args) {
806 return call.call.apply(call, args); 818 return call.call.apply(call, args);
807 } 819 }
(...skipping 10 matching lines...) Expand all
818 // We rely on ES6 static inheritance. All types that are represented by 830 // We rely on ES6 static inheritance. All types that are represented by
819 // class constructor functions will see these definitions, with [this] 831 // class constructor functions will see these definitions, with [this]
820 // being bound to the class constructor. 832 // being bound to the class constructor.
821 833
822 // The 'instanceof' checks don't work for primitive types (which have fast 834 // The 'instanceof' checks don't work for primitive types (which have fast
823 // definitions below) and don't work for native types. In those cases we 835 // definitions below) and don't work for native types. In those cases we
824 // fall through to the general purpose checking code. 836 // fall through to the general purpose checking code.
825 body.add(js.statement( 837 body.add(js.statement(
826 '#.is = function is_Object(o) {' 838 '#.is = function is_Object(o) {'
827 ' if (o instanceof this) return true;' 839 ' if (o instanceof this) return true;'
828 ' return dart.is(o, this);' 840 ' return #.is(o, this);'
829 '}', 841 '}',
830 className)); 842 [className, _runtimeModule]));
831 body.add(js.statement( 843 body.add(js.statement(
832 '#.as = function as_Object(o) {' 844 '#.as = function as_Object(o) {'
833 ' if (o == null || o instanceof this) return o;' 845 ' if (o == null || o instanceof this) return o;'
834 ' return dart.as(o, this);' 846 ' return #.as(o, this);'
835 '}', 847 '}',
836 className)); 848 [className, _runtimeModule]));
837 body.add(js.statement( 849 body.add(js.statement(
838 '#._check = function check_Object(o) {' 850 '#._check = function check_Object(o) {'
839 ' if (o == null || o instanceof this) return o;' 851 ' if (o == null || o instanceof this) return o;'
840 ' return dart.check(o, this);' 852 ' return #.check(o, this);'
841 '}', 853 '}',
842 className)); 854 [className, _runtimeModule]));
843 return; 855 return;
844 } 856 }
845 if (classElem == stringClass) { 857 if (classElem == stringClass) {
846 body.add(js.statement( 858 body.add(js.statement(
847 '#.is = function is_String(o) { return typeof o == "string"; }', 859 '#.is = function is_String(o) { return typeof o == "string"; }',
848 className)); 860 className));
849 body.add(js.statement( 861 body.add(js.statement(
850 '#.as = function as_String(o) {' 862 '#.as = function as_String(o) {'
851 ' if (typeof o == "string" || o == null) return o;' 863 ' if (typeof o == "string" || o == null) return o;'
852 ' return dart.as(o, #);' 864 ' return #.as(o, #);'
853 '}', 865 '}',
854 [className, className])); 866 [className, _runtimeModule, className]));
855 body.add(js.statement( 867 body.add(js.statement(
856 '#._check = function check_String(o) {' 868 '#._check = function check_String(o) {'
857 ' if (typeof o == "string" || o == null) return o;' 869 ' if (typeof o == "string" || o == null) return o;'
858 ' return dart.check(o, #);' 870 ' return #.check(o, #);'
859 '}', 871 '}',
860 [className, className])); 872 [className, _runtimeModule, className]));
861 return; 873 return;
862 } 874 }
863 if (classElem == intClass) { 875 if (classElem == intClass) {
864 body.add(js.statement( 876 body.add(js.statement(
865 '#.is = function is_int(o) {' 877 '#.is = function is_int(o) {'
866 ' return typeof o == "number" && Math.floor(o) == o;' 878 ' return typeof o == "number" && Math.floor(o) == o;'
867 '}', 879 '}',
868 className)); 880 className));
869 body.add(js.statement( 881 body.add(js.statement(
870 '#.as = function as_int(o) {' 882 '#.as = function as_int(o) {'
871 ' if ((typeof o == "number" && Math.floor(o) == o) || o == null)' 883 ' if ((typeof o == "number" && Math.floor(o) == o) || o == null)'
872 ' return o;' 884 ' return o;'
873 ' return dart.as(o, #);' 885 ' return #.as(o, #);'
874 '}', 886 '}',
875 [className, className])); 887 [className, _runtimeModule, className]));
876 body.add(js.statement( 888 body.add(js.statement(
877 '#._check = function check_int(o) {' 889 '#._check = function check_int(o) {'
878 ' if ((typeof o == "number" && Math.floor(o) == o) || o == null)' 890 ' if ((typeof o == "number" && Math.floor(o) == o) || o == null)'
879 ' return o;' 891 ' return o;'
880 ' return dart.check(o, #);' 892 ' return #.check(o, #);'
881 '}', 893 '}',
882 [className, className])); 894 [className, _runtimeModule, className]));
883 return; 895 return;
884 } 896 }
885 if (classElem == nullClass) { 897 if (classElem == nullClass) {
886 body.add(js.statement( 898 body.add(js.statement(
887 '#.is = function is_Null(o) { return o == null; }', className)); 899 '#.is = function is_Null(o) { return o == null; }', className));
888 body.add(js.statement( 900 body.add(js.statement(
889 '#.as = function as_Null(o) {' 901 '#.as = function as_Null(o) {'
890 ' if (o == null) return o;' 902 ' if (o == null) return o;'
891 ' return dart.as(o, #);' 903 ' return #.as(o, #);'
892 '}', 904 '}',
893 [className, className])); 905 [className, _runtimeModule, className]));
894 body.add(js.statement( 906 body.add(js.statement(
895 '#._check = function check_Null(o) {' 907 '#._check = function check_Null(o) {'
896 ' if (o == null) return o;' 908 ' if (o == null) return o;'
897 ' return dart.check(o, #);' 909 ' return #.check(o, #);'
898 '}', 910 '}',
899 [className, className])); 911 [className, _runtimeModule, className]));
900 return; 912 return;
901 } 913 }
902 if (classElem == numClass) { 914 if (classElem == numClass) {
903 body.add(js.statement( 915 body.add(js.statement(
904 '#.is = function is_num(o) { return typeof o == "number"; }', 916 '#.is = function is_num(o) { return typeof o == "number"; }',
905 className)); 917 className));
906 body.add(js.statement( 918 body.add(js.statement(
907 '#.as = function as_num(o) {' 919 '#.as = function as_num(o) {'
908 ' if (typeof o == "number" || o == null) return o;' 920 ' if (typeof o == "number" || o == null) return o;'
909 ' return dart.as(o, #);' 921 ' return #.as(o, #);'
910 '}', 922 '}',
911 [className, className])); 923 [className, _runtimeModule, className]));
912 body.add(js.statement( 924 body.add(js.statement(
913 '#._check = function check_num(o) {' 925 '#._check = function check_num(o) {'
914 ' if (typeof o == "number" || o == null) return o;' 926 ' if (typeof o == "number" || o == null) return o;'
915 ' return dart.check(o, #);' 927 ' return #.check(o, #);'
916 '}', 928 '}',
917 [className, className])); 929 [className, _runtimeModule, className]));
918 return; 930 return;
919 } 931 }
920 if (classElem == boolClass) { 932 if (classElem == boolClass) {
921 body.add(js.statement( 933 body.add(js.statement(
922 '#.is = function is_bool(o) { return o === true || o === false; }', 934 '#.is = function is_bool(o) { return o === true || o === false; }',
923 className)); 935 className));
924 body.add(js.statement( 936 body.add(js.statement(
925 '#.as = function as_bool(o) {' 937 '#.as = function as_bool(o) {'
926 ' if (o === true || o === false || o == null) return o;' 938 ' if (o === true || o === false || o == null) return o;'
927 ' return dart.as(o, #);' 939 ' return #.as(o, #);'
928 '}', 940 '}',
929 [className, className])); 941 [className, _runtimeModule, className]));
930 body.add(js.statement( 942 body.add(js.statement(
931 '#._check = function check_bool(o) {' 943 '#._check = function check_bool(o) {'
932 ' if (o === true || o === false || o == null) return o;' 944 ' if (o === true || o === false || o == null) return o;'
933 ' return dart.check(o, #);' 945 ' return #.check(o, #);'
934 '}', 946 '}',
935 [className, className])); 947 [className, _runtimeModule, className]));
936 return; 948 return;
937 } 949 }
938 // TODO(sra): Add special cases for hot tests like `x is html.Element`. 950 // TODO(sra): Add special cases for hot tests like `x is html.Element`.
939 951
940 // `instanceof` check is futile for classes that are Interceptor classes. 952 // `instanceof` check is futile for classes that are Interceptor classes.
941 ClassElement parent = classElem; 953 ClassElement parent = classElem;
942 while (parent != objectClass) { 954 while (parent != objectClass) {
943 if (parent == interceptorClass) { 955 if (parent == interceptorClass) {
944 if (classElem == interceptorClass) { 956 if (classElem == interceptorClass) {
945 // Place non-instanceof version of checks on Interceptor. All 957 // Place non-instanceof version of checks on Interceptor. All
946 // interceptor classes will inherit the methods via ES6 class static 958 // interceptor classes will inherit the methods via ES6 class static
947 // inheritance. 959 // inheritance.
948 body.add(js.statement('dart.addTypeTests(#);', className)); 960 body.add(_callHelperStatement('addTypeTests(#);', className));
949 961
950 // TODO(sra): We could place on the extension type a pointer to the 962 // TODO(sra): We could place on the extension type a pointer to the
951 // peer constructor and use that for the `instanceof` check, e.g. 963 // peer constructor and use that for the `instanceof` check, e.g.
952 // 964 //
953 // if (o instanceof this[_peerConstructor]) return o; 965 // if (o instanceof this[_peerConstructor]) return o;
954 // 966 //
955 } 967 }
956 return; 968 return;
957 } 969 }
958 parent = parent.type.superclass.element; 970 parent = parent.type.superclass.element;
(...skipping 17 matching lines...) Expand all
976 return true; 988 return true;
977 } 989 }
978 990
979 assert(classElem != objectClass); 991 assert(classElem != objectClass);
980 bool thisIsSimple = isSimple(classElem); 992 bool thisIsSimple = isSimple(classElem);
981 bool superIsSimple = isSimple(classElem.type.superclass.element); 993 bool superIsSimple = isSimple(classElem.type.superclass.element);
982 994
983 if (thisIsSimple == superIsSimple) return; 995 if (thisIsSimple == superIsSimple) return;
984 996
985 if (thisIsSimple) { 997 if (thisIsSimple) {
986 body.add(js.statement('dart.addSimpleTypeTests(#);', className)); 998 body.add(_callHelperStatement('addSimpleTypeTests(#);', className));
987 } else { 999 } else {
988 body.add(js.statement('dart.addTypeTests(#);', className)); 1000 body.add(_callHelperStatement('addTypeTests(#);', className));
989 } 1001 }
990 } 1002 }
991 1003
992 void _emitSuperHelperSymbols( 1004 void _emitSuperHelperSymbols(
993 List<JS.TemporaryId> superHelperSymbols, List<JS.Statement> body) { 1005 List<JS.TemporaryId> superHelperSymbols, List<JS.Statement> body) {
994 for (var id in superHelperSymbols) { 1006 for (var id in superHelperSymbols) {
995 body.add(js.statement('const # = Symbol(#)', [id, js.string(id.name)])); 1007 body.add(js.statement('const # = Symbol(#)', [id, js.string(id.name)]));
996 } 1008 }
997 superHelperSymbols.clear(); 1009 superHelperSymbols.clear();
998 } 1010 }
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
1096 // Create enum class 1108 // Create enum class
1097 var classExpr = new JS.ClassExpression(new JS.Identifier(type.name), 1109 var classExpr = new JS.ClassExpression(new JS.Identifier(type.name),
1098 _emitClassHeritage(element), [constructor, toStringF]); 1110 _emitClassHeritage(element), [constructor, toStringF]);
1099 var id = _emitTopLevelName(element); 1111 var id = _emitTopLevelName(element);
1100 var result = [ 1112 var result = [
1101 js.statement('# = #', [id, classExpr]) 1113 js.statement('# = #', [id, classExpr])
1102 ]; 1114 ];
1103 1115
1104 // Create static fields for each enum value 1116 // Create static fields for each enum value
1105 for (var i = 0; i < fields.length; ++i) { 1117 for (var i = 0; i < fields.length; ++i) {
1106 result.add(js.statement('#.# = dart.const(new #(#));', 1118 result.add(js.statement('#.# = #.const(new #(#));',
1107 [id, fields[i].name, id, js.number(i)])); 1119 [id, fields[i].name, _runtimeModule, id, js.number(i)]));
1108 } 1120 }
1109 1121
1110 // Create static values list 1122 // Create static values list
1111 var values = new JS.ArrayInitializer(new List<JS.Expression>.from( 1123 var values = new JS.ArrayInitializer(new List<JS.Expression>.from(
1112 fields.map((f) => js.call('#.#', [id, f.name])))); 1124 fields.map((f) => js.call('#.#', [id, f.name]))));
1113 1125
1114 // dart.constList helper internally depends on _interceptors.JSArray. 1126 // dart.constList helper internally depends on _interceptors.JSArray.
1115 _declareBeforeUse(_jsArray); 1127 _declareBeforeUse(_jsArray);
1116 1128
1117 result.add(js.statement( 1129 result.add(js.statement('#.values = #.constList(#, #);',
1118 '#.values = dart.constList(#, #);', [id, values, _emitType(type)])); 1130 [id, _runtimeModule, values, _emitType(type)]));
1119 1131
1120 return _statement(result); 1132 return _statement(result);
1121 } 1133 }
1122 1134
1123 /// Wraps a possibly generic class in its type arguments. 1135 /// Wraps a possibly generic class in its type arguments.
1124 JS.Statement _defineClassTypeArguments(TypeDefiningElement element, 1136 JS.Statement _defineClassTypeArguments(TypeDefiningElement element,
1125 List<TypeParameterElement> formals, JS.Statement body) { 1137 List<TypeParameterElement> formals, JS.Statement body) {
1126 assert(formals.isNotEmpty); 1138 assert(formals.isNotEmpty);
1127 var genericCall = js.call('dart.generic((#) => { #; #; return #; })', [ 1139 var genericCall = _callHelper('generic((#) => { #; #; return #; })', [
1128 _emitTypeFormals(formals), 1140 _emitTypeFormals(formals),
1129 _typeTable.discharge(formals), 1141 _typeTable.discharge(formals),
1130 body, 1142 body,
1131 element.name 1143 element.name
1132 ]); 1144 ]);
1133 if (element.library.isDartAsync && 1145 if (element.library.isDartAsync &&
1134 (element.name == "Future" || element.name == "_Future")) { 1146 (element.name == "Future" || element.name == "_Future")) {
1135 genericCall = js.call('dart.flattenFutures(#)', [genericCall]); 1147 genericCall = _callHelper('flattenFutures(#)', [genericCall]);
1136 } 1148 }
1137 var genericDef = js.statement( 1149 var genericDef = js.statement(
1138 '# = #;', [_emitTopLevelName(element, suffix: r'$'), genericCall]); 1150 '# = #;', [_emitTopLevelName(element, suffix: r'$'), genericCall]);
1139 var dynType = fillDynamicTypeArgs(element.type); 1151 var dynType = fillDynamicTypeArgs(element.type);
1140 var genericInst = _emitType(dynType, lowerGeneric: true); 1152 var genericInst = _emitType(dynType, lowerGeneric: true);
1141 return js.statement( 1153 return js.statement(
1142 '{ #; # = #; }', [genericDef, _emitTopLevelName(element), genericInst]); 1154 '{ #; # = #; }', [genericDef, _emitTopLevelName(element), genericInst]);
1143 } 1155 }
1144 1156
1145 bool _deferIfNeeded(DartType type, ClassElement current) { 1157 bool _deferIfNeeded(DartType type, ClassElement current) {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1183 _hasDeferredSupertype.add(element); 1195 _hasDeferredSupertype.add(element);
1184 } 1196 }
1185 // We could choose to name the superclasses, but it's 1197 // We could choose to name the superclasses, but it's
1186 // not clear that there's much benefit 1198 // not clear that there's much benefit
1187 heritage = _emitType(supertype, nameType: false); 1199 heritage = _emitType(supertype, nameType: false);
1188 1200
1189 if (type.mixins.isNotEmpty) { 1201 if (type.mixins.isNotEmpty) {
1190 var mixins = 1202 var mixins =
1191 type.mixins.map((t) => _emitType(t, nameType: false)).toList(); 1203 type.mixins.map((t) => _emitType(t, nameType: false)).toList();
1192 mixins.insert(0, heritage); 1204 mixins.insert(0, heritage);
1193 heritage = js.call('dart.mixin(#)', [mixins]); 1205 heritage = _callHelper('mixin(#)', [mixins]);
1194 } 1206 }
1195 1207
1196 _loader.finishTopLevel(element); 1208 _loader.finishTopLevel(element);
1197 1209
1198 return heritage; 1210 return heritage;
1199 } 1211 }
1200 1212
1201 /// Provide Dart getters and setters that forward to the underlying native 1213 /// Provide Dart getters and setters that forward to the underlying native
1202 /// field. Note that the Dart names are always symbolized to avoid 1214 /// field. Note that the Dart names are always symbolized to avoid
1203 /// conflicts. They will be installed as extension methods on the underlying 1215 /// conflicts. They will be installed as extension methods on the underlying
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
1403 var invocationProps = <JS.Property>[]; 1415 var invocationProps = <JS.Property>[];
1404 addProperty(String name, JS.Expression value) { 1416 addProperty(String name, JS.Expression value) {
1405 invocationProps.add(new JS.Property(js.string(name), value)); 1417 invocationProps.add(new JS.Property(js.string(name), value));
1406 } 1418 }
1407 1419
1408 var args = new JS.TemporaryId('args'); 1420 var args = new JS.TemporaryId('args');
1409 var fnArgs = <JS.Parameter>[]; 1421 var fnArgs = <JS.Parameter>[];
1410 JS.Expression positionalArgs; 1422 JS.Expression positionalArgs;
1411 1423
1412 if (method.type.namedParameterTypes.isNotEmpty) { 1424 if (method.type.namedParameterTypes.isNotEmpty) {
1413 addProperty( 1425 addProperty('namedArguments', _callHelper('extractNamedArgs(#)', [args]));
1414 'namedArguments', js.call('dart.extractNamedArgs(#)', [args]));
1415 } 1426 }
1416 1427
1417 if (method is MethodElement) { 1428 if (method is MethodElement) {
1418 addProperty('isMethod', js.boolean(true)); 1429 addProperty('isMethod', js.boolean(true));
1419 1430
1420 fnArgs.add(new JS.RestParameter(args)); 1431 fnArgs.add(new JS.RestParameter(args));
1421 positionalArgs = args; 1432 positionalArgs = args;
1422 } else { 1433 } else {
1423 var property = method as PropertyAccessorElement; 1434 var property = method as PropertyAccessorElement;
1424 if (property.isGetter) { 1435 if (property.isGetter) {
1425 addProperty('isGetter', js.boolean(true)); 1436 addProperty('isGetter', js.boolean(true));
1426 1437
1427 positionalArgs = new JS.ArrayInitializer([]); 1438 positionalArgs = new JS.ArrayInitializer([]);
1428 } else if (property.isSetter) { 1439 } else if (property.isSetter) {
1429 addProperty('isSetter', js.boolean(true)); 1440 addProperty('isSetter', js.boolean(true));
1430 1441
1431 fnArgs.add(args); 1442 fnArgs.add(args);
1432 positionalArgs = new JS.ArrayInitializer([args]); 1443 positionalArgs = new JS.ArrayInitializer([args]);
1433 } 1444 }
1434 } 1445 }
1435 1446
1436 var fnBody = 1447 var fnBody = js.call('this.noSuchMethod(new #.InvocationImpl(#, #, #))', [
1437 js.call('this.noSuchMethod(new dart.InvocationImpl(#, #, #))', [ 1448 _runtimeModule,
1438 _declareMemberName(method), 1449 _declareMemberName(method),
1439 positionalArgs, 1450 positionalArgs,
1440 new JS.ObjectInitializer(invocationProps) 1451 new JS.ObjectInitializer(invocationProps)
1441 ]); 1452 ]);
1442 1453
1443 if (!method.returnType.isDynamic) { 1454 if (!method.returnType.isDynamic) {
1444 fnBody = js.call('#._check(#)', [_emitType(method.returnType), fnBody]); 1455 fnBody = js.call('#._check(#)', [_emitType(method.returnType), fnBody]);
1445 } 1456 }
1446 1457
1447 var fn = new JS.Fun(fnArgs, js.statement('{ return #; }', [fnBody]), 1458 var fn = new JS.Fun(fnArgs, js.statement('{ return #; }', [fnBody]),
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
1545 // simple code size optimization. 1556 // simple code size optimization.
1546 var parent = t.lookUpGetterInSuperclass('iterator', t.element.library); 1557 var parent = t.lookUpGetterInSuperclass('iterator', t.element.library);
1547 if (parent != null) return null; 1558 if (parent != null) return null;
1548 var parentType = findSupertype(t, _implementsIterable); 1559 var parentType = findSupertype(t, _implementsIterable);
1549 if (parentType != null) return null; 1560 if (parentType != null) return null;
1550 1561
1551 // Otherwise, emit the adapter method, which wraps the Dart iterator in 1562 // Otherwise, emit the adapter method, which wraps the Dart iterator in
1552 // an ES6 iterator. 1563 // an ES6 iterator.
1553 return new JS.Method( 1564 return new JS.Method(
1554 js.call('Symbol.iterator'), 1565 js.call('Symbol.iterator'),
1555 js.call('function() { return new dart.JsIterator(this.#); }', 1566 js.call('function() { return new #.JsIterator(this.#); }',
1556 [_emitMemberName('iterator', type: t)]) as JS.Fun); 1567 [_runtimeModule, _emitMemberName('iterator', type: t)]) as JS.Fun);
1557 } 1568 }
1558 1569
1559 JS.Expression _instantiateAnnotation(Annotation node) { 1570 JS.Expression _instantiateAnnotation(Annotation node) {
1560 var element = node.element; 1571 var element = node.element;
1561 if (element is ConstructorElement) { 1572 if (element is ConstructorElement) {
1562 return _emitInstanceCreationExpression(element, element.returnType, 1573 return _emitInstanceCreationExpression(element, element.returnType,
1563 node.constructorName, node.arguments, true); 1574 node.constructorName, node.arguments, true);
1564 } else { 1575 } else {
1565 return _visit(node.name); 1576 return _visit(node.name);
1566 } 1577 }
(...skipping 16 matching lines...) Expand all
1583 .where((peer) => !peer.startsWith("!")) 1594 .where((peer) => !peer.startsWith("!"))
1584 .toList(); 1595 .toList();
1585 } else { 1596 } else {
1586 return []; 1597 return [];
1587 } 1598 }
1588 } 1599 }
1589 1600
1590 void _registerExtensionType( 1601 void _registerExtensionType(
1591 ClassElement classElem, String jsPeerName, List<JS.Statement> body) { 1602 ClassElement classElem, String jsPeerName, List<JS.Statement> body) {
1592 if (jsPeerName != null) { 1603 if (jsPeerName != null) {
1593 body.add(js.statement('dart.registerExtension(dart.global.#, #);', 1604 body.add(_callHelperStatement('registerExtension(#.global.#, #);', [
1594 [_propertyName(jsPeerName), _emitTopLevelName(classElem)])); 1605 _runtimeModule,
1606 _propertyName(jsPeerName),
1607 _emitTopLevelName(classElem)
1608 ]));
1595 } 1609 }
1596 } 1610 }
1597 1611
1598 void _setBaseClass(ClassElement classElem, JS.Expression className, 1612 void _setBaseClass(ClassElement classElem, JS.Expression className,
1599 List<String> jsPeerNames, List<JS.Statement> body) { 1613 List<String> jsPeerNames, List<JS.Statement> body) {
1600 if (jsPeerNames.isNotEmpty && classElem.typeParameters.isNotEmpty) { 1614 if (jsPeerNames.isNotEmpty && classElem.typeParameters.isNotEmpty) {
1601 for (var peer in jsPeerNames) { 1615 for (var peer in jsPeerNames) {
1602 // TODO(jmesserly): we should just extend Array in the first place 1616 // TODO(jmesserly): we should just extend Array in the first place
1603 var newBaseClass = js.call('dart.global.#', [peer]); 1617 var newBaseClass = _callHelper('global.#', [peer]);
1604 body.add(js.statement( 1618 body.add(_callHelperStatement(
1605 'dart.setExtensionBaseClass(#, #);', [className, newBaseClass])); 1619 'setExtensionBaseClass(#, #);', [className, newBaseClass]));
1606 } 1620 }
1607 } else if (_hasDeferredSupertype.contains(classElem)) { 1621 } else if (_hasDeferredSupertype.contains(classElem)) {
1608 var newBaseClass = _emitType(classElem.type.superclass, 1622 var newBaseClass = _emitType(classElem.type.superclass,
1609 nameType: false, subClass: classElem, className: className); 1623 nameType: false, subClass: classElem, className: className);
1610 body.add( 1624 body.add(_callHelperStatement(
1611 js.statement('dart.setBaseClass(#, #);', [className, newBaseClass])); 1625 'setBaseClass(#, #);', [className, newBaseClass]));
1612 } 1626 }
1613 } 1627 }
1614 1628
1615 void _defineNamedConstructors(List<ConstructorDeclaration> ctors, 1629 void _defineNamedConstructors(List<ConstructorDeclaration> ctors,
1616 List<JS.Statement> body, JS.Expression className, bool isCallable) { 1630 List<JS.Statement> body, JS.Expression className, bool isCallable) {
1617 var code = isCallable 1631 var code = isCallable
1618 ? 'dart.defineNamedConstructorCallable(#, #, #);' 1632 ? 'defineNamedConstructorCallable(#, #, #);'
1619 : 'dart.defineNamedConstructor(#, #)'; 1633 : 'defineNamedConstructor(#, #)';
1620 1634
1621 for (ConstructorDeclaration member in ctors) { 1635 for (ConstructorDeclaration member in ctors) {
1622 if (member.name != null && member.factoryKeyword == null) { 1636 if (member.name != null && member.factoryKeyword == null) {
1623 var args = [className, _constructorName(member.element)]; 1637 var args = [className, _constructorName(member.element)];
1624 if (isCallable) { 1638 if (isCallable) {
1625 args.add(_emitCallableClassConstructor(member.element)); 1639 args.add(_emitCallableClassConstructor(member.element));
1626 } 1640 }
1627 1641
1628 body.add(js.statement(code, args)); 1642 body.add(_callHelperStatement(code, args));
1629 } 1643 }
1630 } 1644 }
1631 } 1645 }
1632 1646
1633 /// Emits static fields for a class, and initialize them eagerly if possible, 1647 /// Emits static fields for a class, and initialize them eagerly if possible,
1634 /// otherwise define them as lazy properties. 1648 /// otherwise define them as lazy properties.
1635 void _emitStaticFields( 1649 void _emitStaticFields(
1636 List<FieldDeclaration> staticFields, 1650 List<FieldDeclaration> staticFields,
1637 Set<FieldElement> staticFieldOverrides, 1651 Set<FieldElement> staticFieldOverrides,
1638 ClassElement classElem, 1652 ClassElement classElem,
(...skipping 12 matching lines...) Expand all
1651 } 1665 }
1652 if (lazyStatics.isNotEmpty) { 1666 if (lazyStatics.isNotEmpty) {
1653 body.add(_emitLazyFields(classElem, lazyStatics)); 1667 body.add(_emitLazyFields(classElem, lazyStatics));
1654 } 1668 }
1655 } 1669 }
1656 1670
1657 void _emitClassMetadata(List<Annotation> metadata, JS.Expression className, 1671 void _emitClassMetadata(List<Annotation> metadata, JS.Expression className,
1658 List<JS.Statement> body) { 1672 List<JS.Statement> body) {
1659 // Metadata 1673 // Metadata
1660 if (options.emitMetadata && metadata.isNotEmpty) { 1674 if (options.emitMetadata && metadata.isNotEmpty) {
1661 body.add(js.statement('#[dart.metadata] = () => #;', [ 1675 body.add(js.statement('#[#.metadata] = () => #;', [
1662 className, 1676 className,
1677 _runtimeModule,
1663 new JS.ArrayInitializer( 1678 new JS.ArrayInitializer(
1664 new List<JS.Expression>.from(metadata.map(_instantiateAnnotation))) 1679 new List<JS.Expression>.from(metadata.map(_instantiateAnnotation)))
1665 ])); 1680 ]));
1666 } 1681 }
1667 } 1682 }
1668 1683
1669 /// If a concrete class implements one of our extensions, we might need to 1684 /// If a concrete class implements one of our extensions, we might need to
1670 /// add forwarders. 1685 /// add forwarders.
1671 void _defineExtensionMembers(List<ExecutableElement> extensions, 1686 void _defineExtensionMembers(List<ExecutableElement> extensions,
1672 JS.Expression className, List<JS.Statement> body) { 1687 JS.Expression className, List<JS.Statement> body) {
1673 // If a concrete class implements one of our extensions, we might need to 1688 // If a concrete class implements one of our extensions, we might need to
1674 // add forwarders. 1689 // add forwarders.
1675 if (extensions.isNotEmpty) { 1690 if (extensions.isNotEmpty) {
1676 var methodNames = <JS.Expression>[]; 1691 var methodNames = <JS.Expression>[];
1677 for (var e in extensions) { 1692 for (var e in extensions) {
1678 methodNames.add(_declareMemberName(e, useExtension: false)); 1693 methodNames.add(_declareMemberName(e, useExtension: false));
1679 } 1694 }
1680 body.add(js.statement('dart.defineExtensionMembers(#, #);', [ 1695 body.add(_callHelperStatement('defineExtensionMembers(#, #);', [
1681 className, 1696 className,
1682 new JS.ArrayInitializer(methodNames, multiline: methodNames.length > 4) 1697 new JS.ArrayInitializer(methodNames, multiline: methodNames.length > 4)
1683 ])); 1698 ]));
1684 } 1699 }
1685 } 1700 }
1686 1701
1687 /// Emit the signature on the class recording the runtime type information 1702 /// Emit the signature on the class recording the runtime type information
1688 void _emitClassSignature( 1703 void _emitClassSignature(
1689 List<MethodDeclaration> methods, 1704 List<MethodDeclaration> methods,
1690 List<FieldDeclaration> fields, 1705 List<FieldDeclaration> fields,
1691 ClassElement classElem, 1706 ClassElement classElem,
1692 List<ConstructorDeclaration> ctors, 1707 List<ConstructorDeclaration> ctors,
1693 List<ExecutableElement> extensions, 1708 List<ExecutableElement> extensions,
1694 JS.Expression className, 1709 JS.Expression className,
1695 List<JS.Statement> body) { 1710 List<JS.Statement> body) {
1696 if (classElem.interfaces.isNotEmpty) { 1711 if (classElem.interfaces.isNotEmpty) {
1697 body.add(js.statement('#[dart.implements] = () => #;', [ 1712 body.add(js.statement('#[#.implements] = () => #;', [
1698 className, 1713 className,
1714 _runtimeModule,
1699 new JS.ArrayInitializer( 1715 new JS.ArrayInitializer(
1700 new List<JS.Expression>.from(classElem.interfaces.map(_emitType))) 1716 new List<JS.Expression>.from(classElem.interfaces.map(_emitType)))
1701 ])); 1717 ]));
1702 } 1718 }
1703 1719
1704 var tStaticMethods = <JS.Property>[]; 1720 var tStaticMethods = <JS.Property>[];
1705 var tInstanceMethods = <JS.Property>[]; 1721 var tInstanceMethods = <JS.Property>[];
1706 var tStaticGetters = <JS.Property>[]; 1722 var tStaticGetters = <JS.Property>[];
1707 var tInstanceGetters = <JS.Property>[]; 1723 var tInstanceGetters = <JS.Property>[];
1708 var tStaticSetters = <JS.Property>[]; 1724 var tStaticSetters = <JS.Property>[];
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
1811 if (!tStaticMethods.isEmpty) { 1827 if (!tStaticMethods.isEmpty) {
1812 assert(!sNames.isEmpty); 1828 assert(!sNames.isEmpty);
1813 // TODO(vsm): Why do we need this names field? 1829 // TODO(vsm): Why do we need this names field?
1814 var aNames = new JS.Property( 1830 var aNames = new JS.Property(
1815 _propertyName('names'), new JS.ArrayInitializer(sNames)); 1831 _propertyName('names'), new JS.ArrayInitializer(sNames));
1816 sigFields.add(build('statics', tStaticMethods)); 1832 sigFields.add(build('statics', tStaticMethods));
1817 sigFields.add(aNames); 1833 sigFields.add(aNames);
1818 } 1834 }
1819 if (!sigFields.isEmpty || extensions.isNotEmpty) { 1835 if (!sigFields.isEmpty || extensions.isNotEmpty) {
1820 var sig = new JS.ObjectInitializer(sigFields); 1836 var sig = new JS.ObjectInitializer(sigFields);
1821 body.add(js.statement('dart.setSignature(#, #);', [className, sig])); 1837 body.add(_callHelperStatement('setSignature(#, #);', [className, sig]));
1822 } 1838 }
1823 // Add static property dart._runtimeType to Object. 1839 // Add static property dart._runtimeType to Object.
1824 // All other Dart classes will (statically) inherit this property. 1840 // All other Dart classes will (statically) inherit this property.
1825 if (classElem == objectClass) { 1841 if (classElem == objectClass) {
1826 body.add(js.statement('dart.tagComputed(#, () => #.#);', 1842 body.add(_callHelperStatement('tagComputed(#, () => #.#);',
1827 [className, emitLibraryName(dartCoreLibrary), 'Type'])); 1843 [className, emitLibraryName(dartCoreLibrary), 'Type']));
1828 } 1844 }
1829 } 1845 }
1830 1846
1831 /// Ensure `dartx.` symbols we will use are present. 1847 /// Ensure `dartx.` symbols we will use are present.
1832 void _initExtensionSymbols( 1848 void _initExtensionSymbols(
1833 ClassElement classElem, 1849 ClassElement classElem,
1834 List<MethodDeclaration> methods, 1850 List<MethodDeclaration> methods,
1835 List<FieldDeclaration> fields, 1851 List<FieldDeclaration> fields,
1836 List<JS.Statement> body) { 1852 List<JS.Statement> body) {
1837 if (_extensionTypes.hasNativeSubtype(classElem.type)) { 1853 if (_extensionTypes.hasNativeSubtype(classElem.type)) {
1838 var dartxNames = <JS.Expression>[]; 1854 var dartxNames = <JS.Expression>[];
1839 for (var m in methods) { 1855 for (var m in methods) {
1840 if (!m.isAbstract && !m.isStatic && m.element.isPublic) { 1856 if (!m.isAbstract && !m.isStatic && m.element.isPublic) {
1841 dartxNames.add(_declareMemberName(m.element, useExtension: false)); 1857 dartxNames.add(_declareMemberName(m.element, useExtension: false));
1842 } 1858 }
1843 } 1859 }
1844 for (var fieldDecl in fields) { 1860 for (var fieldDecl in fields) {
1845 if (!fieldDecl.isStatic) { 1861 if (!fieldDecl.isStatic) {
1846 for (var field in fieldDecl.fields.variables) { 1862 for (var field in fieldDecl.fields.variables) {
1847 var e = field.element as FieldElement; 1863 var e = field.element as FieldElement;
1848 if (e.isPublic) { 1864 if (e.isPublic) {
1849 dartxNames.add(_declareMemberName(e.getter, useExtension: false)); 1865 dartxNames.add(_declareMemberName(e.getter, useExtension: false));
1850 } 1866 }
1851 } 1867 }
1852 } 1868 }
1853 } 1869 }
1854 if (dartxNames.isNotEmpty) { 1870 if (dartxNames.isNotEmpty) {
1855 body.add(js.statement('dart.defineExtensionNames(#)', 1871 body.add(_callHelperStatement('defineExtensionNames(#)',
1856 [new JS.ArrayInitializer(dartxNames, multiline: true)])); 1872 [new JS.ArrayInitializer(dartxNames, multiline: true)]));
1857 } 1873 }
1858 } 1874 }
1859 } 1875 }
1860 1876
1861 List<ExecutableElement> _extensionsToImplement(ClassElement element) { 1877 List<ExecutableElement> _extensionsToImplement(ClassElement element) {
1862 var members = <ExecutableElement>[]; 1878 var members = <ExecutableElement>[];
1863 if (_extensionTypes.isNativeClass(element)) return members; 1879 if (_extensionTypes.isNativeClass(element)) return members;
1864 1880
1865 // Collect all extension types we implement. 1881 // Collect all extension types we implement.
(...skipping 459 matching lines...) Expand 10 before | Expand all | Expand 10 after
2325 2341
2326 // If we have a getter/setter pair, they need to be defined together. 2342 // If we have a getter/setter pair, they need to be defined together.
2327 if (node.isGetter) { 2343 if (node.isGetter) {
2328 PropertyAccessorElement element = node.element; 2344 PropertyAccessorElement element = node.element;
2329 var props = <JS.Method>[_emitTopLevelProperty(node)]; 2345 var props = <JS.Method>[_emitTopLevelProperty(node)];
2330 var setter = element.correspondingSetter; 2346 var setter = element.correspondingSetter;
2331 if (setter != null) { 2347 if (setter != null) {
2332 props.add(_loader.emitDeclaration( 2348 props.add(_loader.emitDeclaration(
2333 setter, (node) => _emitTopLevelProperty(node))); 2349 setter, (node) => _emitTopLevelProperty(node)));
2334 } 2350 }
2335 return js.statement('dart.copyProperties(#, { # });', 2351 return _callHelperStatement('copyProperties(#, { # });',
2336 [emitLibraryName(currentLibrary), props]); 2352 [emitLibraryName(currentLibrary), props]);
2337 } 2353 }
2338 if (node.isSetter) { 2354 if (node.isSetter) {
2339 PropertyAccessorElement element = node.element; 2355 PropertyAccessorElement element = node.element;
2340 var props = <JS.Method>[_emitTopLevelProperty(node)]; 2356 var props = <JS.Method>[_emitTopLevelProperty(node)];
2341 var getter = element.correspondingGetter; 2357 var getter = element.correspondingGetter;
2342 if (getter != null) { 2358 if (getter != null) {
2343 props.add(_loader.emitDeclaration( 2359 props.add(_loader.emitDeclaration(
2344 getter, (node) => _emitTopLevelProperty(node))); 2360 getter, (node) => _emitTopLevelProperty(node)));
2345 } 2361 }
2346 return js.statement('dart.copyProperties(#, { # });', 2362 return _callHelperStatement('copyProperties(#, { # });',
2347 [emitLibraryName(currentLibrary), props]); 2363 [emitLibraryName(currentLibrary), props]);
2348 } 2364 }
2349 2365
2350 var body = <JS.Statement>[]; 2366 var body = <JS.Statement>[];
2351 var fn = _emitFunction(node.functionExpression); 2367 var fn = _emitFunction(node.functionExpression);
2352 2368
2353 if (currentLibrary.source.isInSystemLibrary && 2369 if (currentLibrary.source.isInSystemLibrary &&
2354 _isInlineJSFunction(node.functionExpression)) { 2370 _isInlineJSFunction(node.functionExpression)) {
2355 fn = _simplifyPassThroughArrowFunCallBody(fn); 2371 fn = _simplifyPassThroughArrowFunCallBody(fn);
2356 } 2372 }
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
2435 return false; 2451 return false;
2436 } 2452 }
2437 return _loader.isLoaded(type.element); 2453 return _loader.isLoaded(type.element);
2438 } 2454 }
2439 2455
2440 JS.Expression _emitFunctionTagged(JS.Expression fn, DartType type, 2456 JS.Expression _emitFunctionTagged(JS.Expression fn, DartType type,
2441 {topLevel: false}) { 2457 {topLevel: false}) {
2442 var lazy = topLevel && !_typeIsLoaded(type); 2458 var lazy = topLevel && !_typeIsLoaded(type);
2443 var typeRep = _emitFunctionType(type, definite: true); 2459 var typeRep = _emitFunctionType(type, definite: true);
2444 if (lazy) { 2460 if (lazy) {
2445 return js.call('dart.lazyFn(#, () => #)', [fn, typeRep]); 2461 return _callHelper('lazyFn(#, () => #)', [fn, typeRep]);
2446 } else { 2462 } else {
2447 return js.call('dart.fn(#, #)', [fn, typeRep]); 2463 return _callHelper('fn(#, #)', [fn, typeRep]);
2448 } 2464 }
2449 } 2465 }
2450 2466
2451 /// Emits an arrow FunctionExpression node. 2467 /// Emits an arrow FunctionExpression node.
2452 /// 2468 ///
2453 /// This should be used for all places in Dart's AST where FunctionExpression 2469 /// This should be used for all places in Dart's AST where FunctionExpression
2454 /// appears and the function is actually in an Expression context. These 2470 /// appears and the function is actually in an Expression context. These
2455 /// correspond to arrow functions in Dart. 2471 /// correspond to arrow functions in Dart.
2456 /// 2472 ///
2457 /// Contrast with [_emitFunction]. 2473 /// Contrast with [_emitFunction].
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
2589 _asyncStarController = savedController; 2605 _asyncStarController = savedController;
2590 2606
2591 DartType returnType = _getExpectedReturnType(element); 2607 DartType returnType = _getExpectedReturnType(element);
2592 JS.Expression gen = new JS.Fun(jsParams, jsBody, 2608 JS.Expression gen = new JS.Fun(jsParams, jsBody,
2593 isGenerator: true, returnType: emitTypeRef(returnType)); 2609 isGenerator: true, returnType: emitTypeRef(returnType));
2594 if (JS.This.foundIn(gen)) { 2610 if (JS.This.foundIn(gen)) {
2595 gen = js.call('#.bind(this)', gen); 2611 gen = js.call('#.bind(this)', gen);
2596 } 2612 }
2597 2613
2598 var T = _emitType(returnType); 2614 var T = _emitType(returnType);
2599 return js.call('dart.#(#)', [ 2615 return _callHelper('#(#)', [
2600 kind, 2616 kind,
2601 [gen, T]..addAll(visitFormalParameterList(parameters, destructure: false)) 2617 [gen, T]..addAll(visitFormalParameterList(parameters, destructure: false))
2602 ]); 2618 ]);
2603 } 2619 }
2604 2620
2605 @override 2621 @override
2606 JS.Statement visitFunctionDeclarationStatement( 2622 JS.Statement visitFunctionDeclarationStatement(
2607 FunctionDeclarationStatement node) { 2623 FunctionDeclarationStatement node) {
2608 var func = node.functionDeclaration; 2624 var func = node.functionDeclaration;
2609 if (func.isGetter || func.isSetter) { 2625 if (func.isGetter || func.isSetter) {
(...skipping 19 matching lines...) Expand all
2629 2645
2630 /// Emits a simple identifier, including handling an inferred generic 2646 /// Emits a simple identifier, including handling an inferred generic
2631 /// function instantiation. 2647 /// function instantiation.
2632 @override 2648 @override
2633 JS.Expression visitSimpleIdentifier(SimpleIdentifier node) { 2649 JS.Expression visitSimpleIdentifier(SimpleIdentifier node) {
2634 var typeArgs = _getTypeArgs(node.staticElement, node.staticType); 2650 var typeArgs = _getTypeArgs(node.staticElement, node.staticType);
2635 var simpleId = _emitSimpleIdentifier(node); 2651 var simpleId = _emitSimpleIdentifier(node);
2636 if (typeArgs == null) { 2652 if (typeArgs == null) {
2637 return simpleId; 2653 return simpleId;
2638 } 2654 }
2639 return js.call('dart.gbind(#, #)', [simpleId, typeArgs]); 2655 return _callHelper('gbind(#, #)', [simpleId, typeArgs]);
2640 } 2656 }
2641 2657
2642 /// Emits a simple identifier, handling implicit `this` as well as 2658 /// Emits a simple identifier, handling implicit `this` as well as
2643 /// going through the qualified library name if necessary, but *not* handling 2659 /// going through the qualified library name if necessary, but *not* handling
2644 /// inferred generic function instantiation. 2660 /// inferred generic function instantiation.
2645 JS.Expression _emitSimpleIdentifier(SimpleIdentifier node) { 2661 JS.Expression _emitSimpleIdentifier(SimpleIdentifier node) {
2646 var accessor = node.staticElement; 2662 var accessor = node.staticElement;
2647 if (accessor == null) { 2663 if (accessor == null) {
2648 return js.commentExpression( 2664 return js.commentExpression(
2649 'Unimplemented unknown name', new JS.Identifier(node.name)); 2665 'Unimplemented unknown name', new JS.Identifier(node.name));
2650 } 2666 }
2651 2667
2652 // Get the original declaring element. If we had a property accessor, this 2668 // Get the original declaring element. If we had a property accessor, this
2653 // indirects back to a (possibly synthetic) field. 2669 // indirects back to a (possibly synthetic) field.
2654 var element = accessor; 2670 var element = accessor;
2655 if (accessor is PropertyAccessorElement) element = accessor.variable; 2671 if (accessor is PropertyAccessorElement) element = accessor.variable;
2656 2672
2657 _declareBeforeUse(element); 2673 _declareBeforeUse(element);
2658 2674
2659 // type literal 2675 // type literal
2660 if (element is TypeDefiningElement) { 2676 if (element is TypeDefiningElement) {
2661 var typeName = _emitType(fillDynamicTypeArgs(element.type)); 2677 var typeName = _emitType(fillDynamicTypeArgs(element.type));
2662 2678
2663 // If the type is a type literal expression in Dart code, wrap the raw 2679 // If the type is a type literal expression in Dart code, wrap the raw
2664 // runtime type in a "Type" instance. 2680 // runtime type in a "Type" instance.
2665 if (!_isInForeignJS && _isTypeLiteral(node)) { 2681 if (!_isInForeignJS && _isTypeLiteral(node)) {
2666 typeName = js.call('dart.wrapType(#)', typeName); 2682 typeName = _callHelper('wrapType(#)', typeName);
2667 } 2683 }
2668 2684
2669 return typeName; 2685 return typeName;
2670 } 2686 }
2671 2687
2672 // library member 2688 // library member
2673 if (element.enclosingElement is CompilationUnitElement) { 2689 if (element.enclosingElement is CompilationUnitElement) {
2674 return _emitTopLevelName(element); 2690 return _emitTopLevelName(element);
2675 } 2691 }
2676 2692
(...skipping 10 matching lines...) Expand all
2687 // library prefix. We don't need those because static calls can't use 2703 // library prefix. We don't need those because static calls can't use
2688 // the generic type. 2704 // the generic type.
2689 if (isStatic) { 2705 if (isStatic) {
2690 var dynType = _emitType(fillDynamicTypeArgs(type)); 2706 var dynType = _emitType(fillDynamicTypeArgs(type));
2691 return new JS.PropertyAccess(dynType, member); 2707 return new JS.PropertyAccess(dynType, member);
2692 } 2708 }
2693 2709
2694 // For instance members, we add implicit-this. 2710 // For instance members, we add implicit-this.
2695 // For method tear-offs, we ensure it's a bound method. 2711 // For method tear-offs, we ensure it's a bound method.
2696 var tearOff = element is MethodElement && !inInvocationContext(node); 2712 var tearOff = element is MethodElement && !inInvocationContext(node);
2697 var code = (tearOff) ? 'dart.bind(this, #)' : 'this.#'; 2713 if (tearOff) return _callHelper('bind(this, #)', member);
2698 return js.call(code, member); 2714 return js.call('this.#', member);
2699 } 2715 }
2700 2716
2701 if (element is ParameterElement) { 2717 if (element is ParameterElement) {
2702 return _emitParameter(element); 2718 return _emitParameter(element);
2703 } 2719 }
2704 2720
2705 // If this is one of our compiler's temporary variables, return its JS form. 2721 // If this is one of our compiler's temporary variables, return its JS form.
2706 if (element is TemporaryVariableElement) { 2722 if (element is TemporaryVariableElement) {
2707 return element.jsVariable; 2723 return element.jsVariable;
2708 } 2724 }
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
2805 bool lowerTypedef: false, 2821 bool lowerTypedef: false,
2806 bool nameType: true, 2822 bool nameType: true,
2807 bool hoistType: true, 2823 bool hoistType: true,
2808 definite: false}) { 2824 definite: false}) {
2809 var parts = _emitFunctionTypeParts(type, 2825 var parts = _emitFunctionTypeParts(type,
2810 parameters: parameters, 2826 parameters: parameters,
2811 lowerTypedef: lowerTypedef, 2827 lowerTypedef: lowerTypedef,
2812 nameType: nameType, 2828 nameType: nameType,
2813 hoistType: hoistType); 2829 hoistType: hoistType);
2814 var helper = (definite) ? 'definiteFunctionType' : 'functionType'; 2830 var helper = (definite) ? 'definiteFunctionType' : 'functionType';
2815 var fullType = js.call('dart.${helper}(#)', [parts]); 2831 var fullType = _callHelper('${helper}(#)', [parts]);
2816 if (!nameType) return fullType; 2832 if (!nameType) return fullType;
2817 return _typeTable.nameType(type, fullType, 2833 return _typeTable.nameType(type, fullType,
2818 hoistType: hoistType, definite: definite); 2834 hoistType: hoistType, definite: definite);
2819 } 2835 }
2820 2836
2821 JS.Expression _emitAnnotatedFunctionType( 2837 JS.Expression _emitAnnotatedFunctionType(
2822 FunctionType type, List<Annotation> metadata, 2838 FunctionType type, List<Annotation> metadata,
2823 {List<FormalParameter> parameters, 2839 {List<FormalParameter> parameters,
2824 bool lowerTypedef: false, 2840 bool lowerTypedef: false,
2825 bool nameType: true, 2841 bool nameType: true,
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
2901 /// if [hoistType] is true, then the named type will be hoisted. 2917 /// if [hoistType] is true, then the named type will be hoisted.
2902 JS.Expression _emitType(DartType type, 2918 JS.Expression _emitType(DartType type,
2903 {bool lowerTypedef: false, 2919 {bool lowerTypedef: false,
2904 bool lowerGeneric: false, 2920 bool lowerGeneric: false,
2905 bool nameType: true, 2921 bool nameType: true,
2906 bool hoistType: true, 2922 bool hoistType: true,
2907 ClassElement subClass, 2923 ClassElement subClass,
2908 JS.Expression className}) { 2924 JS.Expression className}) {
2909 // The void and dynamic types are not defined in core. 2925 // The void and dynamic types are not defined in core.
2910 if (type.isVoid) { 2926 if (type.isVoid) {
2911 return js.call('dart.void'); 2927 return _callHelper('void');
2912 } else if (type.isDynamic) { 2928 } else if (type.isDynamic) {
2913 return js.call('dart.dynamic'); 2929 return _callHelper('dynamic');
2914 } else if (type.isBottom) { 2930 } else if (type.isBottom) {
2915 return js.call('dart.bottom'); 2931 return _callHelper('bottom');
2916 } 2932 }
2917 2933
2918 _declareBeforeUse(type.element); 2934 _declareBeforeUse(type.element);
2919 2935
2920 // TODO(jmesserly): like constants, should we hoist function types out of 2936 // TODO(jmesserly): like constants, should we hoist function types out of
2921 // methods? Similar issue with generic types. For all of these, we may want 2937 // methods? Similar issue with generic types. For all of these, we may want
2922 // to canonicalize them too, at least when inside the same library. 2938 // to canonicalize them too, at least when inside the same library.
2923 var name = type.name; 2939 var name = type.name;
2924 var element = type.element; 2940 var element = type.element;
2925 if (name == '' || name == null || lowerTypedef) { 2941 if (name == '' || name == null || lowerTypedef) {
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
3052 if (target is SuperExpression) { 3068 if (target is SuperExpression) {
3053 return _emitSetSuper(lhs, target, id, rhs); 3069 return _emitSetSuper(lhs, target, id, rhs);
3054 } 3070 }
3055 3071
3056 if (target != null && isDynamicInvoke(target)) { 3072 if (target != null && isDynamicInvoke(target)) {
3057 if (_inWhitelistCode(lhs)) { 3073 if (_inWhitelistCode(lhs)) {
3058 var vars = <JS.MetaLetVariable, JS.Expression>{}; 3074 var vars = <JS.MetaLetVariable, JS.Expression>{};
3059 var l = _visit(_bindValue(vars, 'l', target)); 3075 var l = _visit(_bindValue(vars, 'l', target));
3060 var name = _emitMemberName(id.name); 3076 var name = _emitMemberName(id.name);
3061 return new JS.MetaLet(vars, [ 3077 return new JS.MetaLet(vars, [
3062 js.call('(#[(#[dart._extensionType]) ? dartx[#] : #] = #)', 3078 js.call('(#[(#[#._extensionType]) ? #[#] : #] = #)', [
3063 [l, l, name, name, _visit(rhs)]) 3079 l,
3080 l,
3081 _runtimeModule,
3082 name,
3083 _extensionSymbolsModule,
3084 name,
3085 _visit(rhs)
3086 ])
3064 ]); 3087 ]);
3065 } 3088 }
3066 return js.call('dart.#(#, #, #)', [ 3089 return _callHelper('#(#, #, #)', [
3067 _emitDynamicOperationName('dput'), 3090 _emitDynamicOperationName('dput'),
3068 _visit(target), 3091 _visit(target),
3069 _emitMemberName(id.name), 3092 _emitMemberName(id.name),
3070 _visit(rhs) 3093 _visit(rhs)
3071 ]); 3094 ]);
3072 } 3095 }
3073 3096
3074 var accessor = id.staticElement; 3097 var accessor = id.staticElement;
3075 var element = 3098 var element =
3076 accessor is PropertyAccessorElement ? accessor.variable : accessor; 3099 accessor is PropertyAccessorElement ? accessor.variable : accessor;
(...skipping 12 matching lines...) Expand all
3089 } 3112 }
3090 } 3113 }
3091 3114
3092 return _badAssignment('Unhandled assignment', lhs, rhs); 3115 return _badAssignment('Unhandled assignment', lhs, rhs);
3093 } 3116 }
3094 3117
3095 JS.Expression _badAssignment(String problem, Expression lhs, Expression rhs) { 3118 JS.Expression _badAssignment(String problem, Expression lhs, Expression rhs) {
3096 // TODO(sra): We should get here only for compiler bugs or weirdness due to 3119 // TODO(sra): We should get here only for compiler bugs or weirdness due to
3097 // --unsafe-force-compile. Once those paths have been addressed, throw at 3120 // --unsafe-force-compile. Once those paths have been addressed, throw at
3098 // compile time. 3121 // compile time.
3099 return js.call('dart.throwUnimplementedError((#, #, #))', 3122 return _callHelper('throwUnimplementedError((#, #, #))',
3100 [js.string('$lhs ='), _visit(rhs), js.string(problem)]); 3123 [js.string('$lhs ='), _visit(rhs), js.string(problem)]);
3101 } 3124 }
3102 3125
3103 /// Emits assignment to a simple identifier. Handles all legal simple 3126 /// Emits assignment to a simple identifier. Handles all legal simple
3104 /// identifier assignment targets (local, top level library member, implicit 3127 /// identifier assignment targets (local, top level library member, implicit
3105 /// `this` or class, etc.) 3128 /// `this` or class, etc.)
3106 JS.Expression _emitSetSimpleIdentifier( 3129 JS.Expression _emitSetSimpleIdentifier(
3107 SimpleIdentifier node, Expression rhs) { 3130 SimpleIdentifier node, Expression rhs) {
3108 JS.Expression unimplemented() { 3131 JS.Expression unimplemented() {
3109 return _badAssignment("Unimplemented: unknown name '$node'", node, rhs); 3132 return _badAssignment("Unimplemented: unknown name '$node'", node, rhs);
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after
3339 var element = node.methodName.staticElement; 3362 var element = node.methodName.staticElement;
3340 bool isStatic = element is ExecutableElement && element.isStatic; 3363 bool isStatic = element is ExecutableElement && element.isStatic;
3341 var memberName = _emitMemberName(name, type: type, isStatic: isStatic); 3364 var memberName = _emitMemberName(name, type: type, isStatic: isStatic);
3342 3365
3343 JS.Expression jsTarget = _visit(target); 3366 JS.Expression jsTarget = _visit(target);
3344 if (isDynamicInvoke(target) || isDynamicInvoke(node.methodName)) { 3367 if (isDynamicInvoke(target) || isDynamicInvoke(node.methodName)) {
3345 if (_inWhitelistCode(target)) { 3368 if (_inWhitelistCode(target)) {
3346 var vars = <JS.MetaLetVariable, JS.Expression>{}; 3369 var vars = <JS.MetaLetVariable, JS.Expression>{};
3347 var l = _visit(_bindValue(vars, 'l', target)); 3370 var l = _visit(_bindValue(vars, 'l', target));
3348 jsTarget = new JS.MetaLet(vars, [ 3371 jsTarget = new JS.MetaLet(vars, [
3349 js.call('(#[(#[dart._extensionType]) ? dartx[#] : #]).bind(#)', 3372 js.call('(#[(#[#._extensionType]) ? #[#] : #]).bind(#)', [
3350 [l, l, memberName, memberName, l]) 3373 l,
3374 l,
3375 _runtimeModule,
3376 memberName,
3377 _extensionSymbolsModule,
3378 memberName,
3379 l
3380 ])
3351 ]); 3381 ]);
3352 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); 3382 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs);
3353 return new JS.Call(jsTarget, args); 3383 return new JS.Call(jsTarget, args);
3354 } 3384 }
3355 if (typeArgs != null) { 3385 if (typeArgs != null) {
3356 return js.call('dart.#(#, #, #, #)', [ 3386 return _callHelper('#(#, #, #, #)', [
3357 _emitDynamicOperationName('dgsend'), 3387 _emitDynamicOperationName('dgsend'),
3358 jsTarget, 3388 jsTarget,
3359 new JS.ArrayInitializer(typeArgs), 3389 new JS.ArrayInitializer(typeArgs),
3360 memberName, 3390 memberName,
3361 args 3391 args
3362 ]); 3392 ]);
3363 } else { 3393 } else {
3364 return js.call('dart.#(#, #, #)', 3394 return _callHelper('#(#, #, #)',
3365 [_emitDynamicOperationName('dsend'), jsTarget, memberName, args]); 3395 [_emitDynamicOperationName('dsend'), jsTarget, memberName, args]);
3366 } 3396 }
3367 } 3397 }
3368 if (_isObjectMemberCall(target, name)) { 3398 if (_isObjectMemberCall(target, name)) {
3369 assert(typeArgs == null); // Object methods don't take type args. 3399 assert(typeArgs == null); // Object methods don't take type args.
3370 return js.call('dart.#(#, #)', [name, jsTarget, args]); 3400 return _callHelper('#(#, #)', [name, jsTarget, args]);
3371 } 3401 }
3372 3402
3373 jsTarget = new JS.PropertyAccess(jsTarget, memberName); 3403 jsTarget = new JS.PropertyAccess(jsTarget, memberName);
3374 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); 3404 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs);
3375 3405
3376 return new JS.Call(jsTarget, args); 3406 return new JS.Call(jsTarget, args);
3377 } 3407 }
3378 3408
3379 JS.Expression _emitDynamicInvoke( 3409 JS.Expression _emitDynamicInvoke(
3380 InvocationExpression node, JS.Expression fn, List<JS.Expression> args) { 3410 InvocationExpression node, JS.Expression fn, List<JS.Expression> args) {
3381 var typeArgs = _emitInvokeTypeArguments(node); 3411 var typeArgs = _emitInvokeTypeArguments(node);
3382 if (typeArgs != null) { 3412 if (typeArgs != null) {
3383 return js.call('dart.dgcall(#, #, #)', 3413 return _callHelper(
3384 [fn, new JS.ArrayInitializer(typeArgs), args]); 3414 'dgcall(#, #, #)', [fn, new JS.ArrayInitializer(typeArgs), args]);
3385 } else { 3415 } else {
3386 if (_inWhitelistCode(node, isCall: true)) { 3416 if (_inWhitelistCode(node, isCall: true)) {
3387 return new JS.Call(fn, args); 3417 return new JS.Call(fn, args);
3388 } 3418 }
3389 return js.call('dart.dcall(#, #)', [fn, args]); 3419 return _callHelper('dcall(#, #)', [fn, args]);
3390 } 3420 }
3391 } 3421 }
3392 3422
3393 /// Emits a function call, to a top-level function, local function, or 3423 /// Emits a function call, to a top-level function, local function, or
3394 /// an expression. 3424 /// an expression.
3395 JS.Expression _emitFunctionCall(InvocationExpression node) { 3425 JS.Expression _emitFunctionCall(InvocationExpression node) {
3396 var fn = _visit(node.function); 3426 var fn = _visit(node.function);
3397 var args = _visit(node.argumentList) as List<JS.Expression>; 3427 var args = _visit(node.argumentList) as List<JS.Expression>;
3398 if (isDynamicInvoke(node.function)) { 3428 if (isDynamicInvoke(node.function)) {
3399 return _emitDynamicInvoke(node, fn, args); 3429 return _emitDynamicInvoke(node, fn, args);
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
3622 JS.Statement visitExpressionStatement(ExpressionStatement node) => 3652 JS.Statement visitExpressionStatement(ExpressionStatement node) =>
3623 _visit(node.expression).toStatement(); 3653 _visit(node.expression).toStatement();
3624 3654
3625 @override 3655 @override
3626 JS.EmptyStatement visitEmptyStatement(EmptyStatement node) => 3656 JS.EmptyStatement visitEmptyStatement(EmptyStatement node) =>
3627 new JS.EmptyStatement(); 3657 new JS.EmptyStatement();
3628 3658
3629 @override 3659 @override
3630 JS.Statement visitAssertStatement(AssertStatement node) => 3660 JS.Statement visitAssertStatement(AssertStatement node) =>
3631 // TODO(jmesserly): only emit in checked mode. 3661 // TODO(jmesserly): only emit in checked mode.
3632 js.statement('dart.assert(#);', _visit(node.condition)); 3662 _callHelperStatement('assert(#);', _visit(node.condition));
3633 3663
3634 @override 3664 @override
3635 JS.Statement visitReturnStatement(ReturnStatement node) { 3665 JS.Statement visitReturnStatement(ReturnStatement node) {
3636 var e = node.expression; 3666 var e = node.expression;
3637 if (e == null) return new JS.Return(); 3667 if (e == null) return new JS.Return();
3638 return (_visit(e) as JS.Expression).toReturn(); 3668 return (_visit(e) as JS.Expression).toReturn();
3639 } 3669 }
3640 3670
3641 @override 3671 @override
3642 JS.Statement visitYieldStatement(YieldStatement node) { 3672 JS.Statement visitYieldStatement(YieldStatement node) {
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
3832 } 3862 }
3833 } 3863 }
3834 3864
3835 JS.Expression objExpr; 3865 JS.Expression objExpr;
3836 if (target is ClassElement) { 3866 if (target is ClassElement) {
3837 objExpr = _emitTopLevelName(target); 3867 objExpr = _emitTopLevelName(target);
3838 } else { 3868 } else {
3839 objExpr = emitLibraryName(target); 3869 objExpr = emitLibraryName(target);
3840 } 3870 }
3841 3871
3842 return js.statement('dart.defineLazy(#, { # });', [objExpr, methods]); 3872 return _callHelperStatement('defineLazy(#, { # });', [objExpr, methods]);
3843 } 3873 }
3844 3874
3845 PropertyAccessorElement _findAccessor(VariableElement element, 3875 PropertyAccessorElement _findAccessor(VariableElement element,
3846 {bool getter}) { 3876 {bool getter}) {
3847 var parent = element.enclosingElement; 3877 var parent = element.enclosingElement;
3848 if (parent is ClassElement) { 3878 if (parent is ClassElement) {
3849 return getter 3879 return getter
3850 ? parent.getGetter(element.name) 3880 ? parent.getGetter(element.name)
3851 : parent.getSetter(element.name); 3881 : parent.getSetter(element.name);
3852 } 3882 }
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
3949 3979
3950 bool binaryOperationIsPrimitive(DartType leftT, DartType rightT) => 3980 bool binaryOperationIsPrimitive(DartType leftT, DartType rightT) =>
3951 typeIsPrimitiveInJS(leftT) && typeIsPrimitiveInJS(rightT); 3981 typeIsPrimitiveInJS(leftT) && typeIsPrimitiveInJS(rightT);
3952 3982
3953 bool unaryOperationIsPrimitive(DartType t) => typeIsPrimitiveInJS(t); 3983 bool unaryOperationIsPrimitive(DartType t) => typeIsPrimitiveInJS(t);
3954 3984
3955 JS.Expression notNull(Expression expr) { 3985 JS.Expression notNull(Expression expr) {
3956 if (expr == null) return null; 3986 if (expr == null) return null;
3957 var jsExpr = _visit(expr); 3987 var jsExpr = _visit(expr);
3958 if (!isNullable(expr)) return jsExpr; 3988 if (!isNullable(expr)) return jsExpr;
3959 return js.call('dart.notNull(#)', jsExpr); 3989 return _callHelper('notNull(#)', jsExpr);
3960 } 3990 }
3961 3991
3962 @override 3992 @override
3963 JS.Expression visitBinaryExpression(BinaryExpression node) { 3993 JS.Expression visitBinaryExpression(BinaryExpression node) {
3964 var op = node.operator; 3994 var op = node.operator;
3965 3995
3966 // The operands of logical boolean operators are subject to boolean 3996 // The operands of logical boolean operators are subject to boolean
3967 // conversion. 3997 // conversion.
3968 if (op.type == TokenType.BAR_BAR || 3998 if (op.type == TokenType.BAR_BAR ||
3969 op.type == TokenType.AMPERSAND_AMPERSAND) { 3999 op.type == TokenType.AMPERSAND_AMPERSAND) {
3970 return _visitTest(node); 4000 return _visitTest(node);
3971 } 4001 }
3972 4002
3973 var left = node.leftOperand; 4003 var left = node.leftOperand;
3974 var right = node.rightOperand; 4004 var right = node.rightOperand;
3975 4005
3976 var leftType = getStaticType(left); 4006 var leftType = getStaticType(left);
3977 var rightType = getStaticType(right); 4007 var rightType = getStaticType(right);
3978 4008
3979 var code; 4009 var code;
3980 if (op.type.isEqualityOperator) { 4010 if (op.type.isEqualityOperator) {
3981 // If we statically know LHS or RHS is null we can generate a clean check. 4011 // If we statically know LHS or RHS is null we can generate a clean check.
3982 // We can also do this if both sides are the same primitive type. 4012 // We can also do this if both sides are the same primitive type.
3983 if (_canUsePrimitiveEquality(left, right)) { 4013 if (_canUsePrimitiveEquality(left, right)) {
3984 code = op.type == TokenType.EQ_EQ ? '# == #' : '# != #'; 4014 code = op.type == TokenType.EQ_EQ ? '# == #' : '# != #';
3985 } else if (left is SuperExpression) { 4015 } else if (left is SuperExpression) {
3986 return _emitSend(left, op.lexeme, [right]); 4016 return _emitSend(left, op.lexeme, [right]);
3987 } else { 4017 } else {
3988 var bang = op.type == TokenType.BANG_EQ ? '!' : ''; 4018 var bang = op.type == TokenType.BANG_EQ ? '!' : '';
3989 code = '${bang}dart.equals(#, #)'; 4019 code = '${bang}#.equals(#, #)';
4020 return js.call(code, [_runtimeModule, _visit(left), _visit(right)]);
3990 } 4021 }
3991 return js.call(code, [_visit(left), _visit(right)]); 4022 return js.call(code, [_visit(left), _visit(right)]);
3992 } 4023 }
3993 4024
3994 if (op.type.lexeme == '??') { 4025 if (op.type.lexeme == '??') {
3995 // TODO(jmesserly): leave RHS for debugging? 4026 // TODO(jmesserly): leave RHS for debugging?
3996 // This should be a hint or warning for dead code. 4027 // This should be a hint or warning for dead code.
3997 if (!isNullable(left)) return _visit(left); 4028 if (!isNullable(left)) return _visit(left);
3998 4029
3999 var vars = <JS.MetaLetVariable, JS.Expression>{}; 4030 var vars = <JS.MetaLetVariable, JS.Expression>{};
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after
4292 // as it will go, e.g. at the level the generic class is defined where type 4323 // as it will go, e.g. at the level the generic class is defined where type
4293 // params are available. 4324 // params are available.
4294 if (_currentFunction == null || usesTypeParams) return jsExpr; 4325 if (_currentFunction == null || usesTypeParams) return jsExpr;
4295 4326
4296 var temp = new JS.TemporaryId('const'); 4327 var temp = new JS.TemporaryId('const');
4297 _moduleItems.add(js.statement('let #;', [temp])); 4328 _moduleItems.add(js.statement('let #;', [temp]));
4298 return js.call('# || (# = #)', [temp, temp, jsExpr]); 4329 return js.call('# || (# = #)', [temp, temp, jsExpr]);
4299 } 4330 }
4300 4331
4301 JS.Expression _emitConst(JS.Expression expr()) => 4332 JS.Expression _emitConst(JS.Expression expr()) =>
4302 _cacheConst(() => js.call('dart.const(#)', expr())); 4333 _cacheConst(() => _callHelper('const(#)', expr()));
4303 4334
4304 /// Returns a new expression, which can be be used safely *once* on the 4335 /// Returns a new expression, which can be be used safely *once* on the
4305 /// left hand side, and *once* on the right side of an assignment. 4336 /// left hand side, and *once* on the right side of an assignment.
4306 /// For example: `expr1[expr2] += y` can be compiled as 4337 /// For example: `expr1[expr2] += y` can be compiled as
4307 /// `expr1[expr2] = expr1[expr2] + y`. 4338 /// `expr1[expr2] = expr1[expr2] + y`.
4308 /// 4339 ///
4309 /// The temporary scope will ensure `expr1` and `expr2` are only evaluated 4340 /// The temporary scope will ensure `expr1` and `expr2` are only evaluated
4310 /// once: `((x1, x2) => x1[x2] = x1[x2] + y)(expr1, expr2)`. 4341 /// once: `((x1, x2) => x1[x2] = x1[x2] + y)(expr1, expr2)`.
4311 /// 4342 ///
4312 /// If the expression does not end up using `x1` or `x2` more than once, or 4343 /// If the expression does not end up using `x1` or `x2` more than once, or
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after
4554 _createTemporary('_', nodeTarget.staticType, nullable: false); 4585 _createTemporary('_', nodeTarget.staticType, nullable: false);
4555 var baseNode = _stripNullAwareOp(node, param); 4586 var baseNode = _stripNullAwareOp(node, param);
4556 tail.add( 4587 tail.add(
4557 new JS.ArrowFun(<JS.Parameter>[_visit(param)], _visit(baseNode))); 4588 new JS.ArrowFun(<JS.Parameter>[_visit(param)], _visit(baseNode)));
4558 node = nodeTarget; 4589 node = nodeTarget;
4559 } else { 4590 } else {
4560 break; 4591 break;
4561 } 4592 }
4562 } 4593 }
4563 if (tail.isEmpty) return _visit(node); 4594 if (tail.isEmpty) return _visit(node);
4564 return js.call( 4595 return _callHelper(
4565 'dart.nullSafe(#, #)', [_visit(node) as JS.Expression, tail.reversed]); 4596 'nullSafe(#, #)', [_visit(node) as JS.Expression, tail.reversed]);
4566 } 4597 }
4567 4598
4568 static Token _getOperator(Expression node) { 4599 static Token _getOperator(Expression node) {
4569 if (node is PropertyAccess) return node.operator; 4600 if (node is PropertyAccess) return node.operator;
4570 if (node is MethodInvocation) return node.operator; 4601 if (node is MethodInvocation) return node.operator;
4571 return null; 4602 return null;
4572 } 4603 }
4573 4604
4574 // TODO(jmesserly): this is dropping source location. 4605 // TODO(jmesserly): this is dropping source location.
4575 Expression _stripNullAwareOp(Expression node, Expression newTarget) { 4606 Expression _stripNullAwareOp(Expression node, Expression newTarget) {
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
4652 JS.Expression _emitAccessInternal(Expression target, Element member, 4683 JS.Expression _emitAccessInternal(Expression target, Element member,
4653 String memberName, List<JS.Expression> typeArgs) { 4684 String memberName, List<JS.Expression> typeArgs) {
4654 bool isStatic = member is ClassMemberElement && member.isStatic; 4685 bool isStatic = member is ClassMemberElement && member.isStatic;
4655 var name = _emitMemberName(memberName, 4686 var name = _emitMemberName(memberName,
4656 type: getStaticType(target), isStatic: isStatic); 4687 type: getStaticType(target), isStatic: isStatic);
4657 if (isDynamicInvoke(target)) { 4688 if (isDynamicInvoke(target)) {
4658 if (_inWhitelistCode(target)) { 4689 if (_inWhitelistCode(target)) {
4659 var vars = <JS.MetaLetVariable, JS.Expression>{}; 4690 var vars = <JS.MetaLetVariable, JS.Expression>{};
4660 var l = _visit(_bindValue(vars, 'l', target)); 4691 var l = _visit(_bindValue(vars, 'l', target));
4661 return new JS.MetaLet(vars, [ 4692 return new JS.MetaLet(vars, [
4662 js.call('(#[dart._extensionType]) ? #[dartx[#]] : #.#', 4693 js.call('(#[#._extensionType]) ? #[#[#]] : #.#',
4663 [l, l, name, l, name]) 4694 [l, _runtimeModule, l, _extensionSymbolsModule, name, l, name])
4664 ]); 4695 ]);
4665 } 4696 }
4666 return js.call('dart.#(#, #)', 4697 return _callHelper('#(#, #)',
4667 [_emitDynamicOperationName('dload'), _visit(target), name]); 4698 [_emitDynamicOperationName('dload'), _visit(target), name]);
4668 } 4699 }
4669 4700
4670 var jsTarget = _visit(target); 4701 var jsTarget = _visit(target);
4671 bool isSuper = jsTarget is JS.Super; 4702 bool isSuper = jsTarget is JS.Super;
4672 4703
4673 if (isSuper && member is FieldElement && !member.isSynthetic) { 4704 if (isSuper && member is FieldElement && !member.isSynthetic) {
4674 // If super.x is actually a field, then x is an instance property since 4705 // If super.x is actually a field, then x is an instance property since
4675 // subclasses cannot override x. 4706 // subclasses cannot override x.
4676 jsTarget = new JS.This(); 4707 jsTarget = new JS.This();
4677 } 4708 }
4678 4709
4679 JS.Expression result; 4710 JS.Expression result;
4680 if (member != null && member is MethodElement && !isStatic) { 4711 if (member != null && member is MethodElement && !isStatic) {
4681 // Tear-off methods: explicitly bind it. 4712 // Tear-off methods: explicitly bind it.
4682 if (isSuper) { 4713 if (isSuper) {
4683 result = js.call('dart.bind(this, #, #.#)', [name, jsTarget, name]); 4714 result = _callHelper('bind(this, #, #.#)', [name, jsTarget, name]);
4684 } else if (_isObjectMemberCall(target, memberName)) { 4715 } else if (_isObjectMemberCall(target, memberName)) {
4685 result = js.call('dart.bind(#, #, dart.#)', 4716 result = _callHelper('bind(#, #, #.#)',
4686 [jsTarget, _propertyName(memberName), memberName]); 4717 [jsTarget, _propertyName(memberName), _runtimeModule, memberName]);
4687 } else { 4718 } else {
4688 result = js.call('dart.bind(#, #)', [jsTarget, name]); 4719 result = _callHelper('bind(#, #)', [jsTarget, name]);
4689 } 4720 }
4690 } else if (_isObjectMemberCall(target, memberName)) { 4721 } else if (_isObjectMemberCall(target, memberName)) {
4691 result = js.call('dart.#(#)', [memberName, jsTarget]); 4722 result = _callHelper('#(#)', [memberName, jsTarget]);
4692 } else { 4723 } else {
4693 result = js.call('#.#', [jsTarget, name]); 4724 result = js.call('#.#', [jsTarget, name]);
4694 } 4725 }
4695 if (typeArgs == null) { 4726 if (typeArgs == null) {
4696 return result; 4727 return result;
4697 } 4728 }
4698 return js.call('dart.gbind(#, #)', [result, typeArgs]); 4729 return _callHelper('gbind(#, #)', [result, typeArgs]);
4699 } 4730 }
4700 4731
4701 /// Emits a generic send, like an operator method. 4732 /// Emits a generic send, like an operator method.
4702 /// 4733 ///
4703 /// **Please note** this function does not support method invocation syntax 4734 /// **Please note** this function does not support method invocation syntax
4704 /// `obj.name(args)` because that could be a getter followed by a call. 4735 /// `obj.name(args)` because that could be a getter followed by a call.
4705 /// See [visitMethodInvocation]. 4736 /// See [visitMethodInvocation].
4706 JS.Expression _emitSend( 4737 JS.Expression _emitSend(
4707 Expression target, String name, List<Expression> args) { 4738 Expression target, String name, List<Expression> args) {
4708 var type = getStaticType(target); 4739 var type = getStaticType(target);
4709 var memberName = _emitMemberName(name, type: type); 4740 var memberName = _emitMemberName(name, type: type);
4710 if (isDynamicInvoke(target)) { 4741 if (isDynamicInvoke(target)) {
4711 if (_inWhitelistCode(target)) { 4742 if (_inWhitelistCode(target)) {
4712 var vars = <JS.MetaLetVariable, JS.Expression>{}; 4743 var vars = <JS.MetaLetVariable, JS.Expression>{};
4713 var l = _visit(_bindValue(vars, 'l', target)); 4744 var l = _visit(_bindValue(vars, 'l', target));
4714 return new JS.MetaLet(vars, [ 4745 return new JS.MetaLet(vars, [
4715 js.call('(#[(#[dart._extensionType]) ? dartx[#] : #]).call(#, #)', 4746 js.call('(#[(#[#._extensionType]) ? #[#] : #]).call(#, #)', [
4716 [l, l, memberName, memberName, l, _visitList(args)]) 4747 l,
4748 l,
4749 _runtimeModule,
4750 memberName,
4751 _extensionSymbolsModule,
4752 memberName,
4753 l,
4754 _visitList(args)
4755 ])
4717 ]); 4756 ]);
4718 } 4757 }
4719 // dynamic dispatch 4758 // dynamic dispatch
4720 var dynamicHelper = const {'[]': 'dindex', '[]=': 'dsetindex'}[name]; 4759 var dynamicHelper = const {'[]': 'dindex', '[]=': 'dsetindex'}[name];
4721 if (dynamicHelper != null) { 4760 if (dynamicHelper != null) {
4722 return js.call('dart.$dynamicHelper(#, #)', 4761 return _callHelper('$dynamicHelper(#, #)',
4723 [_visit(target) as JS.Expression, _visitList(args)]); 4762 [_visit(target) as JS.Expression, _visitList(args)]);
4724 } else { 4763 } else {
4725 return js.call('dart.dsend(#, #, #)', 4764 return _callHelper(
4726 [_visit(target), memberName, _visitList(args)]); 4765 'dsend(#, #, #)', [_visit(target), memberName, _visitList(args)]);
4727 } 4766 }
4728 } 4767 }
4729 4768
4730 // Generic dispatch to a statically known method. 4769 // Generic dispatch to a statically known method.
4731 return js.call('#.#(#)', [_visit(target), memberName, _visitList(args)]); 4770 return js.call('#.#(#)', [_visit(target), memberName, _visitList(args)]);
4732 } 4771 }
4733 4772
4734 @override 4773 @override
4735 visitIndexExpression(IndexExpression node) { 4774 visitIndexExpression(IndexExpression node) {
4736 var target = _getTarget(node); 4775 var target = _getTarget(node);
(...skipping 23 matching lines...) Expand all
4760 _visitTest(node.condition), 4799 _visitTest(node.condition),
4761 _visit(node.thenExpression), 4800 _visit(node.thenExpression),
4762 _visit(node.elseExpression) 4801 _visit(node.elseExpression)
4763 ]); 4802 ]);
4764 } 4803 }
4765 4804
4766 @override 4805 @override
4767 visitThrowExpression(ThrowExpression node) { 4806 visitThrowExpression(ThrowExpression node) {
4768 var expr = _visit(node.expression); 4807 var expr = _visit(node.expression);
4769 if (node.parent is ExpressionStatement) { 4808 if (node.parent is ExpressionStatement) {
4770 return js.statement('dart.throw(#);', expr); 4809 return _callHelperStatement('throw(#);', expr);
4771 } else { 4810 } else {
4772 return js.call('dart.throw(#)', expr); 4811 return _callHelper('throw(#)', expr);
4773 } 4812 }
4774 } 4813 }
4775 4814
4776 @override 4815 @override
4777 visitRethrowExpression(RethrowExpression node) { 4816 visitRethrowExpression(RethrowExpression node) {
4778 if (node.parent is ExpressionStatement) { 4817 if (node.parent is ExpressionStatement) {
4779 return js.statement('throw #;', _visit(_catchParameter)); 4818 return js.statement('throw #;', _visit(_catchParameter));
4780 } else { 4819 } else {
4781 return js.call('throw #', _visit(_catchParameter)); 4820 return js.call('throw #', _visit(_catchParameter));
4782 } 4821 }
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
4965 var savedCatch = _catchParameter; 5004 var savedCatch = _catchParameter;
4966 if (node.catchKeyword != null) { 5005 if (node.catchKeyword != null) {
4967 var name = node.exceptionParameter; 5006 var name = node.exceptionParameter;
4968 if (name != null && name != _catchParameter) { 5007 if (name != null && name != _catchParameter) {
4969 body.add(js 5008 body.add(js
4970 .statement('let # = #;', [_visit(name), _visit(_catchParameter)])); 5009 .statement('let # = #;', [_visit(name), _visit(_catchParameter)]));
4971 _catchParameter = name; 5010 _catchParameter = name;
4972 } 5011 }
4973 if (node.stackTraceParameter != null) { 5012 if (node.stackTraceParameter != null) {
4974 var stackVar = node.stackTraceParameter.name; 5013 var stackVar = node.stackTraceParameter.name;
4975 body.add(js.statement( 5014 body.add(js.statement('let # = #.stackTrace(#);',
4976 'let # = dart.stackTrace(#);', [stackVar, _visit(name)])); 5015 [stackVar, _runtimeModule, _visit(name)]));
4977 } 5016 }
4978 } 5017 }
4979 5018
4980 body.add( 5019 body.add(
4981 new JS.Block(_visitList(node.body.statements) as List<JS.Statement>)); 5020 new JS.Block(_visitList(node.body.statements) as List<JS.Statement>));
4982 _catchParameter = savedCatch; 5021 _catchParameter = savedCatch;
4983 return _statement(body); 5022 return _statement(body);
4984 } 5023 }
4985 5024
4986 @override 5025 @override
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
5048 ParameterizedType type = node.staticType; 5087 ParameterizedType type = node.staticType;
5049 var elementType = type.typeArguments.single; 5088 var elementType = type.typeArguments.single;
5050 // TODO(jmesserly): analyzer will usually infer `List<Object>` because 5089 // TODO(jmesserly): analyzer will usually infer `List<Object>` because
5051 // that is the least upper bound of the element types. So we rarely 5090 // that is the least upper bound of the element types. So we rarely
5052 // generate a plain `List<dynamic>` anymore. 5091 // generate a plain `List<dynamic>` anymore.
5053 if (!elementType.isDynamic || isConst) { 5092 if (!elementType.isDynamic || isConst) {
5054 // dart.list helper internally depends on _interceptors.JSArray. 5093 // dart.list helper internally depends on _interceptors.JSArray.
5055 _declareBeforeUse(_jsArray); 5094 _declareBeforeUse(_jsArray);
5056 if (isConst) { 5095 if (isConst) {
5057 var typeRep = _emitType(elementType); 5096 var typeRep = _emitType(elementType);
5058 list = js.call('dart.constList(#, #)', [list, typeRep]); 5097 list = _callHelper('constList(#, #)', [list, typeRep]);
5059 } else { 5098 } else {
5060 // Call `new JSArray<E>.of(list)` 5099 // Call `new JSArray<E>.of(list)`
5061 var jsArrayType = _jsArray.type.instantiate(type.typeArguments); 5100 var jsArrayType = _jsArray.type.instantiate(type.typeArguments);
5062 list = js.call('#.of(#)', [_emitType(jsArrayType), list]); 5101 list = js.call('#.of(#)', [_emitType(jsArrayType), list]);
5063 } 5102 }
5064 } 5103 }
5065 return list; 5104 return list;
5066 } 5105 }
5067 5106
5068 if (isConst) return _cacheConst(emitList); 5107 if (isConst) return _cacheConst(emitList);
(...skipping 25 matching lines...) Expand all
5094 for (var e in entries) { 5133 for (var e in entries) {
5095 values.add(_visit(e.key)); 5134 values.add(_visit(e.key));
5096 values.add(_visit(e.value)); 5135 values.add(_visit(e.value));
5097 } 5136 }
5098 mapArguments = new JS.ArrayInitializer(values); 5137 mapArguments = new JS.ArrayInitializer(values);
5099 } 5138 }
5100 var types = <JS.Expression>[]; 5139 var types = <JS.Expression>[];
5101 if (reifyTypeArgs) { 5140 if (reifyTypeArgs) {
5102 types.addAll(typeArgs.map((e) => _emitType(e))); 5141 types.addAll(typeArgs.map((e) => _emitType(e)));
5103 } 5142 }
5104 return js.call('dart.map(#, #)', [mapArguments, types]); 5143 return _callHelper('map(#, #)', [mapArguments, types]);
5105 } 5144 }
5106 5145
5107 if (node.constKeyword != null) return _emitConst(emitMap); 5146 if (node.constKeyword != null) return _emitConst(emitMap);
5108 return emitMap(); 5147 return emitMap();
5109 } 5148 }
5110 5149
5111 @override 5150 @override
5112 JS.LiteralString visitSimpleStringLiteral(SimpleStringLiteral node) => 5151 JS.LiteralString visitSimpleStringLiteral(SimpleStringLiteral node) =>
5113 js.escapedString(node.value, node.isSingleQuoted ? "'" : '"'); 5152 js.escapedString(node.value, node.isSingleQuoted ? "'" : '"');
5114 5153
5115 @override 5154 @override
5116 JS.Expression visitAdjacentStrings(AdjacentStrings node) => 5155 JS.Expression visitAdjacentStrings(AdjacentStrings node) =>
5117 _visitListToBinary(node.strings, '+'); 5156 _visitListToBinary(node.strings, '+');
5118 5157
5119 @override 5158 @override
5120 JS.Expression visitStringInterpolation(StringInterpolation node) { 5159 JS.Expression visitStringInterpolation(StringInterpolation node) {
5121 return new JS.TaggedTemplate( 5160 return new JS.TaggedTemplate(
5122 js.call('dart.str'), new JS.TemplateString(_visitList(node.elements))); 5161 _callHelper('str'), new JS.TemplateString(_visitList(node.elements)));
5123 } 5162 }
5124 5163
5125 @override 5164 @override
5126 String visitInterpolationString(InterpolationString node) { 5165 String visitInterpolationString(InterpolationString node) {
5127 // TODO(jmesserly): this call adds quotes, and then we strip them off. 5166 // TODO(jmesserly): this call adds quotes, and then we strip them off.
5128 var str = js.escapedString(node.value, '`').value; 5167 var str = js.escapedString(node.value, '`').value;
5129 return str.substring(1, str.length - 1); 5168 return str.substring(1, str.length - 1);
5130 } 5169 }
5131 5170
5132 @override 5171 @override
5133 visitInterpolationExpression(InterpolationExpression node) => 5172 visitInterpolationExpression(InterpolationExpression node) =>
5134 _visit(node.expression); 5173 _visit(node.expression);
5135 5174
5136 @override 5175 @override
5137 visitBooleanLiteral(BooleanLiteral node) => js.boolean(node.value); 5176 visitBooleanLiteral(BooleanLiteral node) => js.boolean(node.value);
5138 5177
5139 @override 5178 @override
5140 JS.Expression visitExpression(Expression node) => 5179 JS.Expression visitExpression(Expression node) =>
5141 _unimplementedCall('Unimplemented ${node.runtimeType}: $node'); 5180 _unimplementedCall('Unimplemented ${node.runtimeType}: $node');
5142 5181
5143 JS.Expression _unimplementedCall(String comment) { 5182 JS.Expression _unimplementedCall(String comment) {
5144 return js.call('dart.throw(#)', [js.escapedString(comment)]); 5183 return _callHelper('throw(#)', [js.escapedString(comment)]);
5145 } 5184 }
5146 5185
5147 @override 5186 @override
5148 visitNode(AstNode node) { 5187 visitNode(AstNode node) {
5149 // TODO(jmesserly): verify this is unreachable. 5188 // TODO(jmesserly): verify this is unreachable.
5150 throw 'Unimplemented ${node.runtimeType}: $node'; 5189 throw 'Unimplemented ${node.runtimeType}: $node';
5151 } 5190 }
5152 5191
5153 _visit(AstNode node) { 5192 _visit(AstNode node) {
5154 if (node == null) return null; 5193 if (node == null) return null;
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
5191 return finish(js.call(code, 5230 return finish(js.call(code,
5192 [_visitTest(node.leftOperand), _visitTest(node.rightOperand)])); 5231 [_visitTest(node.leftOperand), _visitTest(node.rightOperand)]));
5193 } 5232 }
5194 5233
5195 var op = node.operator.type.lexeme; 5234 var op = node.operator.type.lexeme;
5196 if (op == '&&') return shortCircuit('# && #'); 5235 if (op == '&&') return shortCircuit('# && #');
5197 if (op == '||') return shortCircuit('# || #'); 5236 if (op == '||') return shortCircuit('# || #');
5198 } 5237 }
5199 if (node is AsExpression && CoercionReifier.isImplicitCast(node)) { 5238 if (node is AsExpression && CoercionReifier.isImplicitCast(node)) {
5200 assert(node.staticType == types.boolType); 5239 assert(node.staticType == types.boolType);
5201 return js.call('dart.test(#)', _visit(node.expression)); 5240 return _callHelper('test(#)', _visit(node.expression));
5202 } 5241 }
5203 JS.Expression result = _visit(node); 5242 JS.Expression result = _visit(node);
5204 if (isNullable(node)) result = js.call('dart.test(#)', result); 5243 if (isNullable(node)) result = _callHelper('test(#)', result);
5205 return result; 5244 return result;
5206 } 5245 }
5207 5246
5208 /// Like [_emitMemberName], but for declaration sites. 5247 /// Like [_emitMemberName], but for declaration sites.
5209 /// 5248 ///
5210 /// Unlike call sites, we always have an element available, so we can use it 5249 /// Unlike call sites, we always have an element available, so we can use it
5211 /// directly rather than computing the relevant options for [_emitMemberName]. 5250 /// directly rather than computing the relevant options for [_emitMemberName].
5212 JS.Expression _declareMemberName(ExecutableElement e, {bool useExtension}) { 5251 JS.Expression _declareMemberName(ExecutableElement e, {bool useExtension}) {
5213 String name; 5252 String name;
5214 if (e is PropertyAccessorElement) { 5253 if (e is PropertyAccessorElement) {
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
5295 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. 5334 // Dart "extension" methods. Used for JS Array, Boolean, Number, String.
5296 var baseType = type; 5335 var baseType = type;
5297 while (baseType is TypeParameterType) { 5336 while (baseType is TypeParameterType) {
5298 baseType = (baseType.element as TypeParameterElement).bound; 5337 baseType = (baseType.element as TypeParameterElement).bound;
5299 } 5338 }
5300 useExtension = baseType != null && 5339 useExtension = baseType != null &&
5301 _extensionTypes.hasNativeSubtype(baseType) && 5340 _extensionTypes.hasNativeSubtype(baseType) &&
5302 !isObjectMember(name); 5341 !isObjectMember(name);
5303 } 5342 }
5304 5343
5305 return useExtension ? js.call('dartx.#', result) : result; 5344 return useExtension
5345 ? js.call('#.#', [_extensionSymbolsModule, result])
5346 : result;
5306 } 5347 }
5307 5348
5308 JS.TemporaryId _emitPrivateNameSymbol(LibraryElement library, String name) { 5349 JS.TemporaryId _emitPrivateNameSymbol(LibraryElement library, String name) {
5309 return _privateNames 5350 return _privateNames
5310 .putIfAbsent(library, () => new HashMap()) 5351 .putIfAbsent(library, () => new HashMap())
5311 .putIfAbsent(name, () { 5352 .putIfAbsent(name, () {
5312 var id = new JS.TemporaryId(name); 5353 var id = new JS.TemporaryId(name);
5313 _moduleItems.add( 5354 _moduleItems.add(
5314 js.statement('const # = Symbol(#);', [id, js.string(id.name, "'")])); 5355 js.statement('const # = Symbol(#);', [id, js.string(id.name, "'")]));
5315 return id; 5356 return id;
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
5398 return type; 5439 return type;
5399 } else if (type is InterfaceType && type.element == expectedType.element) { 5440 } else if (type is InterfaceType && type.element == expectedType.element) {
5400 return type.typeArguments[0]; 5441 return type.typeArguments[0];
5401 } else { 5442 } else {
5402 // TODO(leafp): The above only handles the case where the return type 5443 // TODO(leafp): The above only handles the case where the return type
5403 // is exactly Future/Stream/Iterable. Handle the subtype case. 5444 // is exactly Future/Stream/Iterable. Handle the subtype case.
5404 return DynamicTypeImpl.instance; 5445 return DynamicTypeImpl.instance;
5405 } 5446 }
5406 } 5447 }
5407 5448
5449 JS.Expression _callHelper(String code, [args]) {
5450 if (args is List) {
5451 args.insert(0, _runtimeModule);
5452 } else if (args != null) {
5453 args = [_runtimeModule, args];
5454 } else {
5455 args = _runtimeModule;
5456 }
5457 return js.call('#.$code', args);
5458 }
5459
5460 JS.Statement _callHelperStatement(String code, args) {
5461 if (args is List) {
5462 args.insert(0, _runtimeModule);
5463 } else {
5464 args = [_runtimeModule, args];
5465 }
5466 return js.statement('#.$code', args);
5467 }
5468
5408 /// Maps whitelisted files to a list of whitelisted methods 5469 /// Maps whitelisted files to a list of whitelisted methods
5409 /// within the file. 5470 /// within the file.
5410 /// 5471 ///
5411 /// If the value is null, the entire file is whitelisted. 5472 /// If the value is null, the entire file is whitelisted.
5412 /// 5473 ///
5413 // TODO(jmesserly): why is this here, and what can we do to remove it? 5474 // TODO(jmesserly): why is this here, and what can we do to remove it?
5414 // 5475 //
5415 // Hard coded lists are completely unnecessary -- if a feature is needed, 5476 // Hard coded lists are completely unnecessary -- if a feature is needed,
5416 // metadata, type system features, or command line options are the right way 5477 // metadata, type system features, or command line options are the right way
5417 // to express it. 5478 // to express it.
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
5512 } 5573 }
5513 5574
5514 bool isLibraryPrefix(Expression node) => 5575 bool isLibraryPrefix(Expression node) =>
5515 node is SimpleIdentifier && node.staticElement is PrefixElement; 5576 node is SimpleIdentifier && node.staticElement is PrefixElement;
5516 5577
5517 LibraryElement _getLibrary(AnalysisContext c, String uri) => 5578 LibraryElement _getLibrary(AnalysisContext c, String uri) =>
5518 c.computeLibraryElement(c.sourceFactory.forUri(uri)); 5579 c.computeLibraryElement(c.sourceFactory.forUri(uri));
5519 5580
5520 bool _isDartRuntime(LibraryElement l) => 5581 bool _isDartRuntime(LibraryElement l) =>
5521 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; 5582 l.isInSdk && l.source.uri.toString() == 'dart:_runtime';
OLDNEW
« no previous file with comments | « no previous file | pkg/dev_compiler/lib/src/compiler/type_utilities.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698