OLD | NEW |
---|---|
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import 'dart:collection' show HashMap, HashSet; | 5 import 'dart:collection' show HashMap, HashSet; |
6 import 'dart:math' show min, max; | 6 import 'dart:math' show min, max; |
7 | 7 |
8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
9 import 'package:analyzer/dart/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; | 10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
111 FunctionBody _currentFunction; | 111 FunctionBody _currentFunction; |
112 | 112 |
113 /// Helper class for emitting elements in the proper order to allow | 113 /// Helper class for emitting elements in the proper order to allow |
114 /// JS to load the module. | 114 /// JS to load the module. |
115 ElementLoader _loader; | 115 ElementLoader _loader; |
116 | 116 |
117 BuildUnit _buildUnit; | 117 BuildUnit _buildUnit; |
118 | 118 |
119 String _buildRoot; | 119 String _buildRoot; |
120 | 120 |
121 bool _superAllowed = true; | |
122 | |
123 List<JS.TemporaryId> _superHelperSymbols = <JS.TemporaryId>[]; | |
124 List<JS.Method> _superHelpers = <JS.Method>[]; | |
125 | |
121 /// Whether we are currently generating code for the body of a `JS()` call. | 126 /// Whether we are currently generating code for the body of a `JS()` call. |
122 bool _isInForeignJS = false; | 127 bool _isInForeignJS = false; |
123 | 128 |
124 CodeGenerator(AnalysisContext c, this.options, this._extensionTypes) | 129 CodeGenerator(AnalysisContext c, this.options, this._extensionTypes) |
125 : context = c, | 130 : context = c, |
126 types = c.typeProvider, | 131 types = c.typeProvider, |
127 _asyncStreamIterator = | 132 _asyncStreamIterator = |
128 _getLibrary(c, 'dart:async').getType('StreamIterator').type, | 133 _getLibrary(c, 'dart:async').getType('StreamIterator').type, |
129 _jsArray = _getLibrary(c, 'dart:_interceptors').getType('JSArray'), | 134 _jsArray = _getLibrary(c, 'dart:_interceptors').getType('JSArray'), |
130 dartCoreLibrary = _getLibrary(c, 'dart:core'), | 135 dartCoreLibrary = _getLibrary(c, 'dart:core'), |
(...skipping 457 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
588 _registerPropertyOverrides(classElem, className, superclasses, allFields, | 593 _registerPropertyOverrides(classElem, className, superclasses, allFields, |
589 virtualFields, virtualFieldSymbols, staticFieldOverrides); | 594 virtualFields, virtualFieldSymbols, staticFieldOverrides); |
590 | 595 |
591 var classExpr = _emitClassExpression(classElem, | 596 var classExpr = _emitClassExpression(classElem, |
592 _emitClassMethods(node, ctors, fields, superclasses, virtualFields), | 597 _emitClassMethods(node, ctors, fields, superclasses, virtualFields), |
593 fields: allFields); | 598 fields: allFields); |
594 | 599 |
595 var body = <JS.Statement>[]; | 600 var body = <JS.Statement>[]; |
596 var extensions = _extensionsToImplement(classElem); | 601 var extensions = _extensionsToImplement(classElem); |
597 _initExtensionSymbols(classElem, methods, fields, body); | 602 _initExtensionSymbols(classElem, methods, fields, body); |
603 _emitSuperHelperSymbols(_superHelperSymbols, body); | |
598 | 604 |
599 // Emit the class, e.g. `core.Object = class Object { ... }` | 605 // Emit the class, e.g. `core.Object = class Object { ... }` |
600 _defineClass(classElem, className, classExpr, body); | 606 _defineClass(classElem, className, classExpr, body); |
601 | 607 |
602 // Emit things that come after the ES6 `class ... { ... }`. | 608 // Emit things that come after the ES6 `class ... { ... }`. |
603 _setBaseClass(classElem, className, body); | 609 _setBaseClass(classElem, className, body); |
604 _defineNamedConstructors(ctors, body, className); | 610 _defineNamedConstructors(ctors, body, className); |
605 _emitVirtualFieldSymbols(virtualFieldSymbols, body); | 611 _emitVirtualFieldSymbols(virtualFieldSymbols, body); |
606 _emitClassSignature(methods, classElem, ctors, extensions, className, body); | 612 _emitClassSignature(methods, classElem, ctors, extensions, className, body); |
607 _defineExtensionMembers(extensions, className, body); | 613 _defineExtensionMembers(extensions, className, body); |
608 _emitClassMetadata(node.metadata, className, body); | 614 _emitClassMetadata(node.metadata, className, body); |
609 | 615 |
610 JS.Statement classDef = _statement(body); | 616 JS.Statement classDef = _statement(body); |
611 var typeFormals = classElem.typeParameters; | 617 var typeFormals = classElem.typeParameters; |
612 if (typeFormals.isNotEmpty) { | 618 if (typeFormals.isNotEmpty) { |
613 classDef = _defineClassTypeArguments(classElem, typeFormals, classDef); | 619 classDef = _defineClassTypeArguments(classElem, typeFormals, classDef); |
614 } | 620 } |
615 | 621 |
616 body = <JS.Statement>[classDef]; | 622 body = <JS.Statement>[classDef]; |
617 _emitStaticFields(staticFields, staticFieldOverrides, classElem, body); | 623 _emitStaticFields(staticFields, staticFieldOverrides, classElem, body); |
618 _registerExtensionType(classElem, body); | 624 _registerExtensionType(classElem, body); |
619 return _statement(body); | 625 return _statement(body); |
620 } | 626 } |
621 | 627 |
628 void _emitSuperHelperSymbols( | |
629 List<JS.TemporaryId> superHelperSymbols, List<JS.Statement> body) { | |
630 for (var id in superHelperSymbols) { | |
631 body.add(js.statement('const # = Symbol(#)', [id, js.string(id.name)])); | |
632 } | |
633 superHelperSymbols.clear(); | |
634 } | |
635 | |
622 void _registerPropertyOverrides( | 636 void _registerPropertyOverrides( |
623 ClassElement classElem, | 637 ClassElement classElem, |
624 JS.Expression className, | 638 JS.Expression className, |
625 List<ClassElement> superclasses, | 639 List<ClassElement> superclasses, |
626 List<FieldDeclaration> fields, | 640 List<FieldDeclaration> fields, |
627 Map<FieldElement, JS.TemporaryId> virtualFields, | 641 Map<FieldElement, JS.TemporaryId> virtualFields, |
628 List<JS.Statement> virtualFieldSymbols, | 642 List<JS.Statement> virtualFieldSymbols, |
629 Set<FieldElement> staticFieldOverrides) { | 643 Set<FieldElement> staticFieldOverrides) { |
630 for (var field in fields) { | 644 for (var field in fields) { |
631 for (VariableDeclaration field in field.fields.variables) { | 645 for (VariableDeclaration field in field.fields.variables) { |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
890 // helper on a parent class. This pattern is common in the core libraries | 904 // helper on a parent class. This pattern is common in the core libraries |
891 // (e.g. IterableMixin<E> and IterableBase<E>). | 905 // (e.g. IterableMixin<E> and IterableBase<E>). |
892 // | 906 // |
893 // (We could do this same optimization for any interface with an `iterator` | 907 // (We could do this same optimization for any interface with an `iterator` |
894 // method, but that's more expensive to check for, so it doesn't seem worth | 908 // method, but that's more expensive to check for, so it doesn't seem worth |
895 // it. The above case for an explicit `iterator` method will catch those.) | 909 // it. The above case for an explicit `iterator` method will catch those.) |
896 if (!hasJsPeer && !hasIterator && _implementsIterable(type)) { | 910 if (!hasJsPeer && !hasIterator && _implementsIterable(type)) { |
897 jsMethods.add(_emitIterable(type)); | 911 jsMethods.add(_emitIterable(type)); |
898 } | 912 } |
899 | 913 |
914 // Add all of the super helper methods | |
915 jsMethods.addAll(_superHelpers); | |
916 _superHelpers.clear(); | |
917 | |
900 return jsMethods.where((m) => m != null).toList(growable: false); | 918 return jsMethods.where((m) => m != null).toList(growable: false); |
901 } | 919 } |
902 | 920 |
903 /// This is called whenever a derived class needs to introduce a new field, | 921 /// This is called whenever a derived class needs to introduce a new field, |
904 /// shadowing a field or getter/setter pair on its parent. | 922 /// shadowing a field or getter/setter pair on its parent. |
905 /// | 923 /// |
906 /// This is important because otherwise, trying to read or write the field | 924 /// This is important because otherwise, trying to read or write the field |
907 /// would end up calling the getter or setter, and one of those might not even | 925 /// would end up calling the getter or setter, and one of those might not even |
908 /// exist, resulting in a runtime error. Even if they did exist, that's the | 926 /// exist, resulting in a runtime error. Even if they did exist, that's the |
909 /// wrong behavior if a new field was declared. | 927 /// wrong behavior if a new field was declared. |
(...skipping 713 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1623 return new JS.Fun(params, js.statement('{ return this.#; }', [name])); | 1641 return new JS.Fun(params, js.statement('{ return this.#; }', [name])); |
1624 } else if (node.isSetter) { | 1642 } else if (node.isSetter) { |
1625 return new JS.Fun( | 1643 return new JS.Fun( |
1626 params, js.statement('{ this.# = #; }', [name, params.last])); | 1644 params, js.statement('{ this.# = #; }', [name, params.last])); |
1627 } else { | 1645 } else { |
1628 return new JS.Fun( | 1646 return new JS.Fun( |
1629 params, js.statement('{ return this.#(#); }', [name, params])); | 1647 params, js.statement('{ return this.#(#); }', [name, params])); |
1630 } | 1648 } |
1631 } | 1649 } |
1632 | 1650 |
1633 JS.Method _emitMethodDeclaration(DartType type, MethodDeclaration node) { | 1651 JS.Method _emitMethodDeclaration(InterfaceType type, MethodDeclaration node) { |
1634 if (node.isAbstract) { | 1652 if (node.isAbstract) { |
1635 return null; | 1653 return null; |
1636 } | 1654 } |
1637 | 1655 |
1638 JS.Fun fn; | 1656 JS.Fun fn; |
1639 if (_externalOrNative(node)) { | 1657 if (_externalOrNative(node)) { |
1640 fn = _emitNativeFunctionBody(node); | 1658 fn = _emitNativeFunctionBody(node); |
1641 // TODO(vsm): Remove if / when we handle the static case above. | 1659 // TODO(vsm): Remove if / when we handle the static case above. |
1642 if (fn == null) return null; | 1660 if (fn == null) return null; |
1643 } else { | 1661 } else { |
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1949 // `await` is generated as `yield`. | 1967 // `await` is generated as `yield`. |
1950 // runtime/_generators.js has an example of what the code is generated as. | 1968 // runtime/_generators.js has an example of what the code is generated as. |
1951 var savedController = _asyncStarController; | 1969 var savedController = _asyncStarController; |
1952 List jsParams = visitFormalParameterList(parameters); | 1970 List jsParams = visitFormalParameterList(parameters); |
1953 if (kind == 'asyncStar') { | 1971 if (kind == 'asyncStar') { |
1954 _asyncStarController = new JS.TemporaryId('stream'); | 1972 _asyncStarController = new JS.TemporaryId('stream'); |
1955 jsParams.insert(0, _asyncStarController); | 1973 jsParams.insert(0, _asyncStarController); |
1956 } else { | 1974 } else { |
1957 _asyncStarController = null; | 1975 _asyncStarController = null; |
1958 } | 1976 } |
1977 var savedSuperAllowed = _superAllowed; | |
1978 _superAllowed = false; | |
1959 // Visit the body with our async* controller set. | 1979 // Visit the body with our async* controller set. |
1960 var jsBody = _visit(body); | 1980 var jsBody = _visit(body); |
1981 _superAllowed = savedSuperAllowed; | |
1961 _asyncStarController = savedController; | 1982 _asyncStarController = savedController; |
1962 | 1983 |
1963 DartType returnType = _getExpectedReturnType(element); | 1984 DartType returnType = _getExpectedReturnType(element); |
1964 JS.Expression gen = new JS.Fun(jsParams, jsBody, | 1985 JS.Expression gen = new JS.Fun(jsParams, jsBody, |
1965 isGenerator: true, returnType: emitTypeRef(returnType)); | 1986 isGenerator: true, returnType: emitTypeRef(returnType)); |
1966 if (JS.This.foundIn(gen)) { | 1987 if (JS.This.foundIn(gen)) { |
1967 gen = js.call('#.bind(this)', gen); | 1988 gen = js.call('#.bind(this)', gen); |
1968 } | 1989 } |
1969 | 1990 |
1970 var T = _emitTypeName(returnType); | 1991 var T = _emitTypeName(returnType); |
(...skipping 25 matching lines...) Expand all Loading... | |
1996 return new JS.Block([ | 2017 return new JS.Block([ |
1997 declareFn, | 2018 declareFn, |
1998 _emitFunctionTagged(name, func.element.type).toStatement() | 2019 _emitFunctionTagged(name, func.element.type).toStatement() |
1999 ]); | 2020 ]); |
2000 } | 2021 } |
2001 | 2022 |
2002 /// Emits a simple identifier, including handling an inferred generic | 2023 /// Emits a simple identifier, including handling an inferred generic |
2003 /// function instantiation. | 2024 /// function instantiation. |
2004 @override | 2025 @override |
2005 JS.Expression visitSimpleIdentifier(SimpleIdentifier node) { | 2026 JS.Expression visitSimpleIdentifier(SimpleIdentifier node) { |
2006 return _applyFunctionTypeArguments( | 2027 var typeArgs = _getTypeArgs(node.staticElement, node.staticType); |
2007 _emitSimpleIdentifier(node), node.staticElement, node.staticType); | 2028 var simpleId = _emitSimpleIdentifier(node); |
2029 if (typeArgs == null) { | |
2030 return simpleId; | |
2031 } | |
2032 return js.call('dart.gbind(#, #)', [simpleId, typeArgs]); | |
2008 } | 2033 } |
2009 | 2034 |
2010 /// Emits a simple identifier, handling implicit `this` as well as | 2035 /// Emits a simple identifier, handling implicit `this` as well as |
2011 /// going through the qualified library name if necessary, but *not* handling | 2036 /// going through the qualified library name if necessary, but *not* handling |
2012 /// inferred generic function instantiation. | 2037 /// inferred generic function instantiation. |
2013 JS.Expression _emitSimpleIdentifier(SimpleIdentifier node) { | 2038 JS.Expression _emitSimpleIdentifier(SimpleIdentifier node) { |
2014 var accessor = node.staticElement; | 2039 var accessor = node.staticElement; |
2015 if (accessor == null) { | 2040 if (accessor == null) { |
2016 return js.commentExpression( | 2041 return js.commentExpression( |
2017 'Unimplemented unknown name', new JS.Identifier(node.name)); | 2042 'Unimplemented unknown name', new JS.Identifier(node.name)); |
(...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2377 if (result != null) return result; | 2402 if (result != null) return result; |
2378 | 2403 |
2379 var target = _getTarget(node); | 2404 var target = _getTarget(node); |
2380 if (target == null || isLibraryPrefix(target)) { | 2405 if (target == null || isLibraryPrefix(target)) { |
2381 return _emitFunctionCall(node); | 2406 return _emitFunctionCall(node); |
2382 } | 2407 } |
2383 | 2408 |
2384 return _emitMethodCall(target, node); | 2409 return _emitMethodCall(target, node); |
2385 } | 2410 } |
2386 | 2411 |
2412 JS.Expression _emitMethodCall(Expression target, MethodInvocation node) { | |
2413 List<JS.Expression> args = _visit(node.argumentList); | |
2414 var typeArgs = _emitInvokeTypeArguments(node); | |
2415 | |
2416 if (target is SuperExpression && !_superAllowed) { | |
2417 return _emitSuperHelperCall(typeArgs, args, target, node); | |
2418 } | |
2419 | |
2420 return _emitMethodCallInternal(target, node, args, typeArgs); | |
2421 } | |
2422 | |
2423 JS.Expression _emitSuperHelperCall(List<JS.Expression> typeArgs, | |
2424 List<JS.Expression> args, SuperExpression target, MethodInvocation node) { | |
2425 var fakeTypeArgs = | |
2426 typeArgs?.map((_) => new JS.TemporaryId('a'))?.toList(growable: false); | |
2427 var fakeArgs = | |
2428 args.map((_) => new JS.TemporaryId('a')).toList(growable: false); | |
2429 var combinedFakeArgs = <JS.TemporaryId>[]; | |
2430 if (fakeTypeArgs != null) { | |
2431 combinedFakeArgs.addAll(fakeTypeArgs); | |
2432 } | |
2433 combinedFakeArgs.addAll(fakeArgs); | |
2434 | |
2435 var forwardedCall = | |
2436 _emitMethodCallInternal(target, node, fakeArgs, fakeTypeArgs); | |
2437 var superForwarder = _getSuperHelperFor( | |
2438 node.methodName.name, forwardedCall, combinedFakeArgs); | |
2439 | |
2440 var combinedRealArgs = <JS.Expression>[]; | |
2441 if (typeArgs != null) { | |
2442 combinedRealArgs.addAll(typeArgs); | |
2443 } | |
2444 combinedRealArgs.addAll(args); | |
2445 | |
2446 return js.call('this.#(#)', [superForwarder, combinedRealArgs]); | |
2447 } | |
2448 | |
2449 JS.Expression _getSuperHelperFor(String name, JS.Expression forwardedCall, | |
2450 List<JS.Expression> helperArgs) { | |
2451 var helperMethod = | |
2452 new JS.Fun(helperArgs, new JS.Block([new JS.Return(forwardedCall)])); | |
2453 var helperMethodName = new JS.TemporaryId('super\$$name'); | |
2454 _superHelperSymbols.add(helperMethodName); | |
2455 _superHelpers.add(new JS.Method(helperMethodName, helperMethod)); | |
2456 return helperMethodName; | |
2457 } | |
2458 | |
2387 /// Emits a (possibly generic) instance method call. | 2459 /// Emits a (possibly generic) instance method call. |
2388 JS.Expression _emitMethodCall(Expression target, MethodInvocation node) { | 2460 JS.Expression _emitMethodCallInternal( |
2461 Expression target, | |
2462 MethodInvocation node, | |
2463 List<JS.Expression> args, | |
2464 List<JS.Expression> typeArgs) { | |
2389 var type = getStaticType(target); | 2465 var type = getStaticType(target); |
2390 var name = node.methodName.name; | 2466 var name = node.methodName.name; |
2391 var element = node.methodName.staticElement; | 2467 var element = node.methodName.staticElement; |
2392 bool isStatic = element is ExecutableElement && element.isStatic; | 2468 bool isStatic = element is ExecutableElement && element.isStatic; |
2393 var memberName = _emitMemberName(name, type: type, isStatic: isStatic); | 2469 var memberName = _emitMemberName(name, type: type, isStatic: isStatic); |
2394 | 2470 |
2395 JS.Expression jsTarget = _visit(target); | 2471 JS.Expression jsTarget = _visit(target); |
2396 var typeArgs = _emitInvokeTypeArguments(node); | |
2397 List<JS.Expression> args = _visit(node.argumentList); | |
2398 if (DynamicInvoke.get(target)) { | 2472 if (DynamicInvoke.get(target)) { |
2399 if (typeArgs != null) { | 2473 if (typeArgs != null) { |
2400 return js.call('dart.dgsend(#, #, #, #)', | 2474 return js.call('dart.dgsend(#, #, #, #)', |
2401 [jsTarget, new JS.ArrayInitializer(typeArgs), memberName, args]); | 2475 [jsTarget, new JS.ArrayInitializer(typeArgs), memberName, args]); |
2402 } else { | 2476 } else { |
2403 return js.call('dart.dsend(#, #, #)', [jsTarget, memberName, args]); | 2477 return js.call('dart.dsend(#, #, #)', [jsTarget, memberName, args]); |
2404 } | 2478 } |
2405 } | 2479 } |
2406 if (_isObjectMemberCall(target, name)) { | 2480 if (_isObjectMemberCall(target, name)) { |
2407 // Object methods require a helper for null checks & native types. | 2481 // Object methods require a helper for null checks & native types. |
2408 assert(typeArgs == null); // Object methods don't take type args. | 2482 assert(typeArgs == null); // Object methods don't take type args. |
2409 return js.call('dart.#(#, #)', [memberName, jsTarget, args]); | 2483 return js.call('dart.#(#, #)', [memberName, jsTarget, args]); |
2410 } | 2484 } |
2411 | 2485 |
2412 jsTarget = new JS.PropertyAccess(jsTarget, memberName); | 2486 jsTarget = new JS.PropertyAccess(jsTarget, memberName); |
2487 | |
2413 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); | 2488 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); |
2414 | 2489 |
2415 if (DynamicInvoke.get(node.methodName)) { | 2490 if (DynamicInvoke.get(node.methodName)) { |
2416 // This is a dynamic call to a statically known target. For example: | 2491 // This is a dynamic call to a statically known target. For example: |
2417 // class Foo { Function bar; } | 2492 // class Foo { Function bar; } |
2418 // new Foo().bar(); // dynamic call | 2493 // new Foo().bar(); // dynamic call |
2419 return js.call('dart.dcall(#, #)', [jsTarget, args]); | 2494 return js.call('dart.dcall(#, #)', [jsTarget, args]); |
2420 } | 2495 } |
2421 | 2496 |
2422 return new JS.Call(jsTarget, args); | 2497 return new JS.Call(jsTarget, args); |
(...skipping 1107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3530 } | 3605 } |
3531 | 3606 |
3532 // Check if the target could be `null`, is dynamic, or may be an extension | 3607 // Check if the target could be `null`, is dynamic, or may be an extension |
3533 // native type. In all of those cases we need defensive code generation. | 3608 // native type. In all of those cases we need defensive code generation. |
3534 var type = getStaticType(target); | 3609 var type = getStaticType(target); |
3535 return isNullable(target) || | 3610 return isNullable(target) || |
3536 type.isDynamic || | 3611 type.isDynamic || |
3537 (_extensionTypes.hasNativeSubtype(type) && target is! SuperExpression); | 3612 (_extensionTypes.hasNativeSubtype(type) && target is! SuperExpression); |
3538 } | 3613 } |
3539 | 3614 |
3540 /// Shared code for [PrefixedIdentifier] and [PropertyAccess]. | |
Jennifer Messerly
2016/05/05 23:50:48
just curious, what happened to this comment?
We w
Harry Terkelsen
2016/05/05 23:58:40
Oops, it got dropped when I was moving things arou
| |
3541 JS.Expression _emitAccess( | 3615 JS.Expression _emitAccess( |
3542 Expression target, SimpleIdentifier memberId, DartType resultType) { | 3616 Expression target, SimpleIdentifier memberId, DartType resultType) { |
3543 Element member = memberId.staticElement; | 3617 Element member = memberId.staticElement; |
3544 if (member is PropertyAccessorElement) { | 3618 if (member is PropertyAccessorElement) { |
3545 member = (member as PropertyAccessorElement).variable; | 3619 member = (member as PropertyAccessorElement).variable; |
3546 } | 3620 } |
3621 String memberName = memberId.name; | |
3622 var typeArgs = _getTypeArgs(member, resultType); | |
3623 | |
3624 if (target is SuperExpression && !_superAllowed) { | |
3625 return _emitSuperHelperAccess(target, member, memberName, typeArgs); | |
3626 } | |
3627 return _emitAccessInternal(target, member, memberName, typeArgs); | |
3628 } | |
3629 | |
3630 JS.Expression _emitSuperHelperAccess(SuperExpression target, Element member, | |
3631 String memberName, List<JS.Expression> typeArgs) { | |
3632 var fakeTypeArgs = | |
3633 typeArgs?.map((_) => new JS.TemporaryId('a'))?.toList(growable: false); | |
3634 | |
3635 var forwardedAccess = | |
3636 _emitAccessInternal(target, member, memberName, fakeTypeArgs); | |
3637 var superForwarder = _getSuperHelperFor( | |
3638 memberName, forwardedAccess, fakeTypeArgs ?? const []); | |
3639 | |
3640 return js.call('this.#(#)', [superForwarder, typeArgs ?? const []]); | |
3641 } | |
3642 | |
3643 List<JS.Expression> _getTypeArgs(Element member, DartType instantiated) { | |
3644 DartType type; | |
3645 if (member is ExecutableElement) { | |
3646 type = member.type; | |
3647 } else if (member is VariableElement) { | |
3648 type = member.type; | |
3649 } | |
3650 | |
3651 // TODO(jmesserly): handle explicitly passed type args. | |
3652 if (type == null) return null; | |
3653 return _emitFunctionTypeArguments(type, instantiated); | |
3654 } | |
3655 | |
3656 /// Shared code for [PrefixedIdentifier] and [PropertyAccess]. | |
3657 JS.Expression _emitAccessInternal(Expression target, Element member, | |
3658 String memberName, List<JS.Expression> typeArgs) { | |
3547 bool isStatic = member is ClassMemberElement && member.isStatic; | 3659 bool isStatic = member is ClassMemberElement && member.isStatic; |
3548 var name = _emitMemberName(memberId.name, | 3660 var name = _emitMemberName(memberName, |
3549 type: getStaticType(target), isStatic: isStatic); | 3661 type: getStaticType(target), isStatic: isStatic); |
3550 if (DynamicInvoke.get(target)) { | 3662 if (DynamicInvoke.get(target)) { |
3551 return js.call('dart.dload(#, #)', [_visit(target), name]); | 3663 return js.call('dart.dload(#, #)', [_visit(target), name]); |
3552 } | 3664 } |
3553 | 3665 |
3554 var jsTarget = _visit(target); | 3666 var jsTarget = _visit(target); |
3555 bool isSuper = jsTarget is JS.Super; | 3667 bool isSuper = jsTarget is JS.Super; |
3556 | 3668 |
3557 if (isSuper && member is FieldElement && !member.isSynthetic) { | 3669 if (isSuper && member is FieldElement && !member.isSynthetic) { |
3558 // If super.x is actually a field, then x is an instance property since | 3670 // If super.x is actually a field, then x is an instance property since |
3559 // subclasses cannot override x. | 3671 // subclasses cannot override x. |
3560 jsTarget = new JS.This(); | 3672 jsTarget = new JS.This(); |
3561 } | 3673 } |
3562 | 3674 |
3563 JS.Expression result; | 3675 JS.Expression result; |
3564 if (member != null && member is MethodElement && !isStatic) { | 3676 if (member != null && member is MethodElement && !isStatic) { |
3565 // Tear-off methods: explicitly bind it. | 3677 // Tear-off methods: explicitly bind it. |
3566 if (isSuper) { | 3678 if (isSuper) { |
3567 result = js.call('dart.bind(this, #, #.#)', [name, jsTarget, name]); | 3679 result = js.call('dart.bind(this, #, #.#)', [name, jsTarget, name]); |
3568 } else if (_isObjectMemberCall(target, memberId.name)) { | 3680 } else if (_isObjectMemberCall(target, memberName)) { |
3569 result = js.call('dart.bind(#, #, dart.#)', [jsTarget, name, name]); | 3681 result = js.call('dart.bind(#, #, dart.#)', [jsTarget, name, name]); |
3570 } else { | 3682 } else { |
3571 result = js.call('dart.bind(#, #)', [jsTarget, name]); | 3683 result = js.call('dart.bind(#, #)', [jsTarget, name]); |
3572 } | 3684 } |
3573 } else if (_isObjectMemberCall(target, memberId.name)) { | 3685 } else if (_isObjectMemberCall(target, memberName)) { |
3574 result = js.call('dart.#(#)', [name, jsTarget]); | 3686 result = js.call('dart.#(#)', [name, jsTarget]); |
3575 } else { | 3687 } else { |
3576 result = js.call('#.#', [jsTarget, name]); | 3688 result = js.call('#.#', [jsTarget, name]); |
3577 } | 3689 } |
3578 return _applyFunctionTypeArguments(result, member, resultType); | 3690 if (typeArgs == null) { |
3579 } | 3691 return result; |
3580 | |
3581 /// If this is an inferred instantiation of a generic function/method, this | |
3582 /// will add the inferred type arguments. | |
3583 JS.Expression _applyFunctionTypeArguments( | |
3584 JS.Expression result, Element member, DartType instantiated) { | |
3585 DartType type; | |
3586 if (member is ExecutableElement) { | |
3587 type = member.type; | |
3588 } else if (member is VariableElement) { | |
3589 type = member.type; | |
3590 } | 3692 } |
3591 | |
3592 // TODO(jmesserly): handle explicitly passed type args. | |
3593 if (type == null) return result; | |
3594 var typeArgs = _emitFunctionTypeArguments(type, instantiated); | |
3595 if (typeArgs == null) return result; | |
3596 return js.call('dart.gbind(#, #)', [result, typeArgs]); | 3693 return js.call('dart.gbind(#, #)', [result, typeArgs]); |
3597 } | 3694 } |
3598 | 3695 |
3599 /// Emits a generic send, like an operator method. | 3696 /// Emits a generic send, like an operator method. |
3600 /// | 3697 /// |
3601 /// **Please note** this function does not support method invocation syntax | 3698 /// **Please note** this function does not support method invocation syntax |
3602 /// `obj.name(args)` because that could be a getter followed by a call. | 3699 /// `obj.name(args)` because that could be a getter followed by a call. |
3603 /// See [visitMethodInvocation]. | 3700 /// See [visitMethodInvocation]. |
3604 JS.Expression _emitSend( | 3701 JS.Expression _emitSend( |
3605 Expression target, String name, List<Expression> args) { | 3702 Expression target, String name, List<Expression> args) { |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3783 } | 3880 } |
3784 | 3881 |
3785 @override | 3882 @override |
3786 visitContinueStatement(ContinueStatement node) { | 3883 visitContinueStatement(ContinueStatement node) { |
3787 var label = node.label; | 3884 var label = node.label; |
3788 return new JS.Continue(label?.name); | 3885 return new JS.Continue(label?.name); |
3789 } | 3886 } |
3790 | 3887 |
3791 @override | 3888 @override |
3792 visitTryStatement(TryStatement node) { | 3889 visitTryStatement(TryStatement node) { |
3793 return new JS.Try(_visit(node.body), _visitCatch(node.catchClauses), | 3890 var savedSuperAllowed = _superAllowed; |
3794 _visit(node.finallyBlock)); | 3891 _superAllowed = false; |
3892 var finallyBlock = _visit(node.finallyBlock); | |
3893 _superAllowed = savedSuperAllowed; | |
3894 return new JS.Try( | |
3895 _visit(node.body), _visitCatch(node.catchClauses), finallyBlock); | |
3795 } | 3896 } |
3796 | 3897 |
3797 _visitCatch(NodeList<CatchClause> clauses) { | 3898 _visitCatch(NodeList<CatchClause> clauses) { |
3798 if (clauses == null || clauses.isEmpty) return null; | 3899 if (clauses == null || clauses.isEmpty) return null; |
3799 | 3900 |
3800 // TODO(jmesserly): need a better way to get a temporary variable. | 3901 // TODO(jmesserly): need a better way to get a temporary variable. |
3801 // This could incorrectly shadow a user's name. | 3902 // This could incorrectly shadow a user's name. |
3802 var savedCatch = _catchParameter; | 3903 var savedCatch = _catchParameter; |
3803 | 3904 |
3804 if (clauses.length == 1 && clauses.single.exceptionParameter != null) { | 3905 if (clauses.length == 1 && clauses.single.exceptionParameter != null) { |
(...skipping 487 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4292 } | 4393 } |
4293 | 4394 |
4294 bool isLibraryPrefix(Expression node) => | 4395 bool isLibraryPrefix(Expression node) => |
4295 node is SimpleIdentifier && node.staticElement is PrefixElement; | 4396 node is SimpleIdentifier && node.staticElement is PrefixElement; |
4296 | 4397 |
4297 LibraryElement _getLibrary(AnalysisContext c, String uri) => | 4398 LibraryElement _getLibrary(AnalysisContext c, String uri) => |
4298 c.computeLibraryElement(c.sourceFactory.forUri(uri)); | 4399 c.computeLibraryElement(c.sourceFactory.forUri(uri)); |
4299 | 4400 |
4300 bool _isDartRuntime(LibraryElement l) => | 4401 bool _isDartRuntime(LibraryElement l) => |
4301 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; | 4402 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; |
OLD | NEW |