Skip to content

Commit 2223292

Browse files
committed
Fix name resolver for class/module-alias
Fix #2293
1 parent 6dd1493 commit 2223292

File tree

4 files changed

+120
-1
lines changed

4 files changed

+120
-1
lines changed

lib/rbs/environment.rb

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,26 @@ def normalize_module_name?(name)
362362
when ClassEntry, ModuleEntry
363363
type_name
364364
when ClassAliasEntry, ModuleAliasEntry
365-
normalize_module_name?(entry.decl.old_name)
365+
i = 0
366+
outer_paths = entry.outer.map { |outer| outer.name.to_namespace.path }
367+
old_name_namespace = entry.decl.old_name.namespace
368+
old_name_bottom = entry.decl.old_name.name
369+
n = nil #: ::RBS::TypeName | nil | false
370+
loop do
371+
outer_path = outer_paths[-i, i] or raise
372+
t = TypeName.new(
373+
namespace: Namespace.new(
374+
absolute: false,
375+
path: outer_path.flatten
376+
) + old_name_namespace,
377+
name: old_name_bottom
378+
)
379+
n = normalize_module_name?(t)
380+
break if n
381+
i += 1
382+
break if outer_paths.length < i
383+
end
384+
n
366385
else
367386
nil
368387
end

lib/rbs/validator.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,11 +158,20 @@ def validate_variable(var)
158158
def validate_class_alias(entry:)
159159
case env.normalize_module_name?(entry.decl.new_name)
160160
when nil
161+
# Unreachable?
161162
raise NoTypeFoundError.new(type_name: entry.decl.old_name, location: entry.decl.location&.[](:old_name))
162163
when false
163164
raise CyclicClassAliasDefinitionError.new(entry)
164165
end
165166

167+
case env.normalize_module_name?(entry.decl.old_name)
168+
when nil
169+
raise NoTypeFoundError.new(type_name: entry.decl.old_name, location: entry.decl.location&.[](:old_name))
170+
when false
171+
# Unreachable?
172+
raise CyclicClassAliasDefinitionError.new(entry)
173+
end
174+
166175
case entry
167176
when Environment::ClassAliasEntry
168177
unless env.class_entry(entry.decl.old_name)

test/rbs/cli_test.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,38 @@ def void: () -> voida
839839
end
840840
end
841841

842+
# https://github.com/ruby/rbs/issues/2293
843+
def test_nested_module_alias
844+
with_cli do |cli|
845+
Dir.mktmpdir do |dir|
846+
(Pathname(dir) + 'a.rbs').write(<<~RBS)
847+
module Foo
848+
module Bar
849+
module M
850+
end
851+
module M2 = M
852+
end
853+
854+
module Baz = Bar
855+
856+
module Bar::N = Bar::M
857+
858+
module X = Nothing
859+
end
860+
861+
module Foo::Qux = Foo::Baz
862+
863+
module Foo::Y = Foo::Nothing
864+
RBS
865+
assert_raises SystemExit do
866+
cli.run(["-I", dir, "validate"])
867+
end
868+
assert_include stdout.string, "a.rbs:12:13...12:20: Could not find Nothing (RBS::NoTypeFoundError)"
869+
assert_include stdout.string, "a.rbs:17:16...17:28: Could not find Foo::Nothing (RBS::NoTypeFoundError)"
870+
end
871+
end
872+
end
873+
842874
def test_constant
843875
with_cli do |cli|
844876
cli.run(%w(constant Pathname))

test/validator_test.rb

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,65 @@ class Baz = Baz
277277
end
278278
end
279279

280+
# https://github.com/ruby/rbs/issues/2293
281+
def test_validate_class_alias_in_namespace
282+
SignatureManager.new do |manager|
283+
manager.add_file("foo.rbs", <<-EOF)
284+
module Foo
285+
module Bar
286+
module M
287+
end
288+
module M2 = M
289+
end
290+
291+
module Baz = Bar
292+
293+
module Bar::N = Bar::M
294+
295+
module X = Nothing
296+
end
297+
298+
module Foo::Qux = Foo::Baz
299+
300+
module Foo::Y = Foo::Nothing
301+
EOF
302+
303+
manager.build do |env|
304+
validator = RBS::Validator.new(env: env)
305+
env.class_alias_decls[RBS::TypeName.parse("::Foo::Baz")].tap do |entry|
306+
assert_nothing_raised do
307+
validator.validate_class_alias(entry: entry)
308+
end
309+
end
310+
env.class_alias_decls[RBS::TypeName.parse("::Foo::Bar::N")].tap do |entry|
311+
assert_nothing_raised do
312+
validator.validate_class_alias(entry: entry)
313+
end
314+
end
315+
env.class_alias_decls[RBS::TypeName.parse("::Foo::Bar::M2")].tap do |entry|
316+
assert_nothing_raised do
317+
validator.validate_class_alias(entry: entry)
318+
end
319+
end
320+
env.class_alias_decls[RBS::TypeName.parse("::Foo::Qux")].tap do |entry|
321+
assert_nothing_raised do
322+
validator.validate_class_alias(entry: entry)
323+
end
324+
end
325+
env.class_alias_decls[RBS::TypeName.parse("::Foo::X")].tap do |entry|
326+
assert_raises RBS::NoTypeFoundError do
327+
validator.validate_class_alias(entry: entry)
328+
end
329+
end
330+
env.class_alias_decls[RBS::TypeName.parse("::Foo::Y")].tap do |entry|
331+
assert_raises RBS::NoTypeFoundError do
332+
validator.validate_class_alias(entry: entry)
333+
end
334+
end
335+
end
336+
end
337+
end
338+
280339
def test_validate_type__presence__module_alias_instance
281340
SignatureManager.new do |manager|
282341
manager.add_file("foo.rbs", <<-EOF)

0 commit comments

Comments
 (0)