Skip to content

fix(checker): an inherited constructor's arity error names its declaring class - #993

Merged
nahime0 merged 2 commits into
mainfrom
fix/870-inherited-ctor-arity-owner
Sep 14, 2026
Merged

fix(checker): an inherited constructor's arity error names its declaring class#993
nahime0 merged 2 commits into
mainfrom
fix/870-inherited-ctor-arity-owner

Conversation

@Guikingone

Copy link
Copy Markdown
Collaborator

Closes #870.

What was wrong

A private constructor is not inherited, so new Child() on a descendant of a class that declares one runs the ancestor's constructor. php-src names that ancestor in the diagnostic:

ArgumentCountError: Too few arguments to function Owner::__construct(), 0 passed … and exactly 1 expected

#796 made elephc's visibility error say so (Cannot access private constructor: Owner::__construct). The arity error still read:

error[4:56]: Constructor 'Child::__construct' expects 1 arguments, got 0

— pointing at a class whose source has no constructor to look at.

Fix

infer_new_object_type already resolves the declaring class for the visibility check. It now computes that label once and uses it for the arity and named-argument diagnostics too.

For a class that declares its own constructor the declaring class and the instantiated class coincide, so every other message is unchanged. The reflection-owner constructor path (ReflectionClass and friends) is untouched — those are builtins that always declare their own.

Tests

The issue notes wrong-arg-count on the resolved owner constructor was untested. Six tests in tests/error_tests/classes_traits.rs, next to the existing visibility ones:

  • too few and too many arguments both naming Owner
  • an unknown named argument, which reaches the same signature through normalize_named_call_args
  • a grandparent-declared constructor, mirroring the visibility half's existing chain test
  • unchanged controls: a class with its own constructor, and an inherited public one

--test error_tests (1524) and --test codegen_tests oop (805) pass; cargo build is warning-free.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KSAAWPyNBq6dP2b5puN3wr

…ing class

Closes #870.

A private constructor is not inherited, so `new Child()` on a descendant of a
class that declares one runs the ANCESTOR's constructor. php-src names that
ancestor in the diagnostic — `Too few arguments to function Owner::__construct()`
— and #796 made elephc's VISIBILITY error say so. The arity error still read
`Constructor 'Child::__construct' expects 1 arguments, got 0`, pointing at a
class whose source has no constructor to look at.

`infer_new_object_type` already resolves the declaring class for the visibility
check; it now computes that label once and uses it for the arity and
named-argument diagnostics too. For a class that declares its own constructor
the declaring class and the instantiated class coincide, so every other message
is unchanged.

Tests cover the two arity directions, an unknown named argument, a
grandparent-declared constructor (mirroring the visibility half's existing
chain test), and the two unchanged shapes: a class with its own constructor,
and an inherited PUBLIC one. Wrong-arg-count on the resolved owner constructor
was untested before.

Claude-Session: https://claude.ai/code/session_01KSAAWPyNBq6dP2b5puN3wr
@github-actions github-actions Bot added area:types Touches type checking, inference, or compatibility. size:xs Very small pull request. type:fix Corrects broken or incompatible behavior. labels Sep 13, 2026
@greptile-apps

greptile-apps Bot commented Sep 13, 2026

Copy link
Copy Markdown

Greptile Summary

Updates constructor diagnostics to identify the class that declares an inherited constructor rather than the class being instantiated.

  • Reuses declaring-class metadata for arity and named-argument diagnostics.
  • Adds regression coverage for private, public, and grandparent-inherited constructors.
  • Preserves diagnostics for classes that declare their own constructors.

Confidence Score: 5/5

The PR appears safe to merge with no outstanding findings.

The earlier documentation concern was corrected and its thread was resolved; no subsequent changes introduced new issues, and the current implementation consistently labels inherited constructor diagnostics with the declaring class.

Important Files Changed

Filename Overview
src/types/checker/inference/objects/constructors.rs Derives a shared constructor label from existing declaring-class metadata and uses it consistently across visibility, arity, and named-argument diagnostics.
tests/error_tests/classes_traits.rs Adds focused regression tests covering inherited constructor diagnostics and unchanged own-constructor behavior.

Reviews (3): Last reviewed commit: "docs(checker): say that the name moves f..." | Re-trigger Greptile

Comment thread src/types/checker/inference/objects/constructors.rs Outdated
Review follow-up on #993.

The comment claimed "every other diagnostic is unchanged", which understates
the change: an inherited PUBLIC or PROTECTED constructor IS in the descendant's
own method map, so the owner walk stops at the descendant — but
`method_declaring_classes` still points at the ancestor that wrote it, and the
label therefore moves for those too.

Measured on `class Base { public function __construct(int $n) {} } class Sub
extends Base {} new Sub();`: before the fix `Constructor 'Sub::__construct'`,
after it `Constructor 'Base::__construct'`. php-src names `Base` as well, so the
new message is the correct one — but a future maintainer reading the old comment
would not have expected the public path to move at all.

Only a class that declares its OWN constructor is unchanged, because there the
two names are the same class. The public-inheritance test's docblock is
corrected the same way: it was labelled "already correct and stays so", when it
is in fact one of the messages this fix changes.

Claude-Session: https://claude.ai/code/session_01KSAAWPyNBq6dP2b5puN3wr
Guikingone added a commit that referenced this pull request Sep 13, 2026
Review follow-up on #993.

The comment claimed "every other diagnostic is unchanged", which understates
the change: an inherited PUBLIC or PROTECTED constructor IS in the descendant's
own method map, so the owner walk stops at the descendant — but
`method_declaring_classes` still points at the ancestor that wrote it, and the
label therefore moves for those too.

Measured on `class Base { public function __construct(int $n) {} } class Sub
extends Base {} new Sub();`: before the fix `Constructor 'Sub::__construct'`,
after it `Constructor 'Base::__construct'`. php-src names `Base` as well, so the
new message is the correct one — but a future maintainer reading the old comment
would not have expected the public path to move at all.

Only a class that declares its OWN constructor is unchanged, because there the
two names are the same class. The public-inheritance test's docblock is
corrected the same way: it was labelled "already correct and stays so", when it
is in fact one of the messages this fix changes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KSAAWPyNBq6dP2b5puN3wr
@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 fix/870-inherited-ctor-arity-owner branch from 691704d to 99249af 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.

lgtm

@nahime0
nahime0 merged commit b32450c into main Sep 14, 2026
148 checks passed
@nahime0
nahime0 deleted the fix/870-inherited-ctor-arity-owner branch September 14, 2026 16:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:types Touches type checking, inference, or compatibility. size:xs Very small pull request. type:fix Corrects broken or incompatible behavior.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Arity error for an inherited private constructor names Child::__construct instead of Owner

2 participants