| 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 | 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 1584 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1595 _runtimeModule, | 1595 _runtimeModule, |
| 1596 _declareMemberName(method, useDisplayName: true), | 1596 _declareMemberName(method, useDisplayName: true), |
| 1597 positionalArgs, | 1597 positionalArgs, |
| 1598 new JS.ObjectInitializer(invocationProps) | 1598 new JS.ObjectInitializer(invocationProps) |
| 1599 ]); | 1599 ]); |
| 1600 | 1600 |
| 1601 if (!method.returnType.isDynamic) { | 1601 if (!method.returnType.isDynamic) { |
| 1602 fnBody = js.call('#._check(#)', [_emitType(method.returnType), fnBody]); | 1602 fnBody = js.call('#._check(#)', [_emitType(method.returnType), fnBody]); |
| 1603 } | 1603 } |
| 1604 | 1604 |
| 1605 var fn = new JS.Fun(fnArgs, js.statement('{ return #; }', [fnBody]), | 1605 var fn = _makeGenericFunction(new JS.Fun( |
| 1606 typeParams: _emitTypeFormals(method.type.typeFormals)); | 1606 fnArgs, js.statement('{ return #; }', [fnBody]), |
| 1607 typeParams: _emitTypeFormals(method.type.typeFormals))); |
| 1607 | 1608 |
| 1608 // TODO(jmesserly): generic type arguments will get dropped. | 1609 // TODO(jmesserly): generic type arguments will get dropped. |
| 1609 // We have a similar issue with `dgsend` helpers. | 1610 // We have a similar issue with `dgsend` helpers. |
| 1610 return new JS.Method( | 1611 return new JS.Method( |
| 1611 _declareMemberName(method, | 1612 _declareMemberName(method, |
| 1612 useExtension: _extensionTypes.isNativeClass(type.element)), | 1613 useExtension: _extensionTypes.isNativeClass(type.element)), |
| 1613 _makeGenericFunction(fn), | 1614 fn, |
| 1614 isGetter: method is PropertyAccessorElement && method.isGetter, | 1615 isGetter: method is PropertyAccessorElement && method.isGetter, |
| 1615 isSetter: method is PropertyAccessorElement && method.isSetter, | 1616 isSetter: method is PropertyAccessorElement && method.isSetter, |
| 1616 isStatic: false); | 1617 isStatic: false); |
| 1617 } | 1618 } |
| 1618 | 1619 |
| 1619 /// This is called whenever a derived class needs to introduce a new field, | 1620 /// This is called whenever a derived class needs to introduce a new field, |
| 1620 /// shadowing a field or getter/setter pair on its parent. | 1621 /// shadowing a field or getter/setter pair on its parent. |
| 1621 /// | 1622 /// |
| 1622 /// This is important because otherwise, trying to read or write the field | 1623 /// This is important because otherwise, trying to read or write the field |
| 1623 /// would end up calling the getter or setter, and one of those might not even | 1624 /// would end up calling the getter or setter, and one of those might not even |
| (...skipping 811 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2435 | 2436 |
| 2436 JS.Fun fn; | 2437 JS.Fun fn; |
| 2437 if (_externalOrNative(node)) { | 2438 if (_externalOrNative(node)) { |
| 2438 if (node.isStatic) { | 2439 if (node.isStatic) { |
| 2439 // TODO(vsm): Do we need to handle this case? | 2440 // TODO(vsm): Do we need to handle this case? |
| 2440 return null; | 2441 return null; |
| 2441 } | 2442 } |
| 2442 fn = _emitNativeFunctionBody(node); | 2443 fn = _emitNativeFunctionBody(node); |
| 2443 } else { | 2444 } else { |
| 2444 fn = _emitFunctionBody(node.element, node.parameters, node.body); | 2445 fn = _emitFunctionBody(node.element, node.parameters, node.body); |
| 2445 | |
| 2446 if (node.operatorKeyword != null && | |
| 2447 node.name.name == '[]=' && | |
| 2448 fn.params.isNotEmpty) { | |
| 2449 // []= methods need to return the value. We could also address this at | |
| 2450 // call sites, but it's cleaner to instead transform the operator method
. | |
| 2451 fn = _alwaysReturnLastParameter(fn); | |
| 2452 } | |
| 2453 | |
| 2454 fn = _makeGenericFunction(fn); | |
| 2455 } | 2446 } |
| 2456 | 2447 |
| 2457 return annotate( | 2448 return annotate( |
| 2458 new JS.Method(_declareMemberName(node.element), fn, | 2449 new JS.Method(_declareMemberName(node.element), fn, |
| 2459 isGetter: node.isGetter, | 2450 isGetter: node.isGetter, |
| 2460 isSetter: node.isSetter, | 2451 isSetter: node.isSetter, |
| 2461 isStatic: node.isStatic), | 2452 isStatic: node.isStatic), |
| 2462 node, | 2453 node, |
| 2463 node.element); | 2454 node.element); |
| 2464 } | 2455 } |
| 2465 | 2456 |
| 2466 /// Transform the function so the last parameter is always returned. | 2457 /// Transform the function so the last parameter is always returned. |
| 2467 /// | 2458 /// |
| 2468 /// This is useful for indexed set methods, which otherwise would not have | 2459 /// This is useful for indexed set methods, which otherwise would not have |
| 2469 /// the right return value in JS. | 2460 /// the right return value in JS. |
| 2470 JS.Fun _alwaysReturnLastParameter(JS.Fun fn) { | 2461 JS.Node _alwaysReturnLastParameter(JS.Node body, JS.Parameter lastParam) { |
| 2471 var body = fn.body; | 2462 if (JS.Return.foundIn(body)) { |
| 2472 if (JS.Return.foundIn(fn)) { | |
| 2473 // If a return is inside body, transform `(params) { body }` to | 2463 // If a return is inside body, transform `(params) { body }` to |
| 2474 // `(params) { (() => { body })(); return value; }`. | 2464 // `(params) { (() => { body })(); return value; }`. |
| 2475 // TODO(jmesserly): we could instead generate the return differently, | 2465 // TODO(jmesserly): we could instead generate the return differently, |
| 2476 // and avoid the immediately invoked function. | 2466 // and avoid the immediately invoked function. |
| 2477 body = new JS.Call(new JS.ArrowFun([], fn.body), []).toStatement(); | 2467 body = new JS.Call(new JS.ArrowFun([], body), []).toStatement(); |
| 2478 } | 2468 } |
| 2479 // Rewrite the function to include the return. | 2469 return new JS.Block([body, new JS.Return(lastParam)]); |
| 2480 return new JS.Fun( | |
| 2481 fn.params, new JS.Block([body, new JS.Return(fn.params.last)]), | |
| 2482 typeParams: fn.typeParams, returnType: fn.returnType) | |
| 2483 ..sourceInformation = fn.sourceInformation; | |
| 2484 } | 2470 } |
| 2485 | 2471 |
| 2486 @override | 2472 @override |
| 2487 JS.Statement visitFunctionDeclaration(FunctionDeclaration node) { | 2473 JS.Statement visitFunctionDeclaration(FunctionDeclaration node) { |
| 2488 assert(node.parent is CompilationUnit); | 2474 assert(node.parent is CompilationUnit); |
| 2489 | 2475 |
| 2490 if (_externalOrNative(node)) return null; | 2476 if (_externalOrNative(node)) return null; |
| 2491 | 2477 |
| 2492 if (node.isGetter || node.isSetter) { | 2478 if (node.isGetter || node.isSetter) { |
| 2493 PropertyAccessorElement element = node.element; | 2479 PropertyAccessorElement element = node.element; |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2622 /// Contrast with [_emitFunction]. | 2608 /// Contrast with [_emitFunction]. |
| 2623 @override | 2609 @override |
| 2624 JS.Expression visitFunctionExpression(FunctionExpression node) { | 2610 JS.Expression visitFunctionExpression(FunctionExpression node) { |
| 2625 assert(node.parent is! FunctionDeclaration && | 2611 assert(node.parent is! FunctionDeclaration && |
| 2626 node.parent is! MethodDeclaration); | 2612 node.parent is! MethodDeclaration); |
| 2627 return _emitFunctionTagged(_emitArrowFunction(node), getStaticType(node), | 2613 return _emitFunctionTagged(_emitArrowFunction(node), getStaticType(node), |
| 2628 topLevel: _executesAtTopLevel(node)); | 2614 topLevel: _executesAtTopLevel(node)); |
| 2629 } | 2615 } |
| 2630 | 2616 |
| 2631 JS.ArrowFun _emitArrowFunction(FunctionExpression node) { | 2617 JS.ArrowFun _emitArrowFunction(FunctionExpression node) { |
| 2632 JS.Fun f = _emitFunctionBody(node.element, node.parameters, node.body); | 2618 JS.Fun fn = _emitFunctionBody(node.element, node.parameters, node.body); |
| 2619 |
| 2620 return annotate(_toArrowFunction(fn), node); |
| 2621 } |
| 2622 |
| 2623 JS.Fun _makeGenericFunction(JS.Fun fn) { |
| 2624 if (fn.typeParams == null || fn.typeParams.isEmpty) return fn; |
| 2625 |
| 2626 return new JS.Fun( |
| 2627 fn.typeParams, |
| 2628 new JS.Block([ |
| 2629 // Convert the function to an => function, to ensure `this` binding. |
| 2630 new JS.Return(_toArrowFunction(fn)) |
| 2631 ])); |
| 2632 } |
| 2633 |
| 2634 JS.ArrowFun _toArrowFunction(JS.Fun f) { |
| 2633 JS.Node body = f.body; | 2635 JS.Node body = f.body; |
| 2634 | 2636 |
| 2635 // Simplify `=> { return e; }` to `=> e` | 2637 // Simplify `=> { return e; }` to `=> e` |
| 2636 if (body is JS.Block) { | 2638 if (body is JS.Block) { |
| 2637 JS.Block block = body; | 2639 JS.Block block = body; |
| 2638 if (block.statements.length == 1) { | 2640 if (block.statements.length == 1) { |
| 2639 JS.Statement s = block.statements[0]; | 2641 JS.Statement s = block.statements[0]; |
| 2640 if (s is JS.Return && s.value != null) body = s.value; | 2642 if (s is JS.Return && s.value != null) body = s.value; |
| 2641 } | 2643 } |
| 2642 } | 2644 } |
| 2643 | 2645 |
| 2644 // Convert `function(...) { ... }` to `(...) => ...` | 2646 // Convert `function(...) { ... }` to `(...) => ...` |
| 2645 // This is for readability, but it also ensures correct `this` binding. | 2647 // This is for readability, but it also ensures correct `this` binding. |
| 2646 var fn = new JS.ArrowFun(f.params, body, | 2648 return new JS.ArrowFun(f.params, body, |
| 2647 typeParams: f.typeParams, returnType: f.returnType); | 2649 typeParams: f.typeParams, returnType: f.returnType) |
| 2648 | 2650 ..sourceInformation = f.sourceInformation; |
| 2649 return annotate(_makeGenericArrowFun(fn), node); | |
| 2650 } | |
| 2651 | |
| 2652 JS.ArrowFun _makeGenericArrowFun(JS.ArrowFun fn) { | |
| 2653 if (fn.typeParams == null || fn.typeParams.isEmpty) return fn; | |
| 2654 return new JS.ArrowFun(fn.typeParams, fn); | |
| 2655 } | |
| 2656 | |
| 2657 JS.Fun _makeGenericFunction(JS.Fun fn) { | |
| 2658 if (fn.typeParams == null || fn.typeParams.isEmpty) return fn; | |
| 2659 | |
| 2660 // TODO(jmesserly): we could make these default to `dynamic`. | |
| 2661 return new JS.Fun( | |
| 2662 fn.typeParams, | |
| 2663 new JS.Block([ | |
| 2664 // Convert the function to an => function, to ensure `this` binding. | |
| 2665 new JS.Return(new JS.ArrowFun(fn.params, fn.body, | |
| 2666 typeParams: fn.typeParams, returnType: fn.returnType)) | |
| 2667 ])); | |
| 2668 } | 2651 } |
| 2669 | 2652 |
| 2670 /// Emits a non-arrow FunctionExpression node. | 2653 /// Emits a non-arrow FunctionExpression node. |
| 2671 /// | 2654 /// |
| 2672 /// This should be used for all places in Dart's AST where FunctionExpression | 2655 /// This should be used for all places in Dart's AST where FunctionExpression |
| 2673 /// appears but the function is not actually in an Expression context, such | 2656 /// appears but the function is not actually in an Expression context, such |
| 2674 /// as methods, properties, and top-level functions. | 2657 /// as methods, properties, and top-level functions. |
| 2675 /// | 2658 /// |
| 2676 /// Contrast with [visitFunctionExpression]. | 2659 /// Contrast with [visitFunctionExpression]. |
| 2677 JS.Fun _emitFunction(FunctionExpression node) { | 2660 JS.Fun _emitFunction(FunctionExpression node) { |
| 2678 var fn = _emitFunctionBody(node.element, node.parameters, node.body); | 2661 return annotate( |
| 2679 return annotate(_makeGenericFunction(fn), node); | 2662 _emitFunctionBody(node.element, node.parameters, node.body), node); |
| 2680 } | 2663 } |
| 2681 | 2664 |
| 2682 JS.Fun _emitFunctionBody(ExecutableElement element, | 2665 JS.Fun _emitFunctionBody(ExecutableElement element, |
| 2683 FormalParameterList parameters, FunctionBody body) { | 2666 FormalParameterList parameters, FunctionBody body) { |
| 2684 FunctionType type = element.type; | 2667 FunctionType type = element.type; |
| 2685 | 2668 |
| 2686 // normal function (sync), vs (sync*, async, async*) | 2669 // normal function (sync), vs (sync*, async, async*) |
| 2687 var stdFn = !(element.isAsynchronous || element.isGenerator); | 2670 var stdFn = !(element.isAsynchronous || element.isGenerator); |
| 2688 var formals = _emitFormalParameterList(parameters, destructure: stdFn); | 2671 var formals = _emitFormalParameterList(parameters, destructure: stdFn); |
| 2689 var code = (stdFn) | 2672 var code = (stdFn) |
| 2690 ? _visit(body) | 2673 ? _visit(body) |
| 2691 : new JS.Block( | 2674 : new JS.Block( |
| 2692 [_emitGeneratorFunctionBody(element, parameters, body).toReturn()]); | 2675 [_emitGeneratorFunctionBody(element, parameters, body).toReturn()]); |
| 2693 var typeFormals = _emitTypeFormals(type.typeFormals); | 2676 var typeFormals = _emitTypeFormals(type.typeFormals); |
| 2694 var returnType = emitTypeRef(type.returnType); | 2677 var returnType = emitTypeRef(type.returnType); |
| 2695 if (type.typeFormals.isNotEmpty) { | 2678 if (type.typeFormals.isNotEmpty) { |
| 2696 code = new JS.Block(<JS.Statement>[ | 2679 code = new JS.Block(<JS.Statement>[ |
| 2697 new JS.Block(_typeTable.discharge(type.typeFormals)), | 2680 new JS.Block(_typeTable.discharge(type.typeFormals)), |
| 2698 code | 2681 code |
| 2699 ]); | 2682 ]); |
| 2700 } | 2683 } |
| 2701 return new JS.Fun(formals, code, | 2684 |
| 2702 typeParams: typeFormals, returnType: returnType); | 2685 if (element.isOperator && element.name == '[]=' && formals.isNotEmpty) { |
| 2686 // []= methods need to return the value. We could also address this at |
| 2687 // call sites, but it's cleaner to instead transform the operator method. |
| 2688 code = _alwaysReturnLastParameter(code, formals.last); |
| 2689 } |
| 2690 |
| 2691 return _makeGenericFunction(new JS.Fun(formals, code, |
| 2692 typeParams: typeFormals, returnType: returnType)); |
| 2703 } | 2693 } |
| 2704 | 2694 |
| 2705 JS.Expression _emitGeneratorFunctionBody(ExecutableElement element, | 2695 JS.Expression _emitGeneratorFunctionBody(ExecutableElement element, |
| 2706 FormalParameterList parameters, FunctionBody body) { | 2696 FormalParameterList parameters, FunctionBody body) { |
| 2707 var kind = element.isSynchronous ? 'sync' : 'async'; | 2697 var kind = element.isSynchronous ? 'sync' : 'async'; |
| 2708 if (element.isGenerator) kind += 'Star'; | 2698 if (element.isGenerator) kind += 'Star'; |
| 2709 | 2699 |
| 2710 // Transforms `sync*` `async` and `async*` function bodies | 2700 // Transforms `sync*` `async` and `async*` function bodies |
| 2711 // using ES6 generators. | 2701 // using ES6 generators. |
| 2712 // | 2702 // |
| (...skipping 3278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5991 if (targetIdentifier.staticElement is! PrefixElement) return false; | 5981 if (targetIdentifier.staticElement is! PrefixElement) return false; |
| 5992 var prefix = targetIdentifier.staticElement as PrefixElement; | 5982 var prefix = targetIdentifier.staticElement as PrefixElement; |
| 5993 | 5983 |
| 5994 // The library the prefix is referring to must come from a deferred import. | 5984 // The library the prefix is referring to must come from a deferred import. |
| 5995 var containingLibrary = resolutionMap | 5985 var containingLibrary = resolutionMap |
| 5996 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) | 5986 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) |
| 5997 .library; | 5987 .library; |
| 5998 var imports = containingLibrary.getImportsWithPrefix(prefix); | 5988 var imports = containingLibrary.getImportsWithPrefix(prefix); |
| 5999 return imports.length == 1 && imports[0].isDeferred; | 5989 return imports.length == 1 && imports[0].isDeferred; |
| 6000 } | 5990 } |
| OLD | NEW |