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

Fix generic method instantiation #205

Merged
merged 1 commit into from
Sep 15, 2020
Merged
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
17 changes: 10 additions & 7 deletions lib/steep/ast/types/factory.rb
Original file line number Diff line number Diff line change
@@ -219,7 +219,7 @@ def method_type(method_type, self_type:, subst2: nil)
end
end
subst = Interface::Substitution.build(alpha_vars, alpha_types)
subst.merge!(subst2) if subst2
subst.merge!(subst2, overwrite: true) if subst2

type = Interface::MethodType.new(
type_params: type_params,
@@ -313,6 +313,7 @@ def expand_alias(type)
end

def interface(type, private:, self_type: type)
Steep.logger.debug { "Factory#interface: #{type}, private=#{private}, self_type=#{self_type}" }
type = expand_alias(type)

case type
@@ -340,13 +341,15 @@ def interface(type, private:, self_type: type)
)

definition.methods.each do |name, method|
next if method.private? && !private
Steep.logger.tagged "method = #{name}" do
next if method.private? && !private

interface.methods[name] = Interface::Interface::Entry.new(
method_types: method.method_types.map do |type|
method_type(type, self_type: self_type, subst2: subst)
end
)
interface.methods[name] = Interface::Interface::Entry.new(
method_types: method.method_types.map do |type|
method_type(type, self_type: self_type, subst2: subst)
end
)
end
end
end

20 changes: 16 additions & 4 deletions lib/steep/interface/substitution.rb
Original file line number Diff line number Diff line change
@@ -90,20 +90,32 @@ def self.build(vars, types = nil, instance_type: AST::Types::Instance.new, modul

def except(vars)
self.class.new(
dictionary: dictionary.reject {|k, _| vars.include?(k) },
dictionary: dictionary,
instance_type: instance_type,
module_type: module_type,
self_type: self_type
)
).except!(vars)
end

def merge!(s)
def except!(vars)
vars.each do |var|
dictionary.delete(var)
end

self
end

def merge!(s, overwrite: false)
dictionary.transform_values! {|ty| ty.subst(s) }
dictionary.merge!(s.dictionary) do |key, a, b|
if a == b
a
else
raise "Duplicated key on merge!: #{key}, #{a}, #{b}"
if overwrite
b
else
raise "Duplicated key on merge!: #{key}, #{a}, #{b} (#{self})"
end
end
end

1 change: 1 addition & 0 deletions lib/steep/type_construction.rb
Original file line number Diff line number Diff line change
@@ -113,6 +113,7 @@ def update_lvar_env
end

def check_relation(sub_type:, super_type:, constraints: Subtyping::Constraints.empty)
Steep.logger.debug { "check_relation: self:#{self_type} |- #{sub_type} <: #{super_type}" }
checker.check(Subtyping::Relation.new(sub_type: sub_type, super_type: super_type), self_type: self_type, constraints: constraints)
end

25 changes: 25 additions & 0 deletions test/type_construction_test.rb
Original file line number Diff line number Diff line change
@@ -5379,4 +5379,29 @@ def test_endless_range
end
end
end

def test_generic_param_rename
with_checker(<<-RBS) do |checker|
interface _Hello[A]
def get: [A] () -> A
end

class TestTest[A]
def foo: (_Hello[A]) -> void
end
RBS
source = parse_ruby(<<-RUBY)
class TestTest
def foo(x)
x.get()
end
end
RUBY

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