Add ZVAL_CHAR/RETVAL_CHAR/RETURN_CHAR as a shortcut for using
ZVAL_INTERNED_STRING and ZSTR_CHAR.
Add zend_string_init_fast() as a helper for the empty string /
one char interned string / zend_string_init() pattern.
Also add corresponding ZVAL_STRINGL_FAST etc macros.
Closes GH-5684.
Instead of looping, use straight-line code with the following
layout:
1. Try to apply the base operation on the dereferenced operands.
2. Try overloaded object operations.
3. Try to convert operands to number, else error out.
4. Apply the base operation on the converted operands.
This makes the code easier to reason about and fixes some edge-case
bugs:
1. We should only try invoking operator overloading once prior to
type conversion. Previously it was invoked both before and after
type conversion.
2. We should not modify any values if an exception is thrown.
Previously we sometimes modified the LHS of a compound assignment
operator.
3. If conversion of the first operand fails, we no longer try to
convert the second operand. I think the previous behavior here
was fine as well, but this still seems a more typical.
This will also make some followup changes I have in mind simpler.
Avoid subtle differences in behavior depending on whether the
handler is absent or returns FAILURE.
If you previously set cast_object to NULL, create a handler that
always returns FAILURE instead.
Make cast_object return FAILURE for casts to int/float, rather than
throwing a notice and returning SUCCESS. Instead move the emission
of the notice to the code invoking cast_object. This will allow us
to customize the behavior per call-site.
This change is written to be NFC, and the code in
zend_std_compare_objects() should illustrate the current behavior
doesn't make a lot of sense.
Split out the simple equality check into an inline function --
this is one of the common cases.
Replace instanceof_function_ex with zend_class_implements_interface.
There are a few more places where it may be used.
Parent interfaces are copied into the interface list during
inheritance, so there's no need to perform a recursive check.
Only exception are instanceof checks performed during inheritance
itself. However, we already have unlinked_instanceof for this
purpose, it just needs to be taught to handle this case.
Closes GH-4857.
instanceof_class does not need to check for a NULL pointer in the
first iteration -- passing NULL to this function is illegal.
instanceof_interface does not need to use instanceof_class(), it
only has to check whether the CEs match exactly. There is no way
for an interface to appear inside "parent", it will always be in
"interfaces" only.
The instanceof_interface_only() function was dead code (always
returned zero).
Clarify that the last parameter indicates whether the passed CE
is interface or class and rewrite the code in terms of assertions.
Previously if the "non well formed" notice was converted into an
exception we'd still end up executing the function.
Also drop the now unnecessary EG(exception) checks in the engine.
Additionally remote a bogus exception in zend_is_callable: It
should only be writing to error, but not directly throwing.
The strcoll function is defined in the C89 standard and should be
on today's systems always available via the <string.h> header.
https://port70.net/~nsz/c/c89/c89-draft.html#4.11.4.3
- Remove also SKIPIF strcoll check in test
Keep track of delayed variance obligations and check them after
linking a class is otherwise finished. Obligations may either be
unresolved method compatibility (because the necessecary classes
aren't available yet) or open parent/interface dependencies. The
latter occur because we allow the use of not fully linked classes
as parents/interfaces now.
An important aspect of the implementation is we do not require
classes involved in variance checks to be fully linked in order for
the class to be fully linked. Because the involved types do have to
exist in the class table (as partially linked classes) and we do
check these for correct variance, we have the guarantee that either
those classes will successfully link lateron or generate an error,
but there is no way to actually use them until that point and as
such no possibility of violating the variance contract. This is
important because it ensures that a class declaration always either
errors or will produce an immediately usable class afterwards --
there are no cases where the finalization of the class declaration
has to be delayed until a later time, as earlier variants of this
patch did.
Because variance checks deal with classes in various stages of
linking, we need to use a special instanceof implementation that
supports this, and also introduce finer-grained flags that tell us
which parts have been linked already and which haven't.
Class autoloading for variance checks is delayed into a separate
stage after the class is otherwise linked and before delayed
variance obligations are processed. This separation is needed to
handle cases like A extends B extends C, where B is the autoload
root, but C is required to check variance. This could end up
loading C while the class structure of B is in an inconsistent
state.