diff --git a/lib/rbs/definition_builder.rb b/lib/rbs/definition_builder.rb index 715b417a9..fd6b61534 100644 --- a/lib/rbs/definition_builder.rb +++ b/lib/rbs/definition_builder.rb @@ -504,6 +504,11 @@ def source_location(source, decl) def validate_type_params(definition, ancestors:, methods:) type_params = definition.type_params_decl + # Without type params nothing can violate the variance: the ancestor validation + # iterates the (empty) params, and the type params of the methods themselves are + # invariant, which `Result#compatible?` always accepts + return if type_params.empty? + calculator = VarianceCalculator.new(builder: self) param_names = type_params.each.map(&:name) @@ -1048,9 +1053,10 @@ def validate_type_presence(type) end def validate_type_name(name, location) - name = name.absolute! unless name.absolute? - return if env.type_name?(env.normalize_type_name(name)) + absolute = name.absolute? ? name : name.absolute! + return if env.type_name?(env.normalize_type_name(absolute)) + # Report the name as it is written in the signature raise NoTypeFoundError.new(type_name: name, location: location) end end diff --git a/lib/rbs/environment/class_entry.rb b/lib/rbs/environment/class_entry.rb index 73762330a..56366ee43 100644 --- a/lib/rbs/environment/class_entry.rb +++ b/lib/rbs/environment/class_entry.rb @@ -15,6 +15,7 @@ def initialize(name) def <<(context_decl) context_decls << context_decl @primary_decl = nil + @type_params_validated = nil self end @@ -50,6 +51,10 @@ def type_params end def validate_type_params + # The entry only changes with `<<`, which resets the memo -- a failed + # validation is not recorded and raises again + return if @type_params_validated + unless context_decls.empty? first_decl, *rest_decls = each_decl.to_a first_decl or raise @@ -63,6 +68,8 @@ def validate_type_params end end end + + @type_params_validated = true end def align_params(decl) diff --git a/lib/rbs/environment/module_entry.rb b/lib/rbs/environment/module_entry.rb index 1f65cf490..95db8eb14 100644 --- a/lib/rbs/environment/module_entry.rb +++ b/lib/rbs/environment/module_entry.rb @@ -14,6 +14,7 @@ def initialize(name) def <<(context_decl) context_decls << context_decl + @type_params_validated = nil self end @@ -72,6 +73,10 @@ def align_params(decl) end def validate_type_params + # The entry only changes with `<<`, which resets the memo -- a failed + # validation is not recorded and raises again + return if @type_params_validated + unless context_decls.empty? first_decl, *rest_decls = each_decl.to_a first_decl or raise @@ -85,6 +90,8 @@ def validate_type_params end end end + + @type_params_validated = true end end end diff --git a/sig/environment/class_entry.rbs b/sig/environment/class_entry.rbs index ff97cc5c1..00e73e541 100644 --- a/sig/environment/class_entry.rbs +++ b/sig/environment/class_entry.rbs @@ -18,6 +18,8 @@ module RBS @primary_decl: declaration? + @type_params_validated: bool? + def initialize: (TypeName) -> void def <<: (context_decl) -> self diff --git a/sig/environment/module_entry.rbs b/sig/environment/module_entry.rbs index c556b0979..3230a4b35 100644 --- a/sig/environment/module_entry.rbs +++ b/sig/environment/module_entry.rbs @@ -17,6 +17,8 @@ module RBS attr_reader context_decls: Array[context_decl] + @type_params_validated: bool? + def initialize: (TypeName) -> void def <<: (context_decl) -> self diff --git a/test/rbs/cli_test.rb b/test/rbs/cli_test.rb index 3d37fe9c0..e9f6672a0 100644 --- a/test/rbs/cli_test.rb +++ b/test/rbs/cli_test.rb @@ -402,7 +402,7 @@ module Bar[B] cli.run(["-I", dir, "validate"]) end - assert_include stdout.string, "a.rbs:2:13...2:14: Could not find ::A (RBS::NoTypeFoundError)" + assert_include stdout.string, "a.rbs:2:13...2:14: Could not find A (RBS::NoTypeFoundError)" end end end