Skip to content

Commit e635192

Browse files
committed
Add tests for dispatcher interaction
Method, multi, and wrapper dispatchers must not break each other and return control to the previous dispatching when exhausted.
1 parent e7a0707 commit e635192

File tree

2 files changed

+120
-0
lines changed

2 files changed

+120
-0
lines changed

S06-advanced/dispatching.t

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
use v6;
2+
use Test;
3+
use soft;
4+
plan 13;
5+
my @order;
6+
7+
my class C1 {
8+
method foo(|) { @order.push: ::?CLASS.^name }
9+
}
10+
11+
my class C2 is C1 {
12+
proto method foo(|) {*}
13+
multi method foo(Str $s) {
14+
@order.push: ::?CLASS.^name ~ "(Str)";
15+
nextsame;
16+
}
17+
multi method foo(Int $s) {
18+
@order.push: ::?CLASS.^name ~ "(Int)";
19+
nextsame;
20+
}
21+
multi method foo(Num) {
22+
@order.push: ::?CLASS.^name ~ "(Num)";
23+
nextsame
24+
}
25+
}
26+
27+
my class C3 is C2 {
28+
method foo(|) {
29+
@order.push: ::?CLASS.^name;
30+
nextsame
31+
}
32+
}
33+
34+
my class C4 is C3 {
35+
proto method foo(|) {*}
36+
multi method foo(Int:D $v) {
37+
@order.push: ::?CLASS.^name ~ "(Int:D)";
38+
nextwith ~$v
39+
}
40+
multi method foo(Any) {
41+
@order.push: ::?CLASS.^name ~ "(Any)";
42+
callsame
43+
}
44+
}
45+
46+
my $inst;
47+
48+
$inst = C3.new;
49+
$inst.foo("bar");
50+
is-deeply @order.List, <C3 C2(Str) C1>, "a multi-method doesn't break MRO dispatching";
51+
@order = [];
52+
$inst.foo(42);
53+
is-deeply @order.List, <C3 C2(Int) C1>, "a multi-method dispatching works correctly";
54+
55+
$inst = C4.new;
56+
@order = [];
57+
$inst.foo("baz");
58+
is-deeply @order.List, <C4(Any) C3 C2(Str) C1>, "multi being the first method in MRO still works";
59+
@order = [];
60+
$inst.foo(13);
61+
is-deeply @order.List, <C4(Int:D) C4(Any) C3 C2(Str) C1>, "nextwith does what's expected";
62+
63+
my \proto := C2.^find_method('foo', :local, :no_fallback);
64+
65+
nok proto.is_wrapped, "proto is not wrapped yet";
66+
my $wh1 = proto.wrap(my method foo-wrap(|) { @order.push: "foo-proto"; nextsame });
67+
ok proto.is_wrapped, "proto is wrapped now";
68+
69+
@order = [];
70+
$inst.foo("");
71+
is-deeply @order.List, <C4(Any) C3 foo-proto C2(Str) C1>, "proto can be wrapped";
72+
73+
proto.unwrap($wh1);
74+
@order = [];
75+
$inst.foo("");
76+
is-deeply @order.List, <C4(Any) C3 C2(Str) C1>, "proto can be unwrapped";
77+
78+
# This should be foo(Rat) candidate
79+
my \cand = proto.candidates[2];
80+
# Note that next* can't be used with blocks.
81+
$wh1 = cand.wrap(-> *@ { @order.push('foo-num-wrap'); callsame });
82+
@order = [];
83+
$inst.foo(pi);
84+
is-deeply @order.List, <C4(Any) C3 foo-num-wrap C2(Num) C1>, "we can wrap a candidate";
85+
86+
# We can even wrap a candidate with another multi. It works!
87+
proto multi-wrap(|) {*}
88+
multi multi-wrap(\SELF, Num) {
89+
@order.push: "multi-wrap(Num)";
90+
nextsame
91+
}
92+
multi multi-wrap(\SELF, Any) {
93+
@order.push: "multi-wrap(Any)";
94+
nextsame
95+
}
96+
97+
my $wh2 = cand.wrap(&multi-wrap);
98+
@order = [];
99+
$inst.foo(pi);
100+
is-deeply @order.List, <C4(Any) C3 multi-wrap(Num) multi-wrap(Any) foo-num-wrap C2(Num) C1>, "we can use a multi as a wrapper of a candidate";
101+
102+
cand.unwrap($wh1);
103+
@order = [];
104+
$inst.foo(pi);
105+
is-deeply @order.List, <C4(Any) C3 multi-wrap(Num) multi-wrap(Any) C2(Num) C1>, "we can use a multi as a wrapper of a candidate";
106+
107+
# Even nastier thing: wrap a candidate of our wrapper!
108+
my $wwh = &multi-wrap.candidates[1].wrap(sub (|) { @order.push: 'cand-wrap'; nextsame });
109+
@order = [];
110+
$inst.foo(pi);
111+
is-deeply @order.List, <C4(Any) C3 multi-wrap(Num) cand-wrap multi-wrap(Any) C2(Num) C1>, "we can use a multi as a wrapper of a candidate";
112+
113+
# Unwrap the method candidate from the second wrapper. We then get the original behavior.
114+
cand.unwrap($wh2);
115+
@order = [];
116+
$inst.foo(pi);
117+
is-deeply @order.List, <C4(Any) C3 C2(Num) C1>, "we can use a multi as a wrapper of a candidate";
118+
119+
done-testing;

spectest.data

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,7 @@ S05-transliteration/trans.t
483483
S05-transliteration/trans-tr-lowercase-operator.t
484484
S05-transliteration/trans-TR-operator.t
485485
S05-transliteration/with-closure.t
486+
S06-advanced/dispatching.t
486487
S06-advanced/callframe.t
487488
S06-advanced/callsame.t
488489
S06-advanced/lexical-subs.t

0 commit comments

Comments
 (0)