Search code examples
compilationrakucompile-timerakudo

Sequence of Raku program compilation and execution (maybe nested compile phases?)


The following program correctly fails to compile:

sub f(Int $a) { my Str $b = $a }
say f 42;
say f 'foo';

Specifically, line 3 causes a compilation error (with a ===SORRY!=== error message); this error occurs before line 2 is executed, so the type mismatch within &f is never reached.

But when, specifically, does this error occur? I thought it occurred during the CHECK phase, but was surprised to notice that raku -c does not generate a compile error; it reports Syntax OK.

To dig into this a bit more, I added logging code to the snippet above:

BEGIN note 'begin';
CHECK note 'check';
INIT  note 'init';
END   note 'end';

sub f(Int $a) { my Str $b = $a }
say f 42;
say f 'foo';

Running this revised code with raku -c prints "begin\n check\n Syntax OK"; running it with raku prints "begin\n check\n ===SORRY!===" (and the rest of the error message).

If I remove the say f 'foo' line (and thus the compile error), raku -c still prints "begin\n check\n Syntax OK" but raku prints "begin\n check\n init\n Type check failed… \n end" (again omitting the body of the error message).

What's going on here? Does the compile error that generated the ===SORRY!=== occur some time between CHECK and INIT (is there any such time?)? Or does raku -c not actually "run BEGIN and CHECK blocks" as raku --help indicates? Or something else?

Relatedly: how, if at all, is any of this connected to the idea of "nested compile times"? Does the execution of this code involve any nested compile times, or does that only occur when using modules? Is there any way to note/log separate compile phases (maybe with correctly placed BEGIN blocks?) or is that something that isn't exposed?


Solution

  • The SORRY message is a side-effect of the static optimizer. Observe the difference in behaviour between:

    $ raku -e 'sub foo(Int $a) { }; foo "foo"'
    ===SORRY!=== Error while compiling -e
    Calling foo(Str) will never work with declared signature (Int $a)
    

    and:

    $ raku --optimize=off -e 'sub foo(Int $a) { }; foo "foo"'
    Type check failed in binding to parameter '$a'; expected Int but got Str ("foo")
      in sub foo at -e line 1
    

    which happens somewhere between CHECK and INIT time, unless it has been disabled. Note that disabling the static optimizer makes it a runtime error.