| Index: lib/src/codegen/js_codegen.dart
|
| diff --git a/lib/src/codegen/js_codegen.dart b/lib/src/codegen/js_codegen.dart
|
| index 34f9534b4839ceab94b0dd3e63ae7defa0d634a6..4426755e2b6e30fb7962793d18e1c5b3c8606f7c 100644
|
| --- a/lib/src/codegen/js_codegen.dart
|
| +++ b/lib/src/codegen/js_codegen.dart
|
| @@ -1117,7 +1117,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor {
|
| if (params == null) params = [];
|
|
|
| return new JS.Method(
|
| - _elementMemberName(node.element), new JS.Fun(params, _visit(node.body)),
|
| + _elementMemberName(node.element), _emitJsFunction(params, node.body),
|
| isGetter: node.isGetter,
|
| isSetter: node.isSetter,
|
| isStatic: node.isStatic);
|
| @@ -1202,10 +1202,9 @@ class JSCodegenVisitor extends GeneralizingAstVisitor {
|
| if (params == null) params = [];
|
|
|
| var parent = node.parent;
|
| - var inDecl = parent is FunctionDeclaration;
|
| var inStmt = parent.parent is FunctionDeclarationStatement;
|
| - if (inDecl && !inStmt) {
|
| - return new JS.Fun(params, _visit(node.body));
|
| + if (parent is FunctionDeclaration) {
|
| + return _emitJsFunction(params, node.body);
|
| } else {
|
| String code;
|
| AstNode body;
|
| @@ -1227,6 +1226,12 @@ class JSCodegenVisitor extends GeneralizingAstVisitor {
|
| }
|
| }
|
|
|
| + JS.Fun _emitJsFunction(List<JS.Parameter> params, FunctionBody body) {
|
| + // TODO(jmesserly): async/async*
|
| + var syncStar = body.isSynchronous && body.star != null;
|
| + return new JS.Fun(params, _visit(body), isGenerator: syncStar);
|
| + }
|
| +
|
| @override
|
| JS.Statement visitFunctionDeclarationStatement(
|
| FunctionDeclarationStatement node) {
|
| @@ -1235,12 +1240,20 @@ class JSCodegenVisitor extends GeneralizingAstVisitor {
|
| return js.comment('Unimplemented function get/set statement: $node');
|
| }
|
|
|
| - // Use an => function to bind this.
|
| - // Technically we only need to do this if the function actually closes over
|
| - // `this`, but it seems harmless enough to just do it always.
|
| + var fn = _visit(func.functionExpression);
|
| + var jsThis = new _JsThisFinder();
|
| + fn.accept(jsThis);
|
| +
|
| var name = new JS.Identifier(func.name.name);
|
| + JS.Statement declareFn;
|
| + if (jsThis.found) {
|
| + declareFn = js.statement('let # = #.bind(this);', [name, fn]);
|
| + } else {
|
| + declareFn = new JS.FunctionDeclaration(name, fn);
|
| + }
|
| +
|
| return new JS.Block([
|
| - js.statement('let # = #;', [name, _visit(func.functionExpression)]),
|
| + declareFn,
|
| _emitFunctionTagged(name, func.element.type).toStatement()
|
| ]);
|
| }
|
| @@ -1642,7 +1655,13 @@ class JSCodegenVisitor extends GeneralizingAstVisitor {
|
| JS.Statement visitReturnStatement(ReturnStatement node) {
|
| var e = node.expression;
|
| if (e == null) return new JS.Return();
|
| - return _visit(e).toReturn();
|
| + return (_visit(e) as JS.Expression).toReturn();
|
| + }
|
| +
|
| + @override
|
| + JS.Statement visitYieldStatement(YieldStatement node) {
|
| + JS.Expression jsExpr = _visit(node.expression);
|
| + return jsExpr.toYieldStatement(star: node.star != null);
|
| }
|
|
|
| @override
|
| @@ -2579,10 +2598,6 @@ class JSCodegenVisitor extends GeneralizingAstVisitor {
|
| JS.Expression visitExpression(Expression node) =>
|
| _unimplementedCall('Unimplemented ${node.runtimeType}: $node');
|
|
|
| - @override
|
| - JS.Statement visitYieldStatement(YieldStatement node) =>
|
| - _unimplementedCall('Unimplemented yield: $node').toStatement();
|
| -
|
| JS.Expression _unimplementedCall(String comment) {
|
| return js.call('dart.throw_(#)', [js.escapedString(comment)]);
|
| }
|
| @@ -2805,3 +2820,13 @@ class TemporaryVariableElement extends LocalVariableElementImpl {
|
| int get hashCode => identityHashCode(this);
|
| bool operator ==(Object other) => identical(this, other);
|
| }
|
| +
|
| +class _JsThisFinder extends JS.BaseVisitor {
|
| + bool found = false;
|
| + visitThis(JS.This node) {
|
| + found = true;
|
| + }
|
| + visitNode(JS.Node node) {
|
| + if (!found) super.visitNode(node);
|
| + }
|
| +}
|
|
|