Skip to content

Commit

Permalink
Support call methods on functions
Browse files Browse the repository at this point in the history
Fixes #624

R=jmesserly@google.com

Review URL: https://codereview.chromium.org/2255993002 .
  • Loading branch information
vsmenon committed Aug 18, 2016
1 parent d90d172 commit 8442efa
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 12 deletions.
38 changes: 28 additions & 10 deletions pkg/dev_compiler/lib/src/compiler/code_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3180,6 +3180,19 @@ class CodeGenerator extends GeneralizingAstVisitor
if (target == null || isLibraryPrefix(target)) {
return _emitFunctionCall(node);
}
if (node.methodName.name == 'call') {
var targetType = target.staticType;
if (targetType is FunctionType) {
// Call methods on function types should be handled as regular function
// invocations.
return _emitFunctionCall(node);
}
if (targetType.isDartCoreFunction || targetType.isDynamic) {
// TODO(vsm): Can a call method take generic type parameters?
return _emitDynamicInvoke(node, _visit(target),
_visit(node.argumentList) as List<JS.Expression>);
}
}

return _emitMethodCall(target, node);
}
Expand Down Expand Up @@ -3273,22 +3286,27 @@ class CodeGenerator extends GeneralizingAstVisitor
return new JS.Call(jsTarget, args);
}

JS.Expression _emitDynamicInvoke(
InvocationExpression node, JS.Expression fn, List<JS.Expression> args) {
var typeArgs = _emitInvokeTypeArguments(node);
if (typeArgs != null) {
return js.call('dart.dgcall(#, #, #)',
[fn, new JS.ArrayInitializer(typeArgs), args]);
} else {
if (_inWhitelistCode(node, isCall: true)) {
return new JS.Call(fn, args);
}
return js.call('dart.dcall(#, #)', [fn, args]);
}
}

/// Emits a function call, to a top-level function, local function, or
/// an expression.
JS.Expression _emitFunctionCall(InvocationExpression node) {
var fn = _visit(node.function);
var args = _visit(node.argumentList) as List<JS.Expression>;
if (isDynamicInvoke(node.function)) {
var typeArgs = _emitInvokeTypeArguments(node);
if (typeArgs != null) {
return js.call('dart.dgcall(#, #, #)',
[fn, new JS.ArrayInitializer(typeArgs), args]);
} else {
if (_inWhitelistCode(node, isCall: true)) {
return new JS.Call(fn, args);
}
return js.call('dart.dcall(#, #)', [fn, args]);
}
return _emitDynamicInvoke(node, fn, args);
} else {
return new JS.Call(_applyInvokeTypeArguments(fn, node), args);
}
Expand Down
39 changes: 39 additions & 0 deletions pkg/dev_compiler/test/codegen/language/call_function_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import "package:expect/expect.dart";

Object bar(Object x) { return x; }

Function baz = bar;

dynamic dyn = bar;

class Foo {
Object call(Object x) { return 'Foo$x'; }
}

typedef Object FooType(Object x);
FooType foo = bar;

void main() {
Expect.equals(42, bar.call(42));
Expect.equals(42, baz.call(42));
Expect.equals(42, foo.call(42));
Expect.equals(42, dyn.call(42));
Expect.equals(42, bar(42));
Expect.equals(42, baz(42));
Expect.equals(42, foo(42));
Expect.equals(42, dyn(42));

baz = new Foo();
foo = new Foo();
dyn = new Foo();
Expect.equals('Foo42', baz.call(42));
Expect.equals('Foo42', foo.call(42));
Expect.equals('Foo42', dyn.call(42));
Expect.equals('Foo42', baz(42));
Expect.equals('Foo42', foo(42));
Expect.equals('Foo42', dyn(42));
}
4 changes: 2 additions & 2 deletions pkg/dev_compiler/test/codegen_expected/varargs.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ dart_library.library('varargs', null, /* Imports */[
let dynamicTodynamic = () => (dynamicTodynamic = dart.constFn(dart.definiteFunctionType(dart.dynamic, [dart.dynamic])))();
varargs.varargsTest = function(x, ...others) {
let args = [1, others];
dart.dsend(x, 'call', ...args);
dart.dcall(x, ...args);
};
dart.fn(varargs.varargsTest, dynamicAnddynamicTodynamic());
varargs.varargsTest2 = function(x, ...others) {
let args = [1, others];
dart.dsend(x, 'call', ...args);
dart.dcall(x, ...args);
};
dart.fn(varargs.varargsTest2, dynamicAnddynamicTodynamic());
src__varargs._Rest = class _Rest extends core.Object {
Expand Down

0 comments on commit 8442efa

Please sign in to comment.