Skip to content

Create Todo declarations for multi-level compact namespaces#656

Open
st0012 wants to merge 1 commit intomainfrom
fix-multi-level-todo-chain
Open

Create Todo declarations for multi-level compact namespaces#656
st0012 wants to merge 1 commit intomainfrom
fix-multi-level-todo-chain

Conversation

@st0012
Copy link
Member

@st0012 st0012 commented Mar 11, 2026

Problem

class A::B::C where A is unknown panics when the class body contains def self.foo with instance variables:

thread panicked at rubydex/src/resolution.rs:386:42:
SelfReceiver definition should have a declaration

The panic occurs in handle_remaining_definitions because C's definition never gets a declaration — the resolution loop retries indefinitely and then gives up.

Fixes #663

Root cause

The Todo mechanism from #529 only handles one level of unknown parent in compact notation. For class Foo::Bar where Foo is unknown, resolve_constant_internal(Foo) returns Unresolved(None), which triggers Todo creation for Foo in name_owner_id.

For multi-level paths like class A::B::C, the flow differs:

  1. name_owner_id(C) calls resolve_constant_internal(B)
  2. B has ParentScope::Attached(A) — checks if A's name is resolved
  3. A is unresolved → returns Retry(None) (line 1189)
  4. name_owner_id passes Retry(None) through unchanged — never reaches the Todo creation branch
  5. The unit is re-enqueued, but nothing ever resolves A, so the loop stalls

The Unresolved(None) branch (which creates Todos) is only reached when resolve_constant_internal goes through run_resolution for a bare name. Intermediate names with ParentScope::Attached short-circuit at the unresolved parent check.

Fix

In name_owner_id, merge Retry(None) with Unresolved(None) to eagerly create Todos for the entire parent chain:

// Before
Outcome::Retry(id) => Outcome::Retry(id),

// After
Outcome::Retry(Some(id)) => Outcome::Retry(Some(id)),
Outcome::Retry(None) | Outcome::Unresolved(None) => {
    // Create Todo for parent, recursively resolving the chain...
}

The recursive name_owner_id(parent_scope) call at line 1089 naturally handles arbitrary depth — each level either resolves to an existing declaration or creates a Todo. If real definitions appear later, the existing promotion mechanism upgrades Todos in place.

Retry(Some(id)) (pending ancestor linearization) is still passed through unchanged — this only affects Retry(None), which in the ParentScope::Attached code path exclusively means "the parent's parent name is unresolved."

@st0012 st0012 force-pushed the fix-multi-level-todo-chain branch from 127a76d to e0f5147 Compare March 11, 2026 21:08
Previously, `class A::B::C` where A is unknown would only create a Todo
for A (the first unresolvable parent), leaving B and C stuck in the retry
loop indefinitely. This caused a panic when the class contained `def self.foo`
with instance variables, because the SelfReceiver lookup expected C's definition
to have a declaration.

The root cause was in `name_owner_id`: `resolve_constant_internal(B)` returned
`Retry(None)` (because A's name was unresolved), which was passed through
unchanged. The `Unresolved(None)` branch that creates Todos was never reached
for intermediate names in the constant path.

Fix: merge `Retry(None)` with `Unresolved(None)` in `name_owner_id`. The
recursive `name_owner_id(parent_scope)` call naturally walks the entire chain,
creating Todos at each level. If real definitions appear later, the existing
promotion mechanism upgrades Todos in place.
@st0012 st0012 force-pushed the fix-multi-level-todo-chain branch from e0f5147 to a1d6f41 Compare March 11, 2026 21:15
@st0012
Copy link
Member Author

st0012 commented Mar 11, 2026

@Morriar There are different ways to resolve the panic mentioned in the description. Looking at #529, I don't think 1-level-only todo declaration creation is intentional, so I opened this PR. If that's the intend, I think we should document it somewhere (architecture.md?), and I have another way to address the panic.

@st0012 st0012 self-assigned this Mar 11, 2026
@st0012 st0012 marked this pull request as ready for review March 13, 2026 16:08
@st0012 st0012 requested a review from a team as a code owner March 13, 2026 16:08
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.

MCP panic: SelfReceiver definition should have a declaration

1 participant