Skip to content

Commit

Permalink
Toplevel constant must be referenced through inheritance
Browse files Browse the repository at this point in the history
  • Loading branch information
soutaro committed Apr 5, 2022
1 parent dc942d8 commit 8d6831f
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 8 deletions.
1 change: 1 addition & 0 deletions lib/rbs/definition_builder/ancestor_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ def instance_ancestors(type_name, building_ancestors: [])

one_ancestors = one_instance_ancestors(type_name)

# @type var ancestors: Array[::RBS::Definition::Ancestor::t]
ancestors = []

case entry
Expand Down
35 changes: 27 additions & 8 deletions lib/rbs/resolver/constant_resolver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,10 @@ def load_context_constants(context)
# @type var consts: Hash[Symbol, Constant]
consts = {}

if context
if last = context[1]
constants_from_ancestors(last, constants: consts)
end
if last = context&.[](1)
constants_from_ancestors(last, constants: consts)
else
constants_from_ancestors(BuiltinNames::Object.name, constants: consts)
end
constants_from_context(context, constants: consts) or return
constants_itself(context, constants: consts)
Expand All @@ -122,7 +122,7 @@ def load_child_constants(name)
constants = {}

if table.children(name)
builder.ancestor_builder.instance_ancestors(name).ancestors.each do |ancestor|
builder.ancestor_builder.instance_ancestors(name).ancestors.reverse_each do |ancestor|
if ancestor.is_a?(Definition::Ancestor::Instance)
if ancestor.name == BuiltinNames::Object.name
if name != BuiltinNames::Object.name
Expand Down Expand Up @@ -152,19 +152,38 @@ def constants_from_context(context, constants:)
consts = table.children(last) or return false
constants.merge!(consts)
end
else
constants.merge!(table.toplevel)
end

true
end

def constants_from_ancestors(module_name, constants:)
builder.ancestor_builder.instance_ancestors(module_name).ancestors.each do |ancestor|
if (entry = builder.env.class_decls[module_name]).is_a?(Environment::ModuleEntry)
self_types = entry.self_types
if self_types.empty?
self_types << AST::Declarations::Module::Self.new(
name: BuiltinNames::Object.name,
args: [],
location: nil
)
end

self_types.each do |self_type|
if self_type.name.class?
constants_from_ancestors(self_type.name, constants: constants)
end
end
end

builder.ancestor_builder.instance_ancestors(module_name).ancestors.reverse_each do |ancestor|
if ancestor.is_a?(Definition::Ancestor::Instance)
case ancestor.source
when AST::Members::Include, :super, nil
consts = table.children(ancestor.name) or raise
if ancestor.name == BuiltinNames::Object.name
# Insert toplevel constants as ::Object's constants
consts.merge!(table.toplevel)
end
constants.merge!(consts)
end
end
Expand Down
43 changes: 43 additions & 0 deletions test/rbs/resolver/constant_resolver_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -282,4 +282,47 @@ class Stuff
end
end
end

def test_reference_constant_toplevel
SignatureManager.new do |manager|
manager.files[Pathname("foo.rbs")] = <<EOF
CONST: Integer
class Foo
CONST: String
end
class Bar < Foo
end
EOF
manager.build do |env|
builder = DefinitionBuilder.new(env: env)
resolver = Resolver::ConstantResolver.new(builder: builder)

resolver.resolve(:CONST, context: [nil, TypeName("::Bar")]).tap do |constant|
assert_equal "::Foo::CONST", constant.name.to_s
end
end
end
end

def test_reference_constant_toplevel2
SignatureManager.new do |manager|
manager.files[Pathname("foo.rbs")] = <<EOF
CONST: Integer
class BasicObject
CONST: String
end
EOF
manager.build do |env|
builder = DefinitionBuilder.new(env: env)
resolver = Resolver::ConstantResolver.new(builder: builder)

resolver.resolve(:CONST, context: [nil, TypeName("::String")]).tap do |constant|
assert_equal "::CONST", constant.name.to_s
end
end
end
end
end

0 comments on commit 8d6831f

Please sign in to comment.