Skip to content

Fix top level constant resolution#729

Open
vinistock wants to merge 1 commit into04-06-fix_default_parent_classesfrom
04-06-fix_top_level_resolution_algorithm
Open

Fix top level constant resolution#729
vinistock wants to merge 1 commit into04-06-fix_default_parent_classesfrom
04-06-fix_top_level_resolution_algorithm

Conversation

@vinistock
Copy link
Copy Markdown
Member

@vinistock vinistock commented Apr 7, 2026

We got the constant resolution algorithm slightly wrong in terms of the top level fallback. This PR fixes it.

  1. First, there's no top level fallback when inside a class. All constants end up being available through inheritance. It looks like there's a top level fallback because not inheriting from Object is pretty uncommon, but you can see that this is the case because this crashes:
# This crashes because `Foo` doesn't have `Object` in its ancestor chain,
# which is the owner of the `String` constant
class Foo < BasicObject
  String
end

And when using constants at the top level of a script, it works because <main> is an instance of Object.

# This doesn't crash, but not because there's a top level fallback. It's simply
# because <main> is `Object`
String
  1. The fallback does exist for modules. However, it's not a simple direct member access. Ruby will actually search the ancestors of Object. For example, this works:
module Kernel
  FOO = 1
end

module Bar
  puts FOO
end

If Ruby can't find the constant in lexical scopes or ancestors of the surrounding nesting, it searches the ancestors of Object. The same exact behaviour occurs for top level references like ::FOO - even inside classes!

module Kernel
  FOO = 1
end

class Bar < BasicObject
  ::FOO # The top level reference will make Ruby search in the ancestors of Object
end

@vinistock vinistock self-assigned this Apr 7, 2026
Copy link
Copy Markdown
Member Author

vinistock commented Apr 7, 2026

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@vinistock vinistock added the bugfix A change that fixes an existing bug label Apr 7, 2026
@vinistock vinistock force-pushed the 04-06-fix_top_level_resolution_algorithm branch from 68c9bfb to d1c948d Compare April 8, 2026 12:40
@vinistock vinistock force-pushed the 04-06-fix_default_parent_classes branch from 1286e1f to 80710f3 Compare April 8, 2026 14:55
@vinistock vinistock force-pushed the 04-06-fix_top_level_resolution_algorithm branch 2 times, most recently from 3bf8916 to bb9979c Compare April 8, 2026 15:32
@vinistock vinistock marked this pull request as ready for review April 8, 2026 15:39
@vinistock vinistock requested a review from a team as a code owner April 8, 2026 15:39
Copy link
Copy Markdown
Member

@st0012 st0012 left a comment

Choose a reason for hiding this comment

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

Can you also update ruby-behaviours doc with this info?

Copy link
Copy Markdown
Member Author

@st0012 done #731.

@vinistock vinistock force-pushed the 04-06-fix_top_level_resolution_algorithm branch from bb9979c to fbf8915 Compare April 8, 2026 19:20
@vinistock vinistock force-pushed the 04-06-fix_default_parent_classes branch from 80710f3 to a00812a Compare April 8, 2026 19:20
@vinistock vinistock force-pushed the 04-06-fix_top_level_resolution_algorithm branch from fbf8915 to 9381da4 Compare April 13, 2026 15:07
@vinistock vinistock force-pushed the 04-06-fix_default_parent_classes branch from a00812a to 1b0feff Compare April 13, 2026 15:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix A change that fixes an existing bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants