Skip to content

Commit

Permalink
Merge pull request #818 from vrurg/generic-parameterization-lookup
Browse files Browse the repository at this point in the history
Add a test for role parameterization of generics
  • Loading branch information
vrurg committed Aug 26, 2022
2 parents d965e0d + 161a601 commit a95e5a9
Showing 1 changed file with 55 additions and 44 deletions.
99 changes: 55 additions & 44 deletions S14-roles/parameterized-type.t
Expand Up @@ -2,7 +2,7 @@ use v6;

use Test;

plan 32;
plan 11;

=begin pod
Expand All @@ -13,55 +13,59 @@ Tests for using parameterized roles as types, plus the of keyword.
# L<S14/Parametric Roles>
# L<S14/Relationship Between of And Types>

role R1[::T] { method x { T } }
class C1 does R1[Int] { }
class C2 does R1[Str] { }
lives-ok { my R1 of Int $x = C1.new }, 'using of as type constraint on variable works (class does role)';
dies-ok { my R1 of Int $x = C2.new }, 'using of as type constraint on variable works (class does role)';
lives-ok { my R1 of Int $x = R1[Int].new }, 'using of as type constraint on variable works (role instantiation)';
dies-ok { my R1 of Int $x = R1[Str].new }, 'using of as type constraint on variable works (role instantiation)';

sub param_test(R1 of Int $x) { $x.x }
isa-ok param_test(C1.new), Int, 'using of as type constraint on parameter works (class does role)';
dies-ok { param_test(C2.new) }, 'using of as type constraint on parameter works (class does role)';
isa-ok param_test(R1[Int].new), Int, 'using of as type constraint on parameter works (role instantiation)';
dies-ok { param_test(R1[Str].new) }, 'using of as type constraint on parameter works (role instantiation)';

