Stas,

>>> -- Can the code generated for a strict type hint can somehow be optimized
> significantly better than the code generated for a dynamic/coercive type
> hint.
>> And me, who wrote an AOT compiler that does **exactly** this, claim
>
> Sorry, did exactly what? Here a bit more explanation would help.

Optimized statically typed PHP functions. Or more specifically
function calls inside of compiled code are treated strictly (so trying
to pass a float to an int typed function would error at compile time).
The outer function call (from non-compiled PHP) is parsed using ZPP
rules, but once it's inside it's strict.

https://github.com/google/recki-ct/blob/master/doc/0_introduction.md
https://github.com/google/recki-ct/blob/master/doc/2_basic_operation.md

>> However, since test_strict() is compiled, there's no reason to
>> dispatch back up to PHP functions for strict_foo(). In fact, that
>> would be exceedingly slow. So instead, we'd compile strict_foo() as a
>> C function, and do a native function call to it. Never having to check
>> types because they are passed on the C stack.
>
> Doesn't that assume strict_foo() is always called with the right type of
> arguments? What exactly ensures that it does in fact happen? Shouldn't
> you have the type check _somewhere_ to be able to claim this happens?
> test_foo() doesn't do any checks, so what ensures $x is of the right
> type for C? And if the check is there, how is it better?

Yes it does check the types, but at compile time. My AOT compiler
backend has no concept of a "mixed" or ZVAL type. All types are
determined at compile time, and in the very few cases it can't it will
error. The type inference engine attempts to determine specifically
using all available information (prior context, current context,
future context) to determine what the type is.

It does also detect type changes (via assignment) and is able to
correctly generate code based on that as well.

>> And note that this can only work with strict types since you can do
>> the necessary type inference and reconstruction (both forward from a
>> function call, and backwards before it).
>
> I don't get the backwards part - I think you claimed it last time we
> discussed it but I haven't seen your answer explaining why it's OK to
> just ignore cases when the variable is of the wrong type. Right now, it
> looks like you claim that if somebody has a call strict_foo($x) and
> strict_foo() accepts integers, that magically makes $x integer and you
> can generate code everywhere (not only inside strict_foo but outside)
> assuming $x is integer without actually needing a check. I don't see how
> this can work.

Ok, let's take another example:

<?php declare(strict_types=1);
function foo(int $int): int {
    return $int + 1;
}

function bar(int $something): int {
    $x = $something / 2;
    return foo($x);
}

^^ In that case, without strict types, you'd have to generate code for
both integer and float paths. With strict types, this code is invalid.

You can tell because you know the function foo expects an integer. So
you can infer that $x will have to have the type integer due to the
future requirement. Which means the expression "$something / 2" must
also be an integer. We know that's not the case, so we can raise an
error here.

At that point the developer has the choice to explicitly cast or put
in a floor() or one of a number of options.

The function "bar" itself didn't give us that information. We needed
to use the type information from foo() to infer the type of $x prior
to foo()'s call. Or more specifically, we inferred the only stable
type that it could be. Which let us determine that $x's assignment was
where the error was (since it wasn't a stable assignment).

Without strict typing this code is always stable, but you still need
to generate full type assertions in a compiled version of foo() and
use ZVALs for $x, hence reducing the effect of the optimization
significantly.

Anthony

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to