This is a follow-up to my previous question.
I am finally able to reproduce the error here:
my @recentList = prompt("Get recentList: e.g. 1 2 3: ").words || (2,4,6);
say "the list is: ", @recentList;
for @recentList -> $x {
say "one element is: ", $x;
say "element type is: ", $x.WHAT;
say "test (1,2,3).tail(\"2\") : ", (1,2,3).tail("2");
say ( (10.rand.Int xx 10) xx 15 ).map: { @($_.tail($x)); };
}
And the results are ok as long as I use the default list by just hitting return at the prompt and not entering anything. But if I enter a number, it gives this error:
Get recentList: e.g. 1 2 3: 2
the list is: [2]
one element is: 2
element type is: (Str)
test (1,2,3).tail("2") : (2 3)
This type cannot unbox to a native integer: P6opaque, Str
in block at intType.p6 line 9
in block <unit> at intType.p6 line 5
If tail("2") works, why does tail($x) fail? Also, in my original code, tail($x.Int) wouldn't correct the problem, but it did here.
This is at best a nanswer. It is a thus-far failed attempt to figure out this problem. I may have just wandered off into the weeds. But I'll publish what I have. If nothing else, maybe it can serve as a reminder that the first three steps below are sensible ones; thereafter I'm gambling on my ability to work my way forward by spelunking source code when I would probably make much faster and more reliable progress by directly debugging the compiler as discussed in the third step.
OK, the first step was an MRE. What you've provided was an E that was fully R and sufficiently M. :)
Step #2 was increasing the M (golfing). I got it down to:
Any.tail('0'); # OK
Any.tail('1'); # BOOM
Note that it can be actual values:
1.tail('1'); # BOOM
(1..2).tail('1'); # BOOM
But some values work:
(1,2).tail('1'); # OK
Step #3 probably should be to follow the instructions in Playing with the code of Rakudo Perl 6 to track the compiler's execution, eg by sticking say
s in its source code and recompiling it.
You may also want to try out App::MoarVM::Debug. (I haven't.)
Using these approaches you'll have the power to track with absolute precision what the compiler does for any code you throw at it. I recommend you do this even though I didn't. Maybe you can figure out where I've gone wrong.
In the following I trace this problem by just directly spelunking the Rakudo compiler's source code.
A search for "method tail" in the Rakudo sources yielded 4 matches. For my golf the matching method is a match in core/AnyIterableMethods.pm6
.
The tail
parameter $n
clearly isn't a Callable
so the pertinent line that continues our spelunking is Rakudo::Iterator.LastNValues(self.iterator,$n,'tail')
.
A search for this leads to this method in core/Iterator.pm6
.
This in turn calls this .new
routine.
These three lines:
nqp::if(
n <= 0, # must be HLL comparison
Rakudo::Iterator.Empty, # negative is just nothing
explain why '0'
works. The <=
operator coerces its operands to numeric before doing the numeric comparison. So '0'
coerces to 0
, the condition is True
, the result is Rakudo::Iterator.Empty
, and the Any.tail('0')
yields ()
and doesn't complain.
The code that immediately follows the above three lines is the else branch of the nqp::if
. It closes with nqp::create(self)!SET-SELF(iterator,n,f)
.
That in turn calls the !SET-SELF
routine, which has the line:
($!lastn := nqp::setelems(nqp::list, $!size = size)),
Which attempts to assign size
, which in our BOOM case is '1'
, to $!size
. But $!size
is declared as:
has int $!size;
Bingo.
Or is it? I don't know if I really have correctly tracked the problem down. I'm only spelunking the code in the github repo, not actually running an instrumented version of the compiler and tracing its execution, as discussed as the sensible step #3 for trying to figure out the problem you've encountered.
Worse, when I'm running a compiler it's an old one whereas the code I'm spelunking is the master
...
Why does this work?
(*,*).tail('1') # OK
The code path for this will presumably be this method. The parameter $n
isn't a Callable
so the code path will run thru the path that uses the $n
in the lines:
nqp::unless(
nqp::istype($n,Whatever) || $n == Inf,
$iterator.skip-at-least(nqp::elems($!reified) - $n.Int)
The $n == Inf
shouldn't be a problem. The ==
will coerce its operands to numerics and that should take care of $n
being '1'
.
The nqp::elems($!reified) - $n.Int
shouldn't be a problem either.
The nqp ops doc shows that nqp::elems
always returns an int
. So this boils down to an int - Int
which should work.
Hmm.
A blame of these lines shows that the .Int
in the last line was only added 3 months ago.
So, clutching at straws, what happens if one tries:
(my int $foo = 1) - '1' # OK
Nope, that's not the problem.
It seems the trail has grown cold or rather I've wandered off the actual execution path.
I'll publish what I've got. Maybe someone else can pick it up from here or I'll have another go in a day or three...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With