Skip to content

Commit

Permalink
Merge pull request #609 from soutaro/generic-type-inference-bug
Browse files Browse the repository at this point in the history
Fix type inference problem on generics
  • Loading branch information
soutaro committed Jul 20, 2022
2 parents 6168467 + 7b4cfe2 commit f890f87
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 18 deletions.
12 changes: 12 additions & 0 deletions lib/steep/subtyping/constraints.rb
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,18 @@ def eliminate_variable(type, to:)
else
type
end
when AST::Types::Tuple
AST::Types::Tuple.new(
types: type.types.map {|ty| eliminate_variable(ty, to: AST::Builtin.any_type) },
location: type.location
)
when AST::Types::Record
AST::Types::Record.new(
elements: type.elements.transform_values {|ty| eliminate_variable(ty, to: AST::Builtin.any_type) },
location: type.location
)
when AST::Types::Proc
type.map_type {|ty| eliminate_variable(ty, to: AST::Builtin.any_type) }
else
type
end
Expand Down
4 changes: 4 additions & 0 deletions lib/steep/type_construction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2731,6 +2731,10 @@ def type_lambda(node, params_node:, body_node:, type_hint:)
)

if expected_block_type = block_constr.block_context.body_type
type_vars = expected_block_type.free_variables
subst = Interface::Substitution.build(type_vars, type_vars.map { AST::Builtin.any_type })
expected_block_type = expected_block_type.subst(subst)

check_relation(sub_type: return_type, super_type: expected_block_type).else do |result|
block_constr.typing.add_error(
Diagnostic::Ruby::BlockBodyTypeMismatch.new(
Expand Down
31 changes: 16 additions & 15 deletions sig/steep/ast/types/proc.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,42 @@ module Steep
class Proc
attr_reader location: untyped

attr_reader type: untyped
attr_reader type: Interface::Function

attr_reader block: untyped
attr_reader block: Interface::Block?

def initialize: (type: untyped, block: untyped, ?location: untyped) -> void
def initialize: (type: Interface::Function, block: Interface::Block?, ?location: untyped) -> void

def ==: (untyped other) -> untyped
def ==: (untyped other) -> bool

def hash: () -> untyped
def hash: () -> Integer

alias eql? ==

def subst: (untyped s) -> untyped
def subst: (Interface::Substitution s) -> Proc

def to_s: () -> ::String

def free_variables: () -> untyped
def free_variables: () -> Set[Symbol]

include Helper::ChildrenLevel

def level: () -> untyped
def level: () -> Array[Integer]

def closed?: () -> untyped
def closed?: () -> bool

def with_location: (untyped new_location) -> untyped
def with_location: (untyped new_location) -> Proc

def map_type: () ?{ () -> untyped } -> untyped
def map_type: () { (AST::Types::t) -> AST::Types::t } -> Proc

def one_arg?: () -> untyped
def one_arg?: () -> bool

def back_type: () -> untyped
def back_type: () -> AST::Types::t

def block_required?: () -> untyped
def block_required?: () -> bool

def each_child: () ?{ () -> untyped } -> untyped
def each_child: () { (AST::Types::t) -> void } -> void
| () -> Enumerator[AST::Types::t, void]
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion sig/steep/subtyping/constraints.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ module Steep

def add: (untyped var, ?sub_type: untyped?, ?super_type: untyped?, ?skip: bool) -> untyped

def eliminate_variable: (untyped `type`, to: untyped) -> untyped
def eliminate_variable: (AST::Types::t `type`, to: AST::Types::t) -> AST::Types::t

def unknown?: (untyped var) -> untyped

Expand Down
4 changes: 2 additions & 2 deletions sig/steep/type_construction.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ module Steep

def synthesize: (Parser::AST::Node node, ?hint: AST::Types::t?, ?condition: bool) -> Pair

def check: (Parser::AST::Node node, untyped `type`, ?constraints: untyped) { (untyped, untyped, untyped) -> untyped } -> bool
def check: (Parser::AST::Node node, AST::Types::t `type`, ?constraints: Subtyping::Constraints) { (AST::Types::t, AST::Types::t, Subtyping::Result::Base) -> void } -> Pair