Skip to content

Commit

Permalink
Merge pull request #1229 from soutaro/kernel-class
Browse files Browse the repository at this point in the history
Add special path for `Kernel#class` method
  • Loading branch information
soutaro authored Sep 19, 2024
2 parents 3c6448e + 76fb79d commit a63fce4
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 35 deletions.
1 change: 1 addition & 0 deletions lib/steep/ast/builtin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ def module_type?(type)
Regexp = Type.new("::Regexp")
NilClass = Type.new("::NilClass")
Proc = Type.new("::Proc")
Kernel = Type.new("::Kernel")

def self.nil_type
AST::Types::Nil.instance
Expand Down
23 changes: 22 additions & 1 deletion lib/steep/interface/builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ def singleton_shape(type_name)
method_name = method_name_for(type_def, name)
method_type = factory.method_type(type_def.type)
method_type = replace_primitive_method(method_name, type_def, method_type)
method_type = replace_kernel_class(method_name, type_def, method_type) { AST::Builtin::Class.instance_type }
Shape::MethodOverload.new(method_type, [type_def])
end

Expand Down Expand Up @@ -311,6 +312,9 @@ def object_shape(type_name)
method_name = method_name_for(type_def, name)
method_type = factory.method_type(type_def.type)
method_type = replace_primitive_method(method_name, type_def, method_type)
if type_name.class?
method_type = replace_kernel_class(method_name, type_def, method_type) { AST::Types::Name::Singleton.new(name: type_name) }
end
Shape::MethodOverload.new(method_type, [type_def])
end

Expand Down Expand Up @@ -748,7 +752,7 @@ def replace_primitive_method(method_name, method_def, method_type)
return_type: AST::Types::Logic::ReceiverIsNil.instance()
)
)
end
end
end

when :!
Expand Down Expand Up @@ -801,6 +805,23 @@ def replace_primitive_method(method_name, method_def, method_type)

method_type
end

def replace_kernel_class(method_name, method_def, method_type)
defined_in = method_def.defined_in
member = method_def.member

if member.is_a?(RBS::AST::Members::MethodDefinition)
case method_name.method_name
when :class
case defined_in
when AST::Builtin::Kernel.module_name
return method_type.with(type: method_type.type.with(return_type: yield))
end
end
end

method_type
end
end
end
end
Expand Down
31 changes: 2 additions & 29 deletions lib/steep/type_construction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2657,34 +2657,11 @@ def check(node, type, constraints: Subtyping::Constraints.empty)
def synthesize_sendish(node, hint:, tapp:)
case node.type
when :send
yield_self do
if self_class?(node)
module_type = expand_alias(module_context.module_type)
type = if module_type.is_a?(AST::Types::Name::Singleton)
AST::Types::Name::Singleton.new(name: module_type.name)
else
module_type
end

add_typing(node, type: type)
else
type_send(node, send_node: node, block_params: nil, block_body: nil, tapp: tapp, hint: hint)
end
end
type_send(node, send_node: node, block_params: nil, block_body: nil, tapp: tapp, hint: hint)
when :csend
yield_self do
send_type, constr =
if self_class?(node)
module_type = expand_alias(module_context.module_type)
type = if module_type.is_a?(AST::Types::Name::Singleton)
AST::Types::Name::Singleton.new(name: module_type.name)
else
module_type
end
add_typing(node, type: type).to_ary
else
type_send(node, send_node: node, block_params: nil, block_body: nil, unwrap: true, tapp: tapp, hint: hint).to_ary
end
type_send(node, send_node: node, block_params: nil, block_body: nil, unwrap: true, tapp: tapp, hint: hint).to_ary

constr
.update_type_env { context.type_env.join(constr.context.type_env, context.type_env) }
Expand Down Expand Up @@ -4687,10 +4664,6 @@ def fallback_to_any(node)
add_typing node, type: AST::Builtin.any_type
end

def self_class?(node)
node.type == :send && node.children[0]&.type == :self && node.children[1] == :class
end

def namespace_module?(node)
# @type var nodes: Array[Parser::AST::Node]
nodes =
Expand Down
2 changes: 2 additions & 0 deletions sig/steep/ast/builtin.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ module Steep

Proc: Type

Kernel: Type

def self.nil_type: () -> Types::Nil

def self.any_type: () -> Types::Any
Expand Down
2 changes: 2 additions & 0 deletions sig/steep/interface/builder.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ module Steep

def replace_primitive_method: (method_name, RBS::Definition::Method::TypeDef, MethodType) -> MethodType

def replace_kernel_class: (method_name, RBS::Definition::Method::TypeDef, MethodType) { () -> AST::Types::t } -> MethodType

@subtyping: Subtyping::Check?

def subtyping: () -> Subtyping::Check
Expand Down
3 changes: 0 additions & 3 deletions sig/steep/type_construction.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -393,9 +393,6 @@ module Steep

def fallback_to_any: (Parser::AST::Node node) ?{ () -> Diagnostic::Ruby::Base } -> Pair

# Return `true` if `node` is `self.class`
def self_class?: (Parser::AST::Node node) -> bool

# Returns `true` if the given `node` is a `class` or `module` declaration that only contains module/class definitions
#
def namespace_module?: (Parser::AST::Node node) -> bool
Expand Down
25 changes: 23 additions & 2 deletions test/type_check_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2349,13 +2349,34 @@ def initialize: (Integer) -> void
},
code: {
"a.rb" => <<~RUBY
Foo.new(1).class.new(2)
Foo.new(1).class.fooo
Foo.class.barr
RUBY
},
expectations: <<~YAML
---
- file: a.rb
diagnostics: []
diagnostics:
- range:
start:
line: 1
character: 17
end:
line: 1
character: 21
severity: ERROR
message: Type `singleton(::Foo)` does not have method `fooo`
code: Ruby::NoMethod
- range:
start:
line: 2
character: 10
end:
line: 2
character: 14
severity: ERROR
message: Type `::Class` does not have method `barr`
code: Ruby::NoMethod
YAML
)
end
Expand Down

0 comments on commit a63fce4

Please sign in to comment.