Skip to content

Commit

Permalink
[dartdevc] Generating nested functions that invoke super as arrow fun…
Browse files Browse the repository at this point in the history
…ctions (e.g., mixins)

Issue: dart-lang/sdk#34806
Change-Id: I7f5297dbdfbf928258146f28f85043f735acacb2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/97686
Reviewed-by: Nicholas Shahan <nshahan@google.com>
Reviewed-by: Jenny Messerly <jmesserly@google.com>
Commit-Queue: Mark Zhou <markzipan@google.com>
  • Loading branch information
Markzipan authored and commit-bot@chromium.org committed Mar 26, 2019
1 parent 3a37316 commit e1a6893
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 34 deletions.
9 changes: 2 additions & 7 deletions pkg/dev_compiler/lib/src/analyzer/code_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2844,7 +2844,7 @@ class CodeGenerator extends Object
genFn);
}
gen.sourceInformation = _functionEnd(body);
if (JS.This.foundIn(gen)) gen = js.call('#.bind(this)', gen);
if (usesThisOrSuper(gen)) gen = js.call('#.bind(this)', gen);

_superAllowed = savedSuperAllowed;
_asyncStarController = savedController;
Expand Down Expand Up @@ -2922,14 +2922,9 @@ class CodeGenerator extends Object
}

var fn = _emitFunctionExpression(func.functionExpression);

var name = _emitVariableDef(func.name);
JS.Statement declareFn;
if (JS.This.foundIn(fn)) {
declareFn = js.statement('const # = #.bind(this);', [name, fn]);
} else {
declareFn = JS.FunctionDeclaration(name, fn);
}
declareFn = toBoundFunctionStatement(fn, name);
var element = func.declaredElement;
if (_reifyFunctionType(element)) {
declareFn = JS.Block(
Expand Down
39 changes: 39 additions & 0 deletions pkg/dev_compiler/lib/src/compiler/shared_compiler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -606,3 +606,42 @@ class YieldFinder extends JS.BaseVisitor {
super.visitNode(node);
}
}

/// Given the function [fn], returns a function declaration statement, binding
/// `this` and `super` if necessary (using an arrow function).
JS.Statement toBoundFunctionStatement(JS.Fun fn, JS.Identifier name) {
if (usesThisOrSuper(fn)) {
return js.statement('const # = (#) => {#}', [name, fn.params, fn.body]);
} else {
return JS.FunctionDeclaration(name, fn);
}
}

/// Returns whether [node] uses `this` or `super`.
bool usesThisOrSuper(JS.Expression node) {
var finder = _ThisOrSuperFinder.instance;
finder.found = false;
node.accept(finder);
return finder.found;
}

class _ThisOrSuperFinder extends JS.BaseVisitor<void> {
bool found = false;

static final instance = _ThisOrSuperFinder();

@override
visitThis(JS.This node) {
found = true;
}

@override
visitSuper(JS.Super node) {
found = true;
}

@override
visitNode(JS.Node node) {
if (!found) super.visitNode(node);
}
}
21 changes: 0 additions & 21 deletions pkg/dev_compiler/lib/src/js_ast/nodes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1189,27 +1189,6 @@ class This extends Expression {
This _clone() => This();
int get precedenceLevel => PRIMARY;
void visitChildren(NodeVisitor visitor) {}

static bool foundIn(Node node) {
var finder = _ThisFinder._instance;
finder.found = false;
node.accept(finder);
return finder.found;
}
}

class _ThisFinder extends BaseVisitor<void> {
bool found = false;

static final _instance = _ThisFinder();

visitThis(This node) {
found = true;
}

visitNode(Node node) {
if (!found) super.visitNode(node);
}
}

// `super` is more restricted in the ES6 spec, but for simplicity we accept
Expand Down
8 changes: 2 additions & 6 deletions pkg/dev_compiler/lib/src/kernel/compiler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2718,7 +2718,7 @@ class ProgramCompiler extends Object
}

gen.sourceInformation = _nodeEnd(function.fileEndOffset);
if (JS.This.foundIn(gen)) gen = js.call('#.bind(this)', gen);
if (usesThisOrSuper(gen)) gen = js.call('#.bind(this)', gen);
});

_asyncStarController = savedController;
Expand Down Expand Up @@ -3569,11 +3569,7 @@ class ProgramCompiler extends Object

var name = _emitVariableDef(node.variable);
JS.Statement declareFn;
if (JS.This.foundIn(fn)) {
declareFn = js.statement('const # = #.bind(this);', [name, fn]);
} else {
declareFn = JS.FunctionDeclaration(name, fn);
}
declareFn = toBoundFunctionStatement(fn, name);
if (_reifyFunctionType(func)) {
declareFn = JS.Block([
declareFn,
Expand Down

0 comments on commit e1a6893

Please sign in to comment.