Skip to content

Create TODO declarations for unresolved parent scopes#529

Open
Morriar wants to merge 3 commits intomainfrom
at-todo-decl
Open

Create TODO declarations for unresolved parent scopes#529
Morriar wants to merge 3 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

Right now, if we can't resolve Foo, we won't create a definition for Bar and will end up creating bar() under object: Object#bar().

With this PR, we try to resolve everything then, for the remaining definition we couldn't resolve, we enter in a mode where we create TODO declaration for the missing ones and try to resolve what it unblocks.

So for our example the logic would look like this:

1. Normal process mode
  1.1. Try to resolve `Bar` -> Unresolved parent scope `Foo`
  1.2. Re-enque `Bar`
  1.3. Continue until the queue is empty or we can't make progress anymore

2. We still have definitions in the queue but couldn't make progress => start Todo process mode
  2.1. Try to resolve `Bar`
  2.2. Create `Foo` as a Todo declaration under `Object`
  2.3. Create `Foo::Bar` under `Foo`
  2.4. Continue until the queue is empty or we can't make progress anymore

3. Process the remaining definitions (methods, etc.)
  3.1. Create `bar()` under `Bar`

Instead of passing it around.

Signed-off-by: Alexandre Terrasa <alexandre.terrasa@shopify.com>
Used to represent namespaces we couldn't resolve but are used as parent
scope of another namespace.

Consider this:

```rb
class Foo::Bar
  def bar; end
end
```

While we can't resolve `Foo`, we want to create `def bar` in the right
namespace: `Foo::Bar`.

Signed-off-by: Alexandre Terrasa <alexandre.terrasa@shopify.com>
Signed-off-by: Alexandre Terrasa <alexandre.terrasa@shopify.com>
@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
.as_namespace()
.unwrap()
.get(nesting_declaration_id)?
.as_namespace()?
Copy link
Member

Choose a reason for hiding this comment

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

Why does this need to change?

// Once we've processed the queue and create all we could, what's remaining is depending on other unresolved units.
// We'll create TODO declarations for these and process the queue again to resolve what we can.
self.create_todo_declarations = true;
self.process_queue();
Copy link
Member

@vinistock vinistock Jan 28, 2026

Choose a reason for hiding this comment

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

Instead of looping through the queue twice, can we not incorporate Todo in the regular processing?

If we eagerly create unresolved definitions as Todo, while still enqueuing a retry, we could do everything in a single loop.

Maybe in combination with #505

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