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
14 changes: 7 additions & 7 deletions lib/typeprof/core/ast/sig_decl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -505,20 +505,20 @@ def attrs = { cpath:, class_scope: }

def define0(genv)
@type.define(genv)
mod = genv.resolve_ivar(cpath, @class_scope, @var)
mod.add_decl(self)
mod
mod = genv.resolve_cpath(cpath)
mod.add_ivar_decl(genv, @class_scope, @var, self)
end

def define_copy(genv)
mod = genv.resolve_ivar(cpath, @class_scope, @var)
mod.add_decl(self)
mod.remove_decl(@prev_node)
mod = genv.resolve_cpath(cpath)
mod.add_ivar_decl(genv, @class_scope, @var, self)
mod.remove_ivar_decl(genv, @class_scope, @var, @prev_node)
super(genv)
end

def undefine0(genv)
genv.resolve_ivar(cpath, @class_scope, @var).remove_decl(self)
mod = genv.resolve_cpath(cpath)
mod.remove_ivar_decl(genv, @class_scope, @var, self)
@type.undefine(genv)
end

Expand Down
13 changes: 13 additions & 0 deletions lib/typeprof/core/env/module_entity.rb
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,19 @@ def get_ivar(singleton, name)
@ivars[singleton][name] ||= ValueEntity.new
end

def add_ivar_decl(genv, singleton, name, decl)
ive = get_ivar(singleton, name)
ive.add_decl(decl)
ive.on_decl_changed(genv)
ive
end

def remove_ivar_decl(genv, singleton, name, decl)
ive = get_ivar(singleton, name)
ive.remove_decl(decl)
ive.on_decl_changed(genv)
end

def get_cvar(name)
@cvars[name] ||= ValueEntity.new
end
Expand Down
8 changes: 8 additions & 0 deletions lib/typeprof/core/env/value_entity.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ def remove_decl(decl)
@decls.delete(decl) || raise
end

# Re-run all read boxes that depend on this entity. Used when a
# declaration is added or removed so that dependents (e.g. an
# IVarReadBox that previously fell back to the inferred type) can
# observe the new state.
def on_decl_changed(genv)
@read_boxes.each {|box| genv.add_run(box) }
end

def add_def(def_)
@defs << def_
end
Expand Down
35 changes: 28 additions & 7 deletions lib/typeprof/core/graph/box.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1280,23 +1280,44 @@ def run0(genv, changes)
singleton = @singleton
cur_ive = mod.get_ivar(singleton, @name)
target_vtx = nil
target_decls = nil
genv.each_direct_superclass(mod, singleton) do |mod, singleton|
ive = mod.get_ivar(singleton, @name)
# Subscribe to every visited ive so that, if one later acquires an
# RBS declaration, this box is re-run and switches to the declared
# type instead of the inferred one.
changes.add_depended_value_entity(ive)
if ive.exist?
target_vtx = ive.vtx
target_decls = ive.decls unless ive.decls.empty?
break if target_decls
end
end
edges = []
if target_vtx

if target_decls
# When declarations exist, return declared types instead of assigned types
target_decls.each do |decl|
subst = {}
if decl.cpath
decl_mod = genv.resolve_cpath(decl.cpath)
if decl_mod.type_params && !decl_mod.type_params.empty?
subst = decl_mod.type_params.to_h do |param, _default_ty|
[param, Vertex.new(@node)]
end
end
end
vtx = decl.type.covariant_vertex(genv, changes, subst)
changes.add_edge(genv, vtx, @ret)
end
elsif target_vtx
edges = []
if target_vtx != cur_ive.vtx
edges << [cur_ive.vtx, @proxy] << [@proxy, target_vtx]
end
edges << [target_vtx, @ret]
else
# TODO: error?
end
edges.each do |src, dst|
changes.add_edge(genv, src, dst)
edges.each do |src, dst|
changes.add_edge(genv, src, dst)
end
end
end
end
Expand Down
21 changes: 21 additions & 0 deletions scenario/rbs/ivar_decl_late_load.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
## update: test.rb
class Foo
def initialize
@x = nil
end

def get_x
@x
end
end

## update: test.rbs
class Foo
@x: Integer
end

## assert: test.rb
class Foo
def initialize: -> void
def get_x: -> Integer
end
34 changes: 34 additions & 0 deletions scenario/rbs/ivar_decl_priority.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
## update: test.rbs
class Base
end

class Child < Base
@x: Integer
end

## update: test.rb
class Base
def initialize
@x = nil
end
end

class Child < Base
def initialize
super
@x = 1
end

def get_x
@x
end
end

## assert
class Base
def initialize: -> void
end
class Child < Base
def initialize: -> void
def get_x: -> Integer
end
Loading