Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stop MethodDefinitionMissing for attr_* and aliases #976

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions lib/steep/type_construction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2613,6 +2613,7 @@ def synthesize(node, hint: nil, condition: false)
end

when :alias
module_context.defined_instance_methods << node.children.first.children.first
add_typing node, type: AST::Builtin.nil_type

when :splat
Expand Down Expand Up @@ -3465,6 +3466,24 @@ def type_send(node, send_node:, block_params:, block_body:, unwrap: false, tapp:
end
end

if module_context && receiver.nil?
case method_name
when :attr_reader
arguments.each do |arg|
module_context.defined_instance_methods << arg.children[0]
Copy link
Owner

Choose a reason for hiding this comment

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

Looks like it's assuming the arguments are symbol literals? Should consider the case they are not.

end
when :attr_writer
arguments.each do |arg|
module_context.defined_instance_methods << "#{arg.children[0]}=".to_sym
end
when :attr_accessor
arguments.each do |arg|
module_context.defined_instance_methods << arg.children[0]
module_context.defined_instance_methods << "#{arg.children[0]}=".to_sym
end
end
end

if unwrap
recv_type = unwrap(recv_type)
end
Expand Down
151 changes: 151 additions & 0 deletions test/type_construction_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10821,4 +10821,155 @@ def test_type_hint__proc_union_proc_instance
end
end
end

def test_method_definition_missing_for_methods
with_checker(<<~RBS) do |checker|
class A
def foo: () -> void
def bar: () -> void
end
RBS
source = parse_ruby(<<~RUBY)
class A
def foo
end
end
RUBY

with_standard_construction(checker, source) do |construction, typing|
construction.synthesize(source.node)

assert_equal 1, typing.errors.size

typing.errors[0].tap do |error|
assert_instance_of Diagnostic::Ruby::MethodDefinitionMissing, error
assert_equal :bar, error.missing_method
end
end
end
end

def test_method_definition_missing_for_attr_readers
with_checker(<<~RBS) do |checker|
class A
attr_reader foo: Integer
attr_reader bar: Integer
end
RBS
source = parse_ruby(<<~RUBY)
class A
attr_reader :foo
end
RUBY

with_standard_construction(checker, source) do |construction, typing|
construction.synthesize(source.node)

assert_equal 1, typing.errors.size

typing.errors[0].tap do |error|
assert_instance_of Diagnostic::Ruby::MethodDefinitionMissing, error
assert_equal :bar, error.missing_method
end
end
end
end

def test_method_definition_missing_for_attr_writers
with_checker(<<~RBS) do |checker|
class A
attr_writer foo: Integer
attr_writer bar: Integer
end
RBS
source = parse_ruby(<<~RUBY)
class A
attr_writer :foo
end
RUBY

with_standard_construction(checker, source) do |construction, typing|
construction.synthesize(source.node)

assert_equal 2, typing.errors.size

typing.errors[0].tap do |error|
assert_instance_of Diagnostic::Ruby::NoMethod, error
assert_equal :attr_writer, error.method # why?
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure why NoMethod is raised for attr_writer...

end

typing.errors[1].tap do |error|
assert_instance_of Diagnostic::Ruby::MethodDefinitionMissing, error
assert_equal :bar=, error.missing_method
end
end
end
end

def test_method_definition_missing_for_attr_accessors
with_checker(<<~RBS) do |checker|
class A
attr_accessor foo: Integer
attr_accessor bar: Integer
end
RBS
source = parse_ruby(<<~RUBY)
class A
attr_accessor :foo
end
RUBY

with_standard_construction(checker, source) do |construction, typing|
construction.synthesize(source.node)

assert_equal 3, typing.errors.size

typing.errors[0].tap do |error|
assert_instance_of Diagnostic::Ruby::NoMethod, error
assert_equal :attr_accessor, error.method # why?
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is also.

end

typing.errors[1].tap do |error|
assert_instance_of Diagnostic::Ruby::MethodDefinitionMissing, error
assert_equal :bar, error.missing_method
end

typing.errors[2].tap do |error|
assert_instance_of Diagnostic::Ruby::MethodDefinitionMissing, error
assert_equal :bar=, error.missing_method
end
end
end
end

def test_method_definition_missing_for_aliases
with_checker(<<~RBS) do |checker|
class A
def ==: (untyped) -> bool
alias eql? ==
alias equal? ==
end
RBS
source = parse_ruby(<<~RUBY)
class A
def ==(other)
true
end

alias eql? ==
end
RUBY

with_standard_construction(checker, source) do |construction, typing|
construction.synthesize(source.node)

assert_equal 1, typing.errors.size

typing.errors[0].tap do |error|
assert_instance_of Diagnostic::Ruby::MethodDefinitionMissing, error
assert_equal :equal?, error.missing_method
end
end
end
end
end
Loading