-
Couldn't load subscription status.
- Fork 8k
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
| 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_closureinreflection_type_factoryand storece. Set it tocalled_scopefor MAY_BE_STATIC, andfptr->common.scopeotherwise - Then here, just use
intern->cein 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
| 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, andstaticare problematic in that those types would usually be resolved at run time.However, in most cases we can resolve at compile time
selfandparent, the exceptions being traits and unbound closures.staticis 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.