role R2[::T] {
method x { "ok" }
method call_test { self.call_test_helper(T.new) }
method call_test_helper(T $x) { "ok" } #OK not used
method call_fail { self.call_test_helper(4.5) }
subtest "Parameterization as constraint" => {
my role R1[::T] { method x { T } }
my class C1 does R1[Int] { }
my class C2 does R1[Str] { }
lives-ok { my R1 of Int $x = C1.new }, 'using of as type constraint on variable works (class does role)';
dies-ok { my R1 of Int $x = C2.new }, 'using of as type constraint on variable works (class does role)';
lives-ok { my R1 of Int $x = R1[Int].new }, 'using of as type constraint on variable works (role instantiation)';
dies-ok { my R1 of Int $x = R1[Str].new }, 'using of as type constraint on variable works (role instantiation)';

sub param_test(R1 of Int $x) { $x.x }
isa-ok param_test(C1.new), Int, 'using of as type constraint on parameter works (class does role)';
dies-ok { param_test(C2.new) }, 'using of as type constraint on parameter works (class does role)';
isa-ok param_test(R1[Int].new), Int, 'using of as type constraint on parameter works (role instantiation)';
dies-ok { param_test(R1[Str].new) }, 'using of as type constraint on parameter works (role instantiation)';
}

subtest "Recursive-ish parameterization" => {
my role R2[::T] {
method x { "ok" }
method call_test { self.call_test_helper(T.new) }
method call_test_helper(T $x) { "ok" } #OK not used
method call_fail { self.call_test_helper(4.5) }
}
my class C3 does R2[R2[Int]] { }
my class C4 does R2[R2[Str]] { }

lives-ok { my R2 of R2 of Int $x = C3.new }, 'roles parameterized with themselves as type constraints';
dies-ok { my R2 of R2 of Int $x = C4.new }, 'roles parameterized with themselves as type constraints';
lives-ok { my R2 of R2 of Int $x = R2[R2[Int]].new }, 'roles parameterized with themselves as type constraints';
dies-ok { my R2 of R2 of Int $x = R2[R2[Str]].new }, 'roles parameterized with themselves as type constraints';

sub param_test_r(R2 of R2 of Int $x) { $x.x }
is param_test_r(C3.new), 'ok', 'roles parameterized with themselves as type constraints';
dies-ok { param_test_r(C4.new) }, 'roles parameterized with themselves as type constraints';
is param_test_r(R2[R2[Int]].new), 'ok', 'roles parameterized with themselves as type constraints';
dies-ok { param_test_r(R2[R2[Str]].new) }, 'roles parameterized with themselves as type constraints';

is R2[Int].new.call_test, 'ok', 'types being used as type constraints inside roles work';
dies-ok { R2[Int].new.call_fail }, 'types being used as type constraints inside roles work';
is C3.new.call_test, 'ok', 'roles being used as type constraints inside roles work';
dies-ok { C3.new.call_fail }, 'roles being used as type constraints inside roles work';
is C4.new.call_test, 'ok', 'roles being used as type constraints inside roles work';
dies-ok { C4.new.call_fail }, 'roles being used as type constraints inside roles work';
is R2[C3].new.call_test, 'ok', 'classes being used as type constraints inside roles work';
dies-ok { R2[C3].new.call_fail }, 'classes being used as type constraints inside roles work';
}
class C3 does R2[R2[Int]] { }
class C4 does R2[R2[Str]] { }

lives-ok { my R2 of R2 of Int $x = C3.new }, 'roles parameterized with themselves as type constraints';
dies-ok { my R2 of R2 of Int $x = C4.new }, 'roles parameterized with themselves as type constraints';
lives-ok { my R2 of R2 of Int $x = R2[R2[Int]].new }, 'roles parameterized with themselves as type constraints';
dies-ok { my R2 of R2 of Int $x = R2[R2[Str]].new }, 'roles parameterized with themselves as type constraints';

sub param_test_r(R2 of R2 of Int $x) { $x.x }
is param_test_r(C3.new), 'ok', 'roles parameterized with themselves as type constraints';
dies-ok { param_test_r(C4.new) }, 'roles parameterized with themselves as type constraints';
is param_test_r(R2[R2[Int]].new), 'ok', 'roles parameterized with themselves as type constraints';
dies-ok { param_test_r(R2[R2[Str]].new) }, 'roles parameterized with themselves as type constraints';

is R2[Int].new.call_test, 'ok', 'types being used as type constraints inside roles work';
dies-ok { R2[Int].new.call_fail }, 'types being used as type constraints inside roles work';
is C3.new.call_test, 'ok', 'roles being used as type constraints inside roles work';
dies-ok { C3.new.call_fail }, 'roles being used as type constraints inside roles work';
is C4.new.call_test, 'ok', 'roles being used as type constraints inside roles work';
dies-ok { C4.new.call_fail }, 'roles being used as type constraints inside roles work';
is R2[C3].new.call_test, 'ok', 'classes being used as type constraints inside roles work';
dies-ok { R2[C3].new.call_fail }, 'classes being used as type constraints inside roles work';

# https://github.com/Raku/old-issue-tracker/issues/1491
throws-like 'role ABCD[EFGH] { }', X::Parameter::InvalidType, 'role with undefined type as parameter dies';

# https://github.com/Raku/old-issue-tracker/issues/1193
{
role TreeNode[::T] does Positional {
my role TreeNode[::T] does Positional {
has TreeNode[T] @!children handles <AT-POS ASSIGN-POS BIND-POS>;
has T $.data is rw;
};
Expand All @@ -77,7 +81,7 @@ throws-like 'role ABCD[EFGH] { }', X::Parameter::InvalidType, 'role with undefin

# https://github.com/Raku/old-issue-tracker/issues/1192
{
role P[$x] { }
my role P[$x] { }
# ::T only makes sense in a signature here, not in
# an argument list.
dies-ok { EVAL 'class MyClass does P[::T] { }' },
Expand Down Expand Up @@ -121,4 +125,11 @@ throws-like 'role ABCD[EFGH] { }', X::Parameter::InvalidType, 'role with undefin
lives-ok { EVAL 'my role A [ :$bs where { True } = 512] { }; class B does A { }' },
'role with where clause and default in parametric signature works out OK';

{
my role A[::T] {
method a { A[T] }
}
isa-ok A[Int].a, A[Int], "role is correctly paramterized in a role's method body";
}

# vim: expandtab shiftwidth=4

0 comments on commit a95e5a9

Please sign in to comment.