Skip to content

fix: call mark_as_used() for classes referenced only in instanceof (#68)#1561

Open
KorsarOfficial wants to merge 1 commit intoVKCOM:masterfrom
KorsarOfficial:bugfix/issue-68-instanceof-unused-class
Open

fix: call mark_as_used() for classes referenced only in instanceof (#68)#1561
KorsarOfficial wants to merge 1 commit intoVKCOM:masterfrom
KorsarOfficial:bugfix/issue-68-instanceof-unused-class

Conversation

@KorsarOfficial
Copy link

Problem

When a class C appears only in an instanceof expression and is never instantiated or used as a value, the code-gen pass crashes: it emits an #include for C's header, but the header was never generated because mark_as_used() was never called for C.

Formal Analysis

Define the class dependency system:

  • Let C = {c₁, c₂, …, cₙ} — set of all classes
  • U(c) — predicate: class is marked as "used"
  • H(c) — predicate: header file was generated
  • R(c) — predicate: class is referenced in code-gen output

Code-gen invariant: ∀c ∈ C : R(c) ⟹ H(c)
Header rule: H(c) ⟺ U(c)
Required invariant: ∀c ∈ C : R(c) ⟹ U(c)

The existing mark_as_used() calls cover instantiation, catch, type hints, and value references — but not instanceof. When instanceof is the only reference, U(c) = false while R(c) = true, violating the invariant.

Fix

Add mark_as_used() for op_instanceof in CalcFuncDepPass::on_enter_vertex, mirroring the identical pattern for op_catch.

Correctness: U'(c) = U(c) ∨ instanceof_ref(c)∀c : R(c) ⟹ U'(c) ⟹ H(c). ∎

Complexity: O(1) per instanceof vertex — negligible overhead.

Tests

  • tests/phpt/interfaces/135_instanceof_unused_class.php — basic regression
  • tests/phpt/interfaces/136_instanceof_only_in_condition.php — instanceof only in conditional branch

Technical Report

📄 Full report with mathematical formalization (PDF)

Closes #68

…KCOM#68)

When a class appeared only in an `instanceof` expression and was never
instantiated anywhere else, the code-gen pass tried to include its
generated header but the header had never been written, causing a crash.

The fix mirrors the identical pattern already applied to `op_catch`:
call `mark_as_used()` so the class header gets generated even when the
class is never used as a value.

Also adds two regression tests:
- tests/phpt/interfaces/135_instanceof_unused_class.php
- tests/phpt/interfaces/136_instanceof_only_in_condition.php
@Danil42Russia
Copy link
Contributor

Danil42Russia commented Mar 18, 2026

Why open a new thread when there’s already #1557? Apart from the fact that you’ve removed the use of Claude

@KorsarOfficial
Copy link
Author

Hey, fair point. I've been experimenting with Claude as a coding assistant recently — it ended up as a co-author in the commits by default, and I didn't notice until after the PRs were already up. Didn't want that showing up in upstream history, so I cleaned it up and reopened. Sorry for the noise.

The code changes are the same, just without the AI attribution in the commit metadata.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Compilation failure for unused class used in instanceof expr

2 participants