From 7b7c1664201479115a7360f184c8e05099a3a7e8 Mon Sep 17 00:00:00 2001 From: Takumi Shotoku Date: Wed, 25 Feb 2026 23:32:21 +0900 Subject: [PATCH] Fix constant resolution to prioritize nesting scope over Object ancestors In Ruby's constant lookup, lexical scope (nesting) takes priority over ancestors. However, `resolve` searched all ancestors including Object before checking outer nesting scopes. This caused `include Store` inside `ActiveRecord::Base` to resolve to `::Store` (app model, via Object) instead of `ActiveRecord::Store` (via nesting). Stop ancestor search at Object when outer nesting scopes remain to be checked (cref.outer), while preserving existing behavior for ScopedConstRead which already passes break_object=true. --- lib/typeprof/core/env/static_read.rb | 2 +- scenario/class/rbs_const_resolution.rb | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 scenario/class/rbs_const_resolution.rb diff --git a/lib/typeprof/core/env/static_read.rb b/lib/typeprof/core/env/static_read.rb index 774bd4241..34ea16121 100644 --- a/lib/typeprof/core/env/static_read.rb +++ b/lib/typeprof/core/env/static_read.rb @@ -37,7 +37,7 @@ def resolve(genv, cref, search_ancestors, break_object) scope = cref.cpath mod = genv.resolve_cpath(scope) genv.each_superclass(mod, false) do |mod, _singleton| - break if mod == genv.mod_object && break_object + break if mod == genv.mod_object && (break_object || cref.outer) unless @source_modules.include?(mod) @source_modules << mod diff --git a/scenario/class/rbs_const_resolution.rb b/scenario/class/rbs_const_resolution.rb new file mode 100644 index 000000000..1e58a0f81 --- /dev/null +++ b/scenario/class/rbs_const_resolution.rb @@ -0,0 +1,22 @@ +## update: test.rbs +module Outer + class Base + include Inner + end + + module Inner + def foo: -> Integer + end +end + +## update: test.rb +class Inner < Outer::Base + def bar + foo + end +end + +## assert: test.rb +class Inner < Outer::Base + def bar: -> Integer +end