Skip to content

Commit

Permalink
Fix handling of junctions by Range ACCEPTS
Browse files Browse the repository at this point in the history
It would manually thread over topic if it's a junction.

The default `ACCEPTS` method now expects `Any`-typed topic. Since we
don't have `cmp` operator for `Mu`, `Range`, in order to handle any
user-created direct `Mu` child, tries to find user-defined
`&infix:<cmp>` and throws with `X::Range::Incomparable` if can't find
any appropriate.

There are still two problems here. First, there is no support for custom
user `cmp` operator for `Any`-inheriting classes. Second, custom
operator couldn't be found for `Mu`-inheriting classes if they're part
of a junction. In the latter case the problem is about the fact that
`CLIENT::` namespace would point into `Junction` class.

Both issues can only be fixed at the cost of performance loss which is
barely acceptable considering the wide use of ranges across the
codebase.
  • Loading branch information
vrurg committed Dec 27, 2021
1 parent 6b828fe commit ed85bad
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 3 deletions.
11 changes: 11 additions & 0 deletions src/core.c/Exception.pm6
Expand Up @@ -2360,6 +2360,17 @@ my class X::Range::InvalidArg is Exception {
}
}

my class X::Range::Incomparable is Exception {
has $.topic;
has $.endpoint;
has $.what-endpoint;
method message() {
"Value of type '" ~ $.topic.^name
~ "' cannot be compared with range $.what-endpoint of type '"
~ $.endpoint.^name ~ "'"
}
}

my class X::Sequence::Deduction is Exception {
has $.from;
method message() {
Expand Down
28 changes: 25 additions & 3 deletions src/core.c/Range.pm6
@@ -1,5 +1,6 @@
my class X::Immutable { ... }
my class X::Range::InvalidArg { ... }
my class X::Range::Incomparable { ... }

my class Range is Cool does Iterable does Positional {
has $.min;
Expand Down Expand Up @@ -401,9 +402,14 @@ my class Range is Cool does Iterable does Positional {
!! self.list.Str
}

multi method ACCEPTS(Range:D: Mu \topic) {
(topic cmp $!min) > -(!$!excludes-min)
and (topic cmp $!max) < +(!$!excludes-max)
my sub IS-COMPARABLE(&client-cmp, Mu $topic, Mu $endpoint, $what-endpoint) {
unless &client-cmp.cando($topic, $endpoint) {
X::Range::Incomparable.new(:$topic, :$endpoint, :$what-endpoint).throw
}
}

multi method ACCEPTS(Range:D \SELF: Junction:D $topic) {
$topic.THREAD: { SELF.ACCEPTS($_) }
}
multi method ACCEPTS(Range:D: Cool:D \got) {
nqp::if(
Expand Down Expand Up @@ -448,6 +454,22 @@ my class Range is Cool does Iterable does Positional {
|| topic.max eq $!max
&& !(!topic.excludes-max && $!excludes-max))
}
multi method ACCEPTS(Range:D: Any \topic) {
(topic cmp $!min) > -(!$!excludes-min)
and (topic cmp $!max) < +(!$!excludes-max)
}
multi method ACCEPTS(Range:D: Mu \topic) {
# Generally speaking, Mu is not a comparable type. Neither any of its children unless specific multi-candidates
# of &infix:<cmp> are provided by user code. In this case try to go slow path.
# XXX This still doesn't work with junctions because with threading this method is invoked from Junction's
# namespace.
my &client-cmp := CLIENT::LEXICAL::{'&infix:<cmp>'};
IS-COMPARABLE(&client-cmp, topic, $!min, 'minimum');
IS-COMPARABLE(&client-cmp, topic, $!max, 'maximum');

(&client-cmp(topic, $!min) > -(!$!excludes-min)
and &client-cmp(topic, $!max) < +(!$!excludes-max))
}

method ASSIGN-POS(Range:D: |) { X::Assignment::RO.new(value => self).throw }

Expand Down

0 comments on commit ed85bad

Please sign in to comment.