Skip to content

Commit f7a5ff4

Browse files
author
John Messerly
committed
workaround for arrow function bind this
I filed dart-archive/dev_compiler#43 to track removal of this workaround [email protected] Review URL: https://chromereviews.googleplex.com/154077013
1 parent 26061d8 commit f7a5ff4

File tree

7 files changed

+202
-169
lines changed

7 files changed

+202
-169
lines changed

pkg/dev_compiler/lib/src/codegen/js_codegen.dart

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -642,12 +642,15 @@ $name.prototype[Symbol.iterator] = function() {
642642
out.write(') ');
643643
node.body.accept(this);
644644
} else {
645+
var bindThis = _needsBindThis(node.body);
646+
if (bindThis) out.write("(");
645647
out.write("(");
646648
_visitNode(node.parameters);
647649
out.write(") => ");
648650
var body = node.body;
649651
if (body is ExpressionFunctionBody) body = body.expression;
650652
body.accept(this);
653+
if (bindThis) out.write(").bind(this)");
651654
}
652655
}
653656

@@ -674,11 +677,8 @@ $name.prototype[Symbol.iterator] = function() {
674677
if (e.enclosingElement is CompilationUnitElement &&
675678
(e.library != libraryInfo.library || _needsModuleGetter(e))) {
676679
out.write('${_jsLibraryName(e.library)}.');
677-
} else if (currentClass != null) {
678-
if (e is PropertyAccessorElement && !e.variable.isStatic ||
679-
e is ClassMemberElement && !e.isStatic && e is! ConstructorElement) {
680-
out.write('this.');
681-
}
680+
} else if (currentClass != null && _needsImplicitThis(e)) {
681+
out.write('this.');
682682
}
683683
out.write(node.name);
684684
}
@@ -1244,7 +1244,9 @@ $name.prototype[Symbol.iterator] = function() {
12441244
if (node.parent is! ExpressionStatement) {
12451245
out.write('return ${_cascadeTarget.name};\n');
12461246
}
1247-
out.write('})(', -2);
1247+
out.write('})', -2);
1248+
if (_needsBindThis(node.cascadeSections)) out.write('.bind(this)');
1249+
out.write('(');
12481250
node.target.accept(this);
12491251
out.write(')');
12501252
}
@@ -1850,6 +1852,18 @@ $name.prototype[Symbol.iterator] = function() {
18501852
name = _canonicalMethodName(name);
18511853
return name.startsWith('[') ? name : '.$name';
18521854
}
1855+
1856+
bool _needsBindThis(node) {
1857+
if (currentClass == null) return false;
1858+
var visitor = _BindThisVisitor._instance;
1859+
visitor._bindThis = false;
1860+
node.accept(visitor);
1861+
return visitor._bindThis;
1862+
}
1863+
1864+
static bool _needsImplicitThis(Element e) =>
1865+
e is PropertyAccessorElement && !e.variable.isStatic ||
1866+
e is ClassMemberElement && !e.isStatic && e is! ConstructorElement;
18531867
}
18541868

18551869
/// Returns true if the local variable is potentially mutated within [context].
@@ -1901,6 +1915,25 @@ class _AssignmentFinder extends RecursiveAstVisitor {
19011915
}
19021916
}
19031917

1918+
/// This is a workaround for V8 arrow function bindings being not yet
1919+
/// implemented. See issue #43
1920+
class _BindThisVisitor extends RecursiveAstVisitor {
1921+
static _BindThisVisitor _instance = new _BindThisVisitor();
1922+
bool _bindThis = false;
1923+
1924+
@override
1925+
visitSimpleIdentifier(SimpleIdentifier node) {
1926+
if (JSCodegenVisitor._needsImplicitThis(node.staticElement)) {
1927+
_bindThis = true;
1928+
}
1929+
}
1930+
1931+
@override
1932+
visitThisExpression(ThisExpression node) {
1933+
_bindThis = true;
1934+
}
1935+
}
1936+
19041937
class JSGenerator extends CodeGenerator {
19051938
JSGenerator(String outDir, Uri root, TypeRules rules)
19061939
: super(outDir, root, rules);

pkg/dev_compiler/test/codegen/expect/BenchmarkBase/BenchmarkBase.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,12 @@ var BenchmarkBase;
5353
}
5454
measure() {
5555
this.setup();
56-
measureFor(() => {
56+
measureFor((() => {
5757
this.warmup();
58-
}, 100);
59-
let result = measureFor(() => {
58+
}).bind(this), 100);
59+
let result = measureFor((() => {
6060
this.exercise();
61-
}, 2000);
61+
}).bind(this), 2000);
6262
this.teardown();
6363
return result;
6464
}

pkg/dev_compiler/test/codegen/expect/_internal/_internal.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ var _internal;
175175
result = ((_) => {
176176
_.length = this.length;
177177
return _;
178-
})(new core.List());
178+
}).bind(this)(new core.List());
179179
} else {
180180
result = new core.List(this.length);
181181
}
@@ -264,7 +264,7 @@ var _internal;
264264
let result = growable ? (((_) => {
265265
_.length = length;
266266
return _;
267-
})(new core.List())) : new core.List(length);
267+
}).bind(this)(new core.List())) : new core.List(length);
268268
for (let i = 0; i < length; i++) {
269269
result.set(i, this._iterable.elementAt(start + i));
270270
if (this._iterable.length < end) throw new core.ConcurrentModificationError(this);

0 commit comments

Comments
 (0)