Skip to content
This repository was archived by the owner on Feb 22, 2018. It is now read-only.

Commit e5c2aac

Browse files
author
John Messerly
committed
fix optional params to mock methods, allow all signatures
switches to use the same technique as `dsend` [email protected] Review URL: https://codereview.chromium.org/2201973002 .
1 parent 4219a9e commit e5c2aac

27 files changed

+620
-549
lines changed

lib/runtime/dart_sdk.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1383,15 +1383,20 @@ dart_library.library('dart_sdk', null, /* Imports */[
13831383
dart._dartSymbol = function(name) {
13841384
return dart.const(core.Symbol.new(name.toString()));
13851385
};
1386+
dart.extractNamedArgs = function(args) {
1387+
if (args.length > 0) {
1388+
let last = args[args.length - 1];
1389+
if (last != null && last.__proto__ === Object.prototype) {
1390+
return args.pop();
1391+
}
1392+
}
1393+
return null;
1394+
};
13861395
dart._checkAndCall = function(f, ftype, obj, typeArgs, args, name) {
13871396
dart._trackCall(obj, name);
13881397
let originalTarget = obj === void 0 ? f : obj;
13891398
function callNSM() {
1390-
let namedArgs = null;
1391-
if (args.length > 0 && args[args.length - 1].__proto__ == Object.prototype) {
1392-
namedArgs = args.pop();
1393-
}
1394-
return dart.noSuchMethod(originalTarget, new dart.InvocationImpl(name, args, {namedArguments: namedArgs, isMethod: true}));
1399+
return dart.noSuchMethod(originalTarget, new dart.InvocationImpl(name, args, {namedArguments: dart.extractNamedArgs(args), isMethod: true}));
13951400
}
13961401
if (!(f instanceof Function)) {
13971402
if (f != null) {

lib/src/compiler/code_generator.dart

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1404,44 +1404,48 @@ class CodeGenerator extends GeneralizingAstVisitor
14041404
///
14051405
/// It will generate an `eatFood` that looks like:
14061406
///
1407-
/// eatFood(food) {
1407+
/// eatFood(...args) {
14081408
/// return core.bool.as(this.noSuchMethod(
1409-
/// new dart.InvocationImpl('eatFood', [food])));
1409+
/// new dart.InvocationImpl('eatFood', args)));
14101410
/// }
14111411
JS.Method _implementMockMethod(ExecutableElement method) {
1412-
var positionalArgs = <JS.Identifier>[]
1413-
..addAll(
1414-
method.type.normalParameterNames.map((a) => new JS.Identifier(a)))
1415-
..addAll(
1416-
method.type.optionalParameterNames.map((a) => new JS.Identifier(a)));
1417-
1418-
var fnArgs = positionalArgs.toList();
1419-
14201412
var invocationProps = <JS.Property>[];
14211413
addProperty(String name, JS.Expression value) {
14221414
invocationProps.add(new JS.Property(js.string(name), value));
14231415
}
14241416

1417+
var args = new JS.TemporaryId('args');
1418+
var fnArgs = <JS.Parameter>[];
1419+
JS.Expression positionalArgs;;
1420+
14251421
if (method.type.namedParameterTypes.isNotEmpty) {
1426-
fnArgs.add(namedArgumentTemp);
1427-
addProperty('namedArguments', namedArgumentTemp);
1422+
addProperty(
1423+
'namedArguments', js.call('dart.extractNamedArgs(#)', [args]));
14281424
}
14291425

14301426
if (method is MethodElement) {
14311427
addProperty('isMethod', js.boolean(true));
1428+
1429+
fnArgs.add(new JS.RestParameter(args));
1430+
positionalArgs = args;
14321431
} else {
14331432
var property = method as PropertyAccessorElement;
14341433
if (property.isGetter) {
14351434
addProperty('isGetter', js.boolean(true));
1435+
1436+
positionalArgs = new JS.ArrayInitializer([]);
14361437
} else if (property.isSetter) {
14371438
addProperty('isSetter', js.boolean(true));
1439+
1440+
fnArgs.add(args);
1441+
positionalArgs = new JS.ArrayInitializer([args]);
14381442
}
14391443
}
14401444

1441-
var fnBody =
1442-
js.call('this.noSuchMethod(new dart.InvocationImpl(#, #, #))', [
1445+
var fnBody = js.call(
1446+
'this.noSuchMethod(new dart.InvocationImpl(#, #, #))', [
14431447
_elementMemberName(method),
1444-
new JS.ArrayInitializer(positionalArgs),
1448+
positionalArgs,
14451449
new JS.ObjectInitializer(invocationProps)
14461450
]);
14471451

lib/src/js_ast/printer.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -945,7 +945,8 @@ class Printer extends TypeScriptTypePrinter implements NodeVisitor {
945945
visitArrowFun(ArrowFun fun) {
946946
localNamer.enterScope(fun);
947947
if (fun.params.length == 1 &&
948-
(fun.params.single.type == null || !options.emitTypes)) {
948+
fun.params[0] is Identifier &&
949+
(!options.emitTypes || fun.params[0].type == null)) {
949950
visitNestedExpression(fun.params.single, SPREAD,
950951
newInForInit: false, newAtStatementBegin: false);
951952
} else {

test/codegen/language/no_such_method_mock_test.dart

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import "package:expect/expect.dart";
77

88
class Cat {
99
bool eatFood(String food) => true;
10-
int scratch(String furniture) => 100;
10+
String scratch(String furniture) => 'purr';
1111
}
1212

1313
class MockCat implements Cat {
@@ -24,9 +24,13 @@ class MockCat2 extends MockCat {
2424

2525
class MockCat3 extends MockCat2 implements Cat {
2626
bool eatFood(String food, {double amount});
27-
int scratch(String furniture, [String furniture2]);
27+
String scratch(String furniture, [String furniture2]);
2828

2929
dynamic noSuchMethod(Invocation invocation) {
30+
if (invocation.memberName == #scratch) {
31+
return invocation.positionalArguments.join(',');
32+
}
33+
3034
return (invocation.positionalArguments[0] as String).isNotEmpty &&
3135
invocation.namedArguments[#amount] > 0.5;
3236
}
@@ -39,24 +43,48 @@ class MockWithGenerics {
3943
noSuchMethod(i) => i.positionalArguments[0] + 100;
4044
}
4145

46+
class MockWithGetterSetter {
47+
get getter;
48+
set setter(value);
49+
50+
Invocation invocation;
51+
noSuchMethod(i) { invocation = i; }
52+
}
53+
4254

4355
void main() {
4456
MockCat mock = new MockCat();
4557
Expect.isTrue((mock as dynamic).eatFood("cat food"));
4658
Expect.isFalse(mock.eatFood(""));
4759

4860
// In strong mode this will be a runtime type error:
49-
// bool is not an int. VM will fail with noSuchMethod +.
50-
Expect.throws(() => mock.scratch("couch") + 0);
61+
// bool is not a String. VM will fail with noSuchMethod +.
62+
Expect.throws(() => mock.scratch("couch") + '');
5163

5264
var mock2 = new MockCat2();
5365
Expect.isTrue(mock2.eatFood("cat food"));
5466

5567
var mock3 = new MockCat3();
5668
Expect.isTrue(mock3.eatFood("cat food", amount: 0.9));
5769
Expect.isFalse(mock3.eatFood("cat food", amount: 0.3));
70+
Expect.equals(mock3.scratch("chair"), "chair");
71+
Expect.equals(mock3.scratch("chair", "couch"), "chair,couch");
72+
Expect.equals(mock3.scratch("chair", null), "chair,null");
73+
Expect.equals(mock3.scratch("chair", ""), "chair,");
5874

5975
var g = new MockWithGenerics();
6076
Expect.equals(g.doStuff(42), 142);
6177
Expect.throws(() => g.doStuff('hi'));
78+
79+
var s = new MockWithGetterSetter();
80+
s.getter;
81+
Expect.equals(s.invocation.positionalArguments.length, 0);
82+
Expect.equals(s.invocation.isGetter, true);
83+
Expect.equals(s.invocation.isSetter, false);
84+
Expect.equals(s.invocation.isMethod, false);
85+
s.setter = 42;
86+
Expect.equals(s.invocation.positionalArguments.single, 42);
87+
Expect.equals(s.invocation.isGetter, false);
88+
Expect.equals(s.invocation.isSetter, true);
89+
Expect.equals(s.invocation.isMethod, false);
6290
}

test/codegen_expected/language/cyclic_import_test.js

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -277,20 +277,16 @@ dart_library.library('language/cyclic_import_test', null, /* Imports */[
277277
const sub__sub$131 = Object.create(null);
278278
const cyclic_import_test$132 = Object.create(null);
279279
const sub__sub$132 = Object.create(null);
280-
const cyclic_import_test$133 = Object.create(null);
281-
const sub__sub$133 = Object.create(null);
282-
const cyclic_import_test$134 = Object.create(null);
283-
const sub__sub$134 = Object.create(null);
284280
let VoidTodynamic = () => (VoidTodynamic = dart.constFn(dart.definiteFunctionType(dart.dynamic, [])))();
285-
cyclic_import_test$134.value = 42;
286-
cyclic_import_test$134.main = function() {
287-
sub__sub$134.subMain();
281+
cyclic_import_test$132.value = 42;
282+
cyclic_import_test$132.main = function() {
283+
sub__sub$132.subMain();
288284
};
289-
dart.fn(cyclic_import_test$134.main, VoidTodynamic());
290-
sub__sub$134.subMain = function() {
291-
expect$.Expect.equals(42, cyclic_import_test$134.value);
285+
dart.fn(cyclic_import_test$132.main, VoidTodynamic());
286+
sub__sub$132.subMain = function() {
287+
expect$.Expect.equals(42, cyclic_import_test$132.value);
292288
};
293-
dart.fn(sub__sub$134.subMain, VoidTodynamic());
289+
dart.fn(sub__sub$132.subMain, VoidTodynamic());
294290
// Exports:
295291
exports.cyclic_import_test = cyclic_import_test;
296292
exports.sub__sub = sub__sub;
@@ -562,8 +558,4 @@ dart_library.library('language/cyclic_import_test', null, /* Imports */[
562558
exports.sub__sub = sub__sub$131;
563559
exports.cyclic_import_test = cyclic_import_test$132;
564560
exports.sub__sub = sub__sub$132;
565-
exports.cyclic_import_test = cyclic_import_test$133;
566-
exports.sub__sub = sub__sub$133;
567-
exports.cyclic_import_test = cyclic_import_test$134;
568-
exports.sub__sub = sub__sub$134;
569561
});

test/codegen_expected/language/flatten_test_01_multi.js

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -19,37 +19,37 @@ dart_library.library('language/flatten_test_01_multi', null, /* Imports */[
1919
return super.noSuchMethod(invocation);
2020
}
2121
wait(T) {
22-
return (futures, opts) => {
23-
return async.Future$(core.List$(T))._check(this.noSuchMethod(new dart.InvocationImpl('wait', [futures], {namedArguments: opts, isMethod: true})));
22+
return (...args) => {
23+
return async.Future$(core.List$(T))._check(this.noSuchMethod(new dart.InvocationImpl('wait', args, {namedArguments: dart.extractNamedArgs(args), isMethod: true})));
2424
};
2525
}
2626
any(T) {
27-
return futures => {
28-
return async.Future$(T)._check(this.noSuchMethod(new dart.InvocationImpl('any', [futures], {isMethod: true})));
27+
return (...args) => {
28+
return async.Future$(T)._check(this.noSuchMethod(new dart.InvocationImpl('any', args, {isMethod: true})));
2929
};
3030
}
31-
forEach(input, f) {
32-
return async.Future._check(this.noSuchMethod(new dart.InvocationImpl('forEach', [input, f], {isMethod: true})));
31+
forEach(...args) {
32+
return async.Future._check(this.noSuchMethod(new dart.InvocationImpl('forEach', args, {isMethod: true})));
3333
}
34-
doWhile(f) {
35-
return async.Future._check(this.noSuchMethod(new dart.InvocationImpl('doWhile', [f], {isMethod: true})));
34+
doWhile(...args) {
35+
return async.Future._check(this.noSuchMethod(new dart.InvocationImpl('doWhile', args, {isMethod: true})));
3636
}
3737
then(S) {
38-
return (onValue, opts) => {
39-
return async.Future$(S)._check(this.noSuchMethod(new dart.InvocationImpl('then', [onValue], {namedArguments: opts, isMethod: true})));
38+
return (...args) => {
39+
return async.Future$(S)._check(this.noSuchMethod(new dart.InvocationImpl('then', args, {namedArguments: dart.extractNamedArgs(args), isMethod: true})));
4040
};
4141
}
42-
catchError(onError, opts) {
43-
return FutureOfT()._check(this.noSuchMethod(new dart.InvocationImpl('catchError', [onError], {namedArguments: opts, isMethod: true})));
42+
catchError(...args) {
43+
return FutureOfT()._check(this.noSuchMethod(new dart.InvocationImpl('catchError', args, {namedArguments: dart.extractNamedArgs(args), isMethod: true})));
4444
}
45-
whenComplete(action) {
46-
return FutureOfT()._check(this.noSuchMethod(new dart.InvocationImpl('whenComplete', [action], {isMethod: true})));
45+
whenComplete(...args) {
46+
return FutureOfT()._check(this.noSuchMethod(new dart.InvocationImpl('whenComplete', args, {isMethod: true})));
4747
}
48-
asStream() {
49-
return StreamOfT()._check(this.noSuchMethod(new dart.InvocationImpl('asStream', [], {isMethod: true})));
48+
asStream(...args) {
49+
return StreamOfT()._check(this.noSuchMethod(new dart.InvocationImpl('asStream', args, {isMethod: true})));
5050
}
51-
timeout(timeLimit, opts) {
52-
return FutureOfT()._check(this.noSuchMethod(new dart.InvocationImpl('timeout', [timeLimit], {namedArguments: opts, isMethod: true})));
51+
timeout(...args) {
52+
return FutureOfT()._check(this.noSuchMethod(new dart.InvocationImpl('timeout', args, {namedArguments: dart.extractNamedArgs(args), isMethod: true})));
5353
}
5454
get _nullFuture() {
5555
return async._Future._check(this.noSuchMethod(new dart.InvocationImpl('_nullFuture', [], {isGetter: true})));
@@ -69,37 +69,37 @@ dart_library.library('language/flatten_test_01_multi', null, /* Imports */[
6969
return super.noSuchMethod(invocation);
7070
}
7171
wait(T) {
72-
return (futures, opts) => {
73-
return async.Future$(core.List$(T))._check(this.noSuchMethod(new dart.InvocationImpl('wait', [futures], {namedArguments: opts, isMethod: true})));
72+
return (...args) => {
73+
return async.Future$(core.List$(T))._check(this.noSuchMethod(new dart.InvocationImpl('wait', args, {namedArguments: dart.extractNamedArgs(args), isMethod: true})));
7474
};
7575
}
7676
any(T) {
77-
return futures => {
78-
return async.Future$(T)._check(this.noSuchMethod(new dart.InvocationImpl('any', [futures], {isMethod: true})));
77+
return (...args) => {
78+
return async.Future$(T)._check(this.noSuchMethod(new dart.InvocationImpl('any', args, {isMethod: true})));
7979
};
8080
}
81-
forEach(input, f) {
82-
return async.Future._check(this.noSuchMethod(new dart.InvocationImpl('forEach', [input, f], {isMethod: true})));
81+
forEach(...args) {
82+
return async.Future._check(this.noSuchMethod(new dart.InvocationImpl('forEach', args, {isMethod: true})));
8383
}
84-
doWhile(f) {
85-
return async.Future._check(this.noSuchMethod(new dart.InvocationImpl('doWhile', [f], {isMethod: true})));
84+
doWhile(...args) {
85+
return async.Future._check(this.noSuchMethod(new dart.InvocationImpl('doWhile', args, {isMethod: true})));
8686
}
8787
then(S) {
88-
return (onValue, opts) => {
89-
return async.Future$(S)._check(this.noSuchMethod(new dart.InvocationImpl('then', [onValue], {namedArguments: opts, isMethod: true})));
88+
return (...args) => {
89+
return async.Future$(S)._check(this.noSuchMethod(new dart.InvocationImpl('then', args, {namedArguments: dart.extractNamedArgs(args), isMethod: true})));
9090
};
9191
}
92-
catchError(onError, opts) {
93-
return FutureOfFixedPointOfT()._check(this.noSuchMethod(new dart.InvocationImpl('catchError', [onError], {namedArguments: opts, isMethod: true})));
92+
catchError(...args) {
93+
return FutureOfFixedPointOfT()._check(this.noSuchMethod(new dart.InvocationImpl('catchError', args, {namedArguments: dart.extractNamedArgs(args), isMethod: true})));
9494
}
95-
whenComplete(action) {
96-
return FutureOfFixedPointOfT()._check(this.noSuchMethod(new dart.InvocationImpl('whenComplete', [action], {isMethod: true})));
95+
whenComplete(...args) {
96+
return FutureOfFixedPointOfT()._check(this.noSuchMethod(new dart.InvocationImpl('whenComplete', args, {isMethod: true})));
9797
}
98-
asStream() {
99-
return StreamOfFixedPointOfT()._check(this.noSuchMethod(new dart.InvocationImpl('asStream', [], {isMethod: true})));
98+
asStream(...args) {
99+
return StreamOfFixedPointOfT()._check(this.noSuchMethod(new dart.InvocationImpl('asStream', args, {isMethod: true})));
100100
}
101-
timeout(timeLimit, opts) {
102-
return FutureOfFixedPointOfT()._check(this.noSuchMethod(new dart.InvocationImpl('timeout', [timeLimit], {namedArguments: opts, isMethod: true})));
101+
timeout(...args) {
102+
return FutureOfFixedPointOfT()._check(this.noSuchMethod(new dart.InvocationImpl('timeout', args, {namedArguments: dart.extractNamedArgs(args), isMethod: true})));
103103
}
104104
get _nullFuture() {
105105
return async._Future._check(this.noSuchMethod(new dart.InvocationImpl('_nullFuture', [], {isGetter: true})));

0 commit comments

Comments
 (0)