-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Resolve relative class type at compile time #11460
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
eda873f
to
a9b9158
Compare
a9b9158
to
b4a63c5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a shit-ton of tests 😄 I think we should condense them somehow.
ext/reflection/php_reflection.c
Outdated
bool allows_null = ZEND_TYPE_PURE_MASK(param->type) & MAY_BE_NULL; | ||
zend_type resolved_type; | ||
/* For static resolved name is the name of the class */ | ||
if (ZEND_TYPE_PURE_MASK(param->type) & MAY_BE_STATIC) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm confused, how can we know static
without knowing the context? (i.e. in what object instance it is called)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One cannot create a "proper" ReflectionType without getting it either from a ReflectionParameter, ReflectionProperty, or a ReflectionFunction for the return type.
Part of the change is to propagate forward the object_ce from those prior Reflection objects.
Zend/zend_compile.c
Outdated
@@ -6495,7 +6532,34 @@ static void zend_is_type_list_redundant_by_single_type(zend_type_list *type_list | |||
} | |||
if (zend_string_equals_ci(ZEND_TYPE_NAME(type_list->types[i]), ZEND_TYPE_NAME(type))) { | |||
zend_string *single_type_str = zend_type_to_string(type); | |||
zend_error_noreturn(E_COMPILE_ERROR, "Duplicate type %s is redundant", ZSTR_VAL(single_type_str)); | |||
if ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this special handling for this edge-case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, because otherwise you would get an error message like Duplicate type T is redundant
when self
or parent
gets resolved to T
and it makes for some confusing stuff, or I'm misunderstanding the question.
fn->common.arg_info = new_arg_infos + has_return_type; | ||
has_resolved_type = true; | ||
} | ||
new_arg_infos[i].type = resolved_type; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't the old type be released? I think this might only be reproducible for eval'd code where the type may contain non-interned strings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe? Haven't thought about something like this as I would usually expect to be allocated on an arena. And releasing the type info for the traits doesn't make a lot of sense as it still needs to keep the unresolved types for itself.
c9d830a
to
1910966
Compare
Yes, it is a lot of tests as there are a lot of weird cases I stumbled into what I thought would be relatively easy :| Not really sure why we need to condense them as I tried to make them all be their own thing somewhat, and even then I've been missing cases (like using eval, or using a trait in two completely unrelated classes). |
1910966
to
b62f42a
Compare
Resolving If we don't do compile time resolution, we could save some |
The main motivation is not saving time at runtime, but to expose co/contra-variant APIs in Reflection to reduce the need in userland to implement the variance logic (at least for most cases as traits and unbound closures are still impossible) So no, I didn't benchmark. However, we could change the error messages to show the resolved types instead of going back to self/parent at the downside of it being a minor BC break. |
b62f42a
to
d5a51e6
Compare
577eda4
to
616f6e7
Compare
61b2568
to
eafac08
Compare
@@ -0,0 +1,19 @@ | |||
--TEST-- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a typo in the file name :)
...ests/type_declarations/union_types/redundant_types/duplicate_relative_class_parent_type.phpt
Show resolved
Hide resolved
ext/reflection/php_reflection.c
Outdated
zend_class_entry *called_scope = NULL; | ||
zend_object *this_obj = NULL; | ||
|
||
Z_OBJ_HANDLER(intern->obj, get_closure)(Z_OBJ(intern->obj), &called_scope, &fptr, &this_obj, /* check_only */ true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that you could avoid calling ->get_closure
twice here and in reflection_type_factory
:
- Call
->get_closure
inreflection_type_factory
and storece
. Set it tocalled_scope
for MAY_BE_STATIC, andfptr->common.scope
otherwise - Then here, just use
intern->ce
in all cases.
An additional benefit is that it may be possible to avoid holding the closure in ->obj
. For the condition above, you could add a flag in type_reference
to indicate this is in a closure context.
eafac08
to
e77225e
Compare
ext/reflection/php_reflection.c
Outdated
@@ -1443,7 +1489,8 @@ static void reflection_method_factory(zend_class_entry *ce, zend_function *metho | |||
intern->ref_type = REF_TYPE_FUNCTION; | |||
intern->ce = ce; | |||
if (closure_object) { | |||
ZVAL_OBJ_COPY(&intern->obj, Z_OBJ_P(closure_object)); | |||
intern->ce = zend_ce_closure; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: This looks wrong, and I need to add a test with a Closure bound within a method.
eea1779
to
478464f
Compare
This is only possible if the type is resolvable.
Also throw a compile error if trying to use a trait using the parent type in a class not having a parent
stopping for today
Seems like a pointer not allocated via ZMM gets into the arena????
478464f
to
8fc28e9
Compare
The motivation for this is to potentially add methods to ReflectionType which can check if it is co/contra-variant to another ReflectionType, however
self
,parent
, andstatic
are problematic in that those types would usually be resolved at run time.However, in most cases we can resolve at compile time
self
andparent
, the exceptions being traits and unbound closures.static
is resolvable if it comes from an instance or a class, as it will resolve to that name, leaving interfaces to be an issue.Commits are kinda a mess as it's somewhat W.I.P. as I might still need to tweak the redundancy check for DNF types.