Skip to content

test(oop): cover the constructor_owner cases #796 left untested - #994

Merged
nahime0 merged 1 commit into
mainfrom
test/871-constructor-owner-coverage
Sep 14, 2026
Merged

test(oop): cover the constructor_owner cases #796 left untested#994
nahime0 merged 1 commit into
mainfrom
test/871-constructor-owner-coverage

Conversation

@Guikingone

Copy link
Copy Markdown
Collaborator

Closes #871.

#796 introduced types::constructor_owner — the walk that finds the class whose __construct PHP runs when a descendant of a class with a non-public constructor is instantiated — and the existing coverage exercised only the 0-argument private-ancestor success path.

Every gap the issue lists is a behaviour that is already correct on main. What was missing is the pins that keep it so, which is what this PR adds; no production code changes.

What is covered

A new tests/codegen/oop/constructor_owner.rs groups the member-visibility half, where private and protected deliberately diverge:

Test Pins
test_protected_ancestor_constructor_is_inherited_and_runs a protected ancestor constructor IS inherited: it runs through the descendant, and method_exists() is true on both classes
test_protected_ancestor_constructor_leaves_the_descendant_uninstantiable it is still not public, so isInstantiable() is false and the reflected declaring class is the ancestor
test_private_ancestor_constructor_is_not_a_member_of_the_descendant a private one is NOT inherited: method_exists() is false on the descendant, true on the declaring class — the half that makes the owner walk necessary at all
test_get_class_methods_omits_an_inherited_private_constructor get_class_methods() agrees, with an inherited public method alongside
test_a_descendants_own_public_constructor_replaces_a_private_ancestors a descendant's own public constructor replaces a private ancestor's

Two error tests in classes_traits.rs cover the direction the walk must not take — a descendant that declares its own private constructor hides an inherited public one, so new static() from the ancestor's scope and a named new Child() both name the descendant's constructor, as php-src does (Call to private HideChild::__construct() from scope HideOwner). Resolving to the ancestor would have accepted those calls, since the ancestor's constructor is public and the call site is its own scope.

The get_class_methods assertion is deliberately a contrast rather than a count of zero: the function is scope-aware, so from global scope a private constructor is omitted from its own declaring class too (php-src returns 0 for both classes when that is the only method). The inherited public method alongside it is what proves the list is populated at all.

Verification

Every fixture's output was diffed against reference PHP 8.5 and matches byte for byte. --test codegen_tests oop (810) and --test error_tests (1520) pass.

Overlap

The remaining items on the issue — omitted defaults on the owner path, a descendant replacing the constructor, and method_exists/getMethods staying false — are covered by the tests in #990 and #991, so they are not duplicated here.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KSAAWPyNBq6dP2b5puN3wr

Closes #871.

#796 introduced `types::constructor_owner` — the walk that finds the class whose
`__construct` PHP runs when a descendant of a class with a non-public
constructor is instantiated — and the existing coverage exercised only the
0-argument private-ancestor success path. The listed gaps are behaviours that
are already CORRECT on main; what was missing is the pins that keep them so.

A new `tests/codegen/oop/constructor_owner.rs` groups the member-visibility half,
where private and protected deliberately diverge:

- a PROTECTED ancestor constructor IS inherited: it runs through the descendant,
  and `method_exists()` is `true` on both classes;
- it is still not public, so the descendant is not instantiable and the reflected
  declaring class is the ancestor;
- a PRIVATE ancestor constructor is NOT inherited: `method_exists()` is `false`
  on the descendant while staying `true` on the declaring class — the half that
  makes the owner walk necessary at all;
- `get_class_methods()` agrees, with an inherited public method alongside so the
  assertion is a contrast rather than a tautology (the function is scope-aware,
  so a private constructor is omitted from its own declaring class too);
- a descendant's own PUBLIC constructor replaces a private ancestor's.

Two error tests cover the hiding direction, which the walk must NOT take: a
descendant that declares its own PRIVATE constructor hides an inherited public
one, so `new static()` from the ancestor's scope and a named `new Child()` both
name the DESCENDANT's constructor, exactly as php-src does
(`Call to private HideChild::__construct() from scope HideOwner`).

Every fixture's output was diffed against reference PHP 8.5 and matches.

The remaining items on the issue — omitted defaults on the owner path, a
descendant replacing the constructor, and `method_exists`/`getMethods` staying
false — are covered by the tests in PRs #990 and #991.

Claude-Session: https://claude.ai/code/session_01KSAAWPyNBq6dP2b5puN3wr
@github-actions github-actions Bot added area:triage No primary component could be inferred from changed paths. size:s Small pull request. type:test Changes tests or test infrastructure only. labels Sep 13, 2026
@greptile-apps

greptile-apps Bot commented Sep 13, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds regression coverage for PHP constructor ownership and visibility behavior without changing production code.

  • Registers a focused constructor-owner codegen test module.
  • Covers inherited protected constructors, non-inherited private constructors, reflection and member-query behavior, and descendant constructor replacement.
  • Adds error tests confirming that a descendant’s private constructor hides an inherited public constructor for both late-static and named instantiation.

Confidence Score: 5/5

The PR appears safe to merge because it only adds coherent regression tests and no outstanding issue was identified.

The changes since the previous review introduce no additional modifications, and the current test additions are properly registered, documented, and consistent with the repository’s native compatibility-test structure.

Important Files Changed

Filename Overview
tests/codegen/oop.rs Registers the new constructor-owner codegen test module.
tests/codegen/oop/constructor_owner.rs Adds focused end-to-end tests for private and protected constructor ownership, inheritance, reflection, and replacement semantics.
tests/error_tests/classes_traits.rs Adds compile-error coverage for descendant private constructors hiding inherited public constructors.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  PHP[PHP constructor fixture] --> Compile[Compile and type-check]
  Compile --> Execute[Run generated program]
  Execute --> Assert[Compare output or expected error]
Loading

Reviews (2): Last reviewed commit: "test(oop): cover the constructor_owner c..." | Re-trigger Greptile

@Guikingone Guikingone self-assigned this Sep 13, 2026
@Guikingone
Guikingone requested a review from nahime0 September 13, 2026 18:45
@Guikingone
Guikingone force-pushed the test/871-constructor-owner-coverage branch from 2006987 to f4d10b3 Compare September 13, 2026 19:39

@nahime0 nahime0 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only tests, merge and forget

@nahime0
nahime0 merged commit 60f8d20 into main Sep 14, 2026
253 of 255 checks passed
@nahime0
nahime0 deleted the test/871-constructor-owner-coverage branch September 14, 2026 16:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:triage No primary component could be inferred from changed paths. size:s Small pull request. type:test Changes tests or test infrastructure only.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tests missing for constructor_owner: method_exists, hiding, omitted defaults

2 participants