Skip to content
Merged
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
17 changes: 13 additions & 4 deletions lib/typeprof/core/ast/sig_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def self.typecheck_for_prepended_modules(genv, changes, a_ty, f_mod, f_args, sub
if prep_decl.is_a?(AST::SigPrependNode) && prep_mod.type_params
prep_ty = genv.get_instance_type(prep_mod, prep_decl.args, changes, {}, a_ty)
else
type_params = prep_mod.type_params.map {|(_name, _default_ty)| Source.new() } # TODO: better support
type_params = prep_mod.type_params.map {|(_name, _default_ty)| genv.untyped_arg } # TODO: better support
prep_ty = Type::Instance.new(genv, prep_mod, type_params)
end
if prep_ty.mod == f_mod
Expand All @@ -64,7 +64,7 @@ def self.typecheck_for_included_modules(genv, changes, a_ty, f_mod, f_args, subs
if inc_decl.is_a?(AST::SigIncludeNode) && inc_mod.type_params
inc_ty = genv.get_instance_type(inc_mod, inc_decl.args, changes, {}, a_ty)
else
type_params = inc_mod.type_params.map {|(_name, _default_ty)| Source.new() } # TODO: better support
type_params = inc_mod.type_params.map {|(_name, _default_ty)| genv.untyped_arg } # TODO: better support
inc_ty = Type::Instance.new(genv, inc_mod, type_params)
end
if inc_ty.mod == f_mod
Expand All @@ -89,7 +89,7 @@ def self.typecheck_for_extended_modules(genv, changes, a_ty, f_mod, f_args, subs
if ext_decl.is_a?(AST::SigExtendNode) && ext_mod.type_params
ext_ty = genv.get_instance_type(ext_mod, ext_decl.args, changes, {}, a_ty)
else
type_params = ext_mod.type_params.map {|(_name, _default_ty)| Source.new() } # TODO: better support
type_params = ext_mod.type_params.map {|(_name, _default_ty)| genv.untyped_arg } # TODO: better support
ext_ty = Type::Instance.new(genv, ext_mod, type_params)
end
if ext_ty.mod == f_mod
Expand Down Expand Up @@ -705,6 +705,10 @@ def covariant_vertex0(genv, changes, vtx, subst)
return unless cpath
mod = genv.resolve_cpath(cpath)
args = @args.map {|arg| arg.covariant_vertex(genv, changes, subst) }
# Omitted type arguments (e.g., `Foo` for `Foo[T]`) default to untyped
mod.type_params.drop(args.size).each do |_, default_ty|
args << (default_ty ? default_ty.covariant_vertex(genv, changes, subst) : genv.untyped_arg)
end
changes.add_edge(genv, Source.new(Type::Instance.new(genv, mod, args)), vtx)
end

Expand All @@ -716,7 +720,7 @@ def contravariant_vertex0(genv, changes, vtx, subst)
# TODO: report error for wrong type arguments
# TODO: support default type args
args = mod.type_params.zip(@args).map do |_, arg|
arg ? arg.contravariant_vertex(genv, changes, subst) : Source.new
arg ? arg.contravariant_vertex(genv, changes, subst) : genv.untyped_arg
end
changes.add_edge(genv, Source.new(Type::Instance.new(genv, mod, args)), vtx)
end
Expand Down Expand Up @@ -1095,6 +1099,10 @@ def covariant_vertex0(genv, changes, vtx, subst)
return unless cpath
mod = genv.resolve_cpath(cpath)
args = @args.map {|arg| arg.covariant_vertex(genv, changes, subst) }
# Omitted type arguments (e.g., `Foo` for `Foo[T]`) default to untyped
mod.type_params.drop(args.size).each do |_, default_ty|
args << (default_ty ? default_ty.covariant_vertex(genv, changes, subst) : genv.untyped_arg)
end
changes.add_edge(genv, Source.new(Type::Instance.new(genv, mod, args)), vtx)
end

Expand All @@ -1104,6 +1112,7 @@ def contravariant_vertex0(genv, changes, vtx, subst)
return unless cpath
mod = genv.resolve_cpath(cpath)
args = @args.map {|arg| arg.contravariant_vertex(genv, changes, subst) }
mod.type_params.drop(args.size).each { args << genv.untyped_arg }
changes.add_edge(genv, Source.new(Type::Instance.new(genv, mod, args)), vtx)
end

Expand Down
17 changes: 11 additions & 6 deletions lib/typeprof/core/env.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ def initialize

@bot_type = Type::Bot.new(self)

# The vertex for a type argument that is not given. This must be shared:
# a fresh vertex makes a different Instance type and a different edge on
# every run, so a box that uses it is re-run forever.
@untyped_arg = Source.new

@run_count = 0
end

Expand All @@ -52,7 +57,7 @@ def initialize
attr_reader :obj_type, :nil_type, :true_type, :false_type, :str_type
attr_reader :int_type, :float_type, :rational_type, :complex_type
attr_reader :proc_type, :symbol_type, :method_type, :set_type, :regexp_type
attr_reader :bot_type
attr_reader :bot_type, :untyped_arg

def gen_ary_type(elem_vtx)
Type::Instance.new(self, @mod_ary, [elem_vtx])
Expand Down Expand Up @@ -130,18 +135,18 @@ def get_instance_type(mod, type_args, changes, base_ty_env, base_ty)
ty_env = base_ty_env.dup
if base_ty.is_a?(Type::Instance)
base_ty.mod.type_params.zip(base_ty.args) do |(param, default_ty), arg|
ty_env[param] = arg || (default_ty ? default_ty.covariant_vertex(self, changes, ty_env) : Source.new)
ty_env[param] = arg || (default_ty ? default_ty.covariant_vertex(self, changes, ty_env) : @untyped_arg)
end
elsif base_ty.is_a?(Type::Singleton)
base_ty.mod.type_params&.each do |(param, default_ty)|
ty_env[param] = default_ty ? default_ty.covariant_vertex(self, changes, ty_env) : Source.new
ty_env[param] = default_ty ? default_ty.covariant_vertex(self, changes, ty_env) : @untyped_arg
end
end
args = mod.type_params.zip(type_args).map do |(param, default_ty), arg|
if changes
(arg || default_ty)&.covariant_vertex(self, changes, ty_env) || Source.new
(arg || default_ty)&.covariant_vertex(self, changes, ty_env) || @untyped_arg
else
Source.new
@untyped_arg
end
end
Type::Instance.new(self, mod, args)
Expand Down Expand Up @@ -463,7 +468,7 @@ def get_self(genv)
case @scope_level
when :instance
mod = genv.resolve_cpath(@cpath || [])
type_params = mod.type_params.map {|(_name, _default_ty)| Source.new() } # TODO: better support
type_params = mod.type_params.map {|(_name, _default_ty)| genv.untyped_arg } # TODO: better support
ty = Type::Instance.new(genv, mod, type_params)
Source.new(ty)
when :class
Expand Down
10 changes: 5 additions & 5 deletions lib/typeprof/core/graph/box.rb
Original file line number Diff line number Diff line change
Expand Up @@ -779,7 +779,7 @@ def run0(genv, changes)
ty = Type::Singleton.new(genv, mod)
param_map0 = Type.default_param_map(genv, ty)
else
type_params = mod.type_params.map {|(_name, _default_ty)| Source.new() } # TODO: better support
type_params = mod.type_params.map {|(_name, _default_ty)| genv.untyped_arg } # TODO: better support
ty = Type::Instance.new(genv, mod, type_params)
param_map0 = Type.default_param_map(genv, ty)
if ty.is_a?(Type::Instance)
Expand Down Expand Up @@ -984,7 +984,7 @@ def run0(genv, changes)
ty_env = Type.default_param_map(genv, orig_ty)
if ty.is_a?(Type::Instance)
ty.mod.type_params.zip(ty.args) do |(param, default_ty), arg|
ty_env[param] = arg || (default_ty ? default_ty.covariant_vertex(genv, changes, ty_env) : Source.new)
ty_env[param] = arg || (default_ty ? default_ty.covariant_vertex(genv, changes, ty_env) : genv.untyped_arg)
end
end
mdecl.resolve_overloads(changes, genv, @node, ty_env, a_args, @ret) do |method_type|
Expand Down Expand Up @@ -1095,7 +1095,7 @@ def resolve_prepended_modules(genv, changes, base_ty_env, ty, mid, &blk)
if prep_decl.is_a?(AST::SigPrependNode) && prep_mod.type_params
prep_ty = genv.get_instance_type(prep_mod, prep_decl.args, changes, base_ty_env, ty)
else
type_params = prep_mod.type_params.map { Source.new() } # TODO: better support
type_params = prep_mod.type_params.map { genv.untyped_arg } # TODO: better support
prep_ty = Type::Instance.new(genv, prep_mod, type_params)
end

Expand Down Expand Up @@ -1150,7 +1150,7 @@ def resolve_included_modules(genv, changes, base_ty_env, ty, mid, &blk)
if inc_decl.is_a?(AST::SigIncludeNode) && inc_mod.type_params
inc_ty = genv.get_instance_type(inc_mod, inc_decl.args, changes, base_ty_env, ty)
else
type_params = inc_mod.type_params.map { Source.new() } # TODO: better support
type_params = inc_mod.type_params.map { genv.untyped_arg } # TODO: better support
inc_ty = Type::Instance.new(genv, inc_mod, type_params)
end

Expand Down Expand Up @@ -1181,7 +1181,7 @@ def resolve_extended_modules(genv, changes, base_ty_env, ty, mid, &blk)
if ext_decl.is_a?(AST::SigExtendNode) && ext_mod.type_params
ext_ty = genv.get_instance_type(ext_mod, ext_decl.args, changes, base_ty_env, ty)
else
type_params = ext_mod.type_params.map { Source.new() } # TODO: better support
type_params = ext_mod.type_params.map { genv.untyped_arg } # TODO: better support
ext_ty = Type::Instance.new(genv, ext_mod, type_params)
end

Expand Down
2 changes: 1 addition & 1 deletion lib/typeprof/core/type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def show

def get_instance_type(genv)
params = @mod.type_params
Instance.new(genv, @mod, params ? params.map { Source.new } : []) # TODO: respect param_default_types
Instance.new(genv, @mod, params ? params.map { genv.untyped_arg } : []) # TODO: respect param_default_types
end
end

Expand Down
23 changes: 23 additions & 0 deletions scenario/rbs/generic-superclass-without-args.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
## update: test.rbs
class Gen[T]
def self.create: () -> instance
end

class Object
def accept: (Gen[Integer]) -> String
end

## update: test.rb
class Sub < Gen
end

def test
accept(Sub.create)
end

## assert
class Sub < Gen
end
class Object
def test: -> String
end
40 changes: 40 additions & 0 deletions scenario/rbs/omitted-type-args.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
## update: test.rbs
class Gen[T]
end

class D[T, U = String]
def u: () -> U
end

interface _I[T]
def get: () -> T
end

class Object
def gen: () -> Gen
def d: () -> D
def i: () -> _I
def accept_gen: (Gen[Integer]) -> String
def accept_d: (D[Integer, String]) -> String
def accept_i: (_I[Integer]) -> String
end

## update: test.rb
def test_gen = accept_gen(gen)
def test_d = accept_d(d)
def test_i = accept_i(i)
def raw_gen = gen
def raw_d = d
def raw_d_u = d.u
def raw_i = i

## assert
class Object
def test_gen: -> String
def test_d: -> String
def test_i: -> String
def raw_gen: -> Gen[untyped]
def raw_d: -> D[untyped, String]
def raw_d_u: -> String
def raw_i: -> _I[untyped]
end
Loading