Skip to content

Create TODO declarations for unresolved parent scopes#529

Merged
Morriar merged 4 commits intomainfrom
at-todo-decl
Mar 5, 2026
Merged

Create TODO declarations for unresolved parent scopes#529
Morriar merged 4 commits intomainfrom
at-todo-decl

Conversation

@Morriar
Copy link
Contributor

@Morriar Morriar commented Jan 27, 2026

Consider this:

class Foo::Bar
  def bar; end
end

Without this PR, if Foo can't be resolved, Bar never gets created and bar() ends up under Object.

This PR introduces TodoDeclaration, a placeholder namespace used when a parent scope can't be resolved. Rather than running the resolution queue twice (once normally, then again in a "create Todos" mode), we create Todos eagerly in a single pass by leveraging the existing constant → namespace promotion mechanism from #505.

The logic for the example above now looks like this:

1. Try to resolve Bar -> parent scope Foo is Unresolved(None) (genuinely unknown)
2. Create Foo as a Todo declaration under Object
3. Resolve Bar under Foo, enqueue its members
4. Create bar() under Foo::Bar

If a real class Foo or module Foo definition appears later, Foo is promoted from Todo to Class/Module in place — same mechanism used to promote constants to namespaces.

Unresolved outcomes with a pending linearization (Unresolved(Some(id))) are propagated as-is rather than triggering Todo creation, so we don't create premature Todos for names that might resolve once ancestor chains are fully computed.

@Morriar Morriar requested a review from a team as a code owner January 27, 2026 20:09
@Morriar Morriar self-assigned this Jan 27, 2026
@Morriar Morriar force-pushed the at-todo-decl branch 10 times, most recently from efe1f7f to ab4b06a Compare March 4, 2026 19:14
@Morriar Morriar requested a review from vinistock March 4, 2026 19:19
@Morriar Morriar force-pushed the at-todo-decl branch 2 times, most recently from 1b010c4 to e0f2509 Compare March 4, 2026 22:16
When resolving `class Bar::Baz` inside `module Foo`, if `Bar` can't be
found, the previous code used lexical nesting to create a Todo named
`"Foo::Bar"`. This was wrong: since `Bar` has no explicit `::` prefix,
the placeholder should live at the top level as `"Bar"`, so it can be
promoted when `module Bar` is later discovered.

Fix: in the Unresolved(None) arm of name_owner_id, check whether the
failing scope has an explicit `::` prefix. If not (bare name), use
OBJECT_ID directly instead of recursing through nesting. For qualified
names like `Outer::Inner` the recursive call is still correct.

The existing Todo promotion mechanism in add_declaration handles the
rest: when `module Bar` is processed (same or next resolve_all), the
Todo at `"Bar"` is promoted and its members transferred.
@Morriar Morriar merged commit 8a1b573 into main Mar 5, 2026
33 checks passed
@Morriar Morriar deleted the at-todo-decl branch March 5, 2026 14:35
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.

2 participants