|
|
|
@ -1602,10 +1602,7 @@ CODE; |
|
|
|
$list = []; |
|
|
|
$list = []; |
|
|
|
if ($func->method) { |
|
|
|
if ($func->method) { |
|
|
|
$list[] = Type::OBJECT . ' &this_'; |
|
|
|
$list[] = Type::OBJECT . ' &this_'; |
|
|
|
// A trait method with `parent::` calls receives an implicit |
|
|
|
if ($func->hasTraitParentCeParameter) { |
|
|
|
// `trait_parent_ce` parameter right after `this_`. The definition |
|
|
|
|
|
|
|
// adds it (see parseFunction); the declaration must match. |
|
|
|
|
|
|
|
if ($func->traitParentCe) { |
|
|
|
|
|
|
|
$list[] = 'zend_class_entry *trait_parent_ce'; |
|
|
|
$list[] = 'zend_class_entry *trait_parent_ce'; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -3465,16 +3462,15 @@ CODE; |
|
|
|
$cppReturnType = $multiReturn |
|
|
|
$cppReturnType = $multiReturn |
|
|
|
? $this->functionDef->getMultiReturnCppType() |
|
|
|
? $this->functionDef->getMultiReturnCppType() |
|
|
|
: ($this->functionDef->returnsByRef ? Type::REF : $this->getReturnType()); |
|
|
|
: ($this->functionDef->returnsByRef ? Type::REF : $this->getReturnType()); |
|
|
|
|
|
|
|
$this->functionDef->hasTraitParentCeParameter = |
|
|
|
|
|
|
|
$this->classDef?->trait !== null && (bool) $this->methodDef?->parentMethodCalls; |
|
|
|
$nativeName = self::PREFIX . $name; |
|
|
|
$nativeName = self::PREFIX . $name; |
|
|
|
$functionAttribute = $this->getFunctionOptimizationAttribute($this->functionDef); |
|
|
|
$functionAttribute = $this->getFunctionOptimizationAttribute($this->functionDef); |
|
|
|
$functionDeclCode = $functionAttribute . $cppReturnType . ' ' . ($multiReturn ? $this->getMultiReturnImplName($name) : $nativeName) . '('; |
|
|
|
$functionDeclCode = $functionAttribute . $cppReturnType . ' ' . ($multiReturn ? $this->getMultiReturnImplName($name) : $nativeName) . '('; |
|
|
|
if ($this->class) { |
|
|
|
if ($this->class) { |
|
|
|
$functionDeclCode .= Type::OBJECT . ' &this_'; |
|
|
|
$functionDeclCode .= Type::OBJECT . ' &this_'; |
|
|
|
if ($this->classDef?->trait !== null && $this->methodDef?->parentMethodCalls) { |
|
|
|
if ($this->functionDef->hasTraitParentCeParameter) { |
|
|
|
$functionDeclCode .= ', zend_class_entry *trait_parent_ce'; |
|
|
|
$functionDeclCode .= ', zend_class_entry *trait_parent_ce'; |
|
|
|
// Record the implicit parameter so the shared `func_decl.h` |
|
|
|
|
|
|
|
// declaration (genFunctionDeclaration) emits the same signature. |
|
|
|
|
|
|
|
$this->functionDef->traitParentCe = true; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
if ($this->functionDef->params) { |
|
|
|
if ($this->functionDef->params) { |
|
|
|
$functionDeclCode .= ', '; |
|
|
|
$functionDeclCode .= ', '; |
|
|
|
@ -4471,6 +4467,10 @@ CODE; |
|
|
|
string $traitMethodName, |
|
|
|
string $traitMethodName, |
|
|
|
string $classMethodName |
|
|
|
string $classMethodName |
|
|
|
): string { |
|
|
|
): string { |
|
|
|
|
|
|
|
// A trait may be composed by multiple classes and aliases. Each wrapper |
|
|
|
|
|
|
|
// needs independent signature metadata. |
|
|
|
|
|
|
|
$methodDef = clone $methodDef; |
|
|
|
|
|
|
|
|
|
|
|
// A trait method's `self`/`static`/`parent` return and parameter types |
|
|
|
// A trait method's `self`/`static`/`parent` return and parameter types |
|
|
|
// refer to the class that uses the trait, not the trait itself. Re-resolve |
|
|
|
// refer to the class that uses the trait, not the trait itself. Re-resolve |
|
|
|
// them to the consuming class so signature-compatibility checks (against |
|
|
|
// them to the consuming class so signature-compatibility checks (against |
|
|
|
@ -4479,13 +4479,9 @@ CODE; |
|
|
|
// function untouched. |
|
|
|
// function untouched. |
|
|
|
$this->reresolveTraitLateBoundTypes($classDef, $methodDef); |
|
|
|
$this->reresolveTraitLateBoundTypes($classDef, $methodDef); |
|
|
|
|
|
|
|
|
|
|
|
// The wrapper is a method of the *composing* class, not a trait method, so |
|
|
|
// The wrapper computes the composing class's parent scope and passes it |
|
|
|
// it must not receive the implicit `trait_parent_ce` parameter (it computes |
|
|
|
// to the trait function; it does not expose that scope in its signature. |
|
|
|
// the parent class entry itself when forwarding to the trait function). The |
|
|
|
$methodDef->functionDef->hasTraitParentCeParameter = false; |
|
|
|
// cloned FunctionDef inherited `traitParentCe` from the trait's FunctionDef; |
|
|
|
|
|
|
|
// clear it so the shared `func_decl.h` declaration matches the wrapper's |
|
|
|
|
|
|
|
// own (2-parameter) definition. |
|
|
|
|
|
|
|
$methodDef->functionDef->traitParentCe = false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Validate `parent::` calls emitted from this trait method against the |
|
|
|
// Validate `parent::` calls emitted from this trait method against the |
|
|
|
// parent of the class that is composing the trait. The trait itself has |
|
|
|
// parent of the class that is composing the trait. The trait itself has |
|
|
|
@ -4558,10 +4554,7 @@ CODE; |
|
|
|
{ |
|
|
|
{ |
|
|
|
$fn = $methodDef->functionDef; |
|
|
|
$fn = $methodDef->functionDef; |
|
|
|
// Always produce a distinct FunctionDef for the composing-class wrapper. |
|
|
|
// Always produce a distinct FunctionDef for the composing-class wrapper. |
|
|
|
// The wrapper is a separate method (different name, and no implicit |
|
|
|
// The wrapper has a separate native signature from the trait function. |
|
|
|
// `trait_parent_ce` parameter) from the trait's own function, so it must |
|
|
|
|
|
|
|
// not share the trait's FunctionDef object — mutating one (e.g. clearing |
|
|
|
|
|
|
|
// `traitParentCe`) would otherwise leak into the trait's declaration. |
|
|
|
|
|
|
|
$newFn = clone $fn; |
|
|
|
$newFn = clone $fn; |
|
|
|
if ($fn->returnTypeKeyword !== '') { |
|
|
|
if ($fn->returnTypeKeyword !== '') { |
|
|
|
$resolved = $this->resolveLateBoundClass($usingClassDef, $fn->returnTypeKeyword); |
|
|
|
$resolved = $this->resolveLateBoundClass($usingClassDef, $fn->returnTypeKeyword); |
|
|
|
|