# New Ticket Created by  Zefram 
# Please include the string:  [perl #127014]
# in the subject line of all future correspondence about this issue. 
# <URL: https://rt.perl.org/Ticket/Display.html?id=127014 >


Is it legal to compile code that, if executed, would always produce
an exception?  Rakudo seems conflicted on the matter.  Most often it is
permitted, as in these cases:

> sub () { my constant \a := 3.5e0; my Int $b; $b = a if False; }
sub () { #`(Sub|94227680) ... }
> sub () { my constant \a := 3.5e0; my Int $b; $b = a; }
sub () { #`(Sub|94218864) ... }

Both of these contain an assignment expression that would produce an
exception if executed.  In the latter case, the assignment would be
executed if the subroutine were called.  In the former case, it would
not be executed even then.  In both cases I have not actually called
the subroutine, so no problem arises at this stage.  But if I wish then
I can call them, to get the obvious runtime behaviour:

> (sub () { my constant \a := 3.5e0; my Int $b; $b = a if False; })()
()
> (sub () { my constant \a := 3.5e0; my Int $b; $b = a; })()
Type check failed in assignment to $b; expected Int but got Num
  in sub  at <unknown file>:1
  in block <unit> at <unknown file>:1

However, the following two very similar cases don't permit the code to
be compiled:

> sub () { my Int $b; $b = 3.5e0 if False; }
===SORRY!=== Error while compiling <unknown file>
Cannot assign a literal of type Num (3.5e0) to a variable of type Int. You can 
declare the variable to be of type Real, or try to coerce the value with 
3.5e0.Int or Int(3.5e0), or just write the value as 3
at <unknown file>:1
------> sub () { my Int $b; $b = ^3.5e0 if False; }
> sub () { my Int $b; $b = 3.5e0; }
===SORRY!=== Error while compiling <unknown file>
Cannot assign a literal of type Num (3.5e0) to a variable of type Int. You can 
declare the variable to be of type Real, or try to coerce the value with 
3.5e0.Int or Int(3.5e0), or just write the value as 3
at <unknown file>:1
------> sub () { my Int $b; $b = ^3.5e0; }

Note that, like the first pair of cases, I'm not attempting to
actually execute the problematic assignment.  In both cases the code is
syntactically well-formed, and even meaningful, in that we can say exactly
how it would behave if the subroutine were called, if the compiler had
allowed us to get that far.  The behaviour would be identical to that
seen in the second pair of cases.

Making code like this error at compile time impedes the use of the
language with machine-generated code.  It is quite normal to end up
generating dead branches that are well-formed but can never be reached,
and because they're unreachable the logic of the generating program may
have little to say about how they would behave if reached.  For this
reason and for general predictability (given that one doesn't know how
clever the compiler will be this week) it is unwise to refuse to compile
code just because one can predict that it would fail if executed.  If the
compiler spots such a situation, it can make better use of its foresight
by optimising the compilation, directly emitting code to generate the
exception at runtime.

-zefram

Reply via email to