这是my previous question的后续.
我终于能够在这里重现错误:
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)); };
}
只要我使用默认列表,只需在提示符下按回车键而不输入任何内容,结果就可以了。但是如果我输入一个数字,它会出现这个错误:
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
如果 tail("2") 有效,为什么 tail($x) 失败?此外,在我的原始代码中, tail($x.Int) 不会纠正问题,但在这里确实如此。
最佳答案
这充其量是一个答案。这是迄今为止解决这个问题的失败尝试。我可能只是在杂草中徘徊。但我会公布我所拥有的。如果不出意外,也许它可以提醒以下前三个步骤是明智的;此后,当我通过直接调试编译器(如第三步中讨论的那样)可能会取得更快、更可靠的进展时,我正在赌我通过挖掘源代码继续前进的能力。
好的,第一步是 MRE .你提供的是一个完全 R 和足够 M 的 E。:)
第 2 步是增加 M(打高尔夫球)。我把它归结为:
Any.tail('0'); # OK
Any.tail('1'); # BOOM
请注意,它可以是实际值:
1.tail('1'); # BOOM
(1..2).tail('1'); # BOOM
但有些值是有效的:
(1,2).tail('1'); # OK
第 3 步可能应该按照 Playing with the code of Rakudo Perl 6 中的说明进行操作。跟踪编译器的执行,例如通过粘贴
say
s 在其源代码中并重新编译它。您可能还想试试 App::MoarVM::Debug . (我没有。)
使用这些方法,您将有能力绝对精确地跟踪编译器对您抛出的任何代码所做的事情。我建议你这样做,即使我没有这样做。也许你能弄清楚我哪里出错了。
在下文中,我通过直接挖掘 Rakudo 编译器的源代码来追踪这个问题。
search for "method tail" in the Rakudo sources产生了 4 场比赛。对于我的高尔夫,匹配方法是 a match in
core/AnyIterableMethods.pm6
.tail
参数 $n
显然不是 Callable
所以继续我们洞穴探险的相关线路是 Rakudo::Iterator.LastNValues(self.iterator,$n,'tail')
.对此进行搜索会导致 this method在
core/Iterator.pm6
.这反过来调用 this
.new
routine .These three lines :
nqp::if(
n <= 0, # must be HLL comparison
Rakudo::Iterator.Empty, # negative is just nothing
解释原因
'0'
作品。 <=
运算符在进行数字比较之前将其操作数强制转换为数字。所以'0'
强制到 0
,条件为 True
,结果是 Rakudo::Iterator.Empty
,以及 Any.tail('0')
yield ()
并且不提示。紧跟在上面三行之后的代码是
nqp::if
的else分支.它以 nqp::create(self)!SET-SELF(iterator,n,f)
结束.这反过来又调用了
!SET-SELF
例程,其中有一行:($!lastn := nqp::setelems(nqp::list, $!size = size)),
哪个尝试分配
size
,在我们的 BOOM 案例中是 '1'
, 至 $!size
.但是 $!size
is declared as :has int $!size;
答对了。
或者是吗?我不知道我是否真的正确地追踪了问题。我只是在 github 存储库中挖掘代码,实际上并没有运行编译器的检测版本并跟踪其执行情况,正如讨论的第 3 步,试图找出您遇到的问题的明智之举。
更糟糕的是,当我运行编译器时,它是旧的,而我正在探索的代码是
master
...为什么这样做?
(*,*).tail('1') # OK
这个的代码路径大概是 this method .参数
$n
不是 Callable
所以代码路径将通过使用 $n
的路径运行在行中: nqp::unless(
nqp::istype($n,Whatever) || $n == Inf,
$iterator.skip-at-least(nqp::elems($!reified) - $n.Int)
$n == Inf
应该没有问题。 ==
将其操作数强制转换为数字,这应该处理 $n
正在 '1'
.nqp::elems($!reified) - $n.Int
也不应该有问题。nqp ops 文档显示
nqp::elems
always returns an int
.所以这归结为 int - Int
哪个应该工作。唔。
A blame of these lines显示 the
.Int
in the last line was only added 3 months ago .所以,捕获稻草,如果有人尝试会发生什么:
(my int $foo = 1) - '1' # OK
不,这不是问题。
这条线索似乎已经变冷了,或者更确切地说,我已经偏离了实际的执行路径。
我会发布我所拥有的。也许其他人可以从这里拿起它,或者我会在一三天内再去一次......
关于string - Perl 6 中的 “P6opaque, Str” 与简单的 “Str” 类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57136084/