Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(500)

Unified Diff: lib/src/codegen/js_codegen.dart

Issue 1088943006: implement tear offs (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: lib/src/codegen/js_codegen.dart
diff --git a/lib/src/codegen/js_codegen.dart b/lib/src/codegen/js_codegen.dart
index afbeb695f176f000612fd3b1258acf8bf09396d4..e9bb89b0ed0b4f75aaf7b4a9b497dc36cfd93184 100644
--- a/lib/src/codegen/js_codegen.dart
+++ b/lib/src/codegen/js_codegen.dart
@@ -1029,14 +1029,22 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
if (element is ClassMemberElement && element is! ConstructorElement) {
bool isStatic = element.isStatic;
var type = element.enclosingElement.type;
+ var member = _emitMemberName(name, isStatic: isStatic, type: type);
- // For instance methods, we add implicit-this.
// For static methods, we add the raw type name, without generics or
// library prefix. We don't need those because static calls can't use
// the generic type.
- var target = isStatic ? new JS.Identifier(type.name) : new JS.This();
- var member = _emitMemberName(name, isStatic: isStatic, type: type);
- return new JS.PropertyAccess(target, member);
+ if (isStatic) {
+ return js.call('#.#', [type.name, member]);
+ }
+
+ // For instance members, we add implicit-this.
+ // For method tear-offs, we ensure it's a bound method.
+ var code = 'this.#';
+ if (element is MethodElement && !inInvocationContext(node)) {
+ code += '.bind(this)';
+ }
+ return js.call(code, member);
}
// initializing formal parameter, e.g. `Point(this.x)`
@@ -1228,8 +1236,6 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
var result = _emitForeignJS(node);
if (result != null) return result;
- // TODO(jmesserly): if we try to call a getter returning a function with
- // a call method, we don't generate the `.call` correctly.
String code;
if (target == null || isLibraryPrefix(target)) {
if (rules.isDynamicCall(node.methodName)) {
@@ -1241,11 +1247,13 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
code, [_visit(node.methodName), _visit(node.argumentList)]);
}
- // TODO(jmesserly): if the methodName resolves statically but the call is
- // dynamic (e.g. `obj.method` is resolved to a field of type `Function`), we
- // could generate call(#.#, #). Not sure if that's worth it.
- if (rules.isDynamicCall(node.methodName)) {
+ if (rules.isDynamicTarget(target)) {
code = 'dart.$DSEND(#, #, #)';
+ } else if (rules.isDynamicCall(node.methodName)) {
+ // This is a dynamic call to a statically know target. For example:
+ // class Foo { Function bar; }
+ // new Foo().bar(); // dynamic call
+ code = 'dart.$DCALL(#.#, #)';
} else {
code = '#.#(#)';
}
@@ -1796,24 +1804,41 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
if (isLibraryPrefix(node.prefix)) {
return _visit(node.identifier);
} else {
- return _emitGet(node.prefix, node.identifier.name);
+ return _emitGet(node.prefix, node.identifier);
}
}
@override
visitPropertyAccess(PropertyAccess node) =>
- _emitGet(_getTarget(node), node.propertyName.name);
+ _emitGet(_getTarget(node), node.propertyName);
/// Shared code for [PrefixedIdentifier] and [PropertyAccess].
- JS.Expression _emitGet(Expression target, String memberName) {
- var name = _emitMemberName(memberName, type: getStaticType(target));
+ JS.Expression _emitGet(Expression target, SimpleIdentifier memberId) {
+ var name = _emitMemberName(memberId.name, type: getStaticType(target));
if (rules.isDynamicTarget(target)) {
return js.call('dart.$DLOAD(#, #)', [_visit(target), name]);
+ }
+
+ String code;
+ var member = memberId.staticElement;
+ if (member != null && member is MethodElement) {
+ // Tear-off methods: explicitly bind it.
+ if (isStateless(target, target)) {
+ return js.call('#.#.bind(#)', [_visit(target), name, _visit(target)]);
+ }
+ code = 'dart.bind(#, #)';
} else {
- return js.call('#.#', [_visit(target), name]);
+ code = '#.#';
}
+
+ return js.call(code, [_visit(target), name]);
}
+ /// Emits a generic send, like an operator method.
+ ///
+ /// **Please note** this function does not support method invocation syntax
+ /// `obj.name(args)` because that could be a getter followed by a call.
+ /// See [visitMethodInvocation].
JS.Expression _emitSend(
Expression target, String name, List<Expression> args) {
var type = getStaticType(target);
@@ -1831,8 +1856,9 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
_visitList(args)
]);
}
+
if (_isJSBuiltinType(type)) {
- // static call pattern for bultins.
+ // static call pattern for builtins.
return js.call('#.#(#, #)', [
_emitTypeName(type),
memberName,

Powered by Google App Engine
This is Rietveld 408576698