diff --git a/lib/typeprof/core/ast.rb b/lib/typeprof/core/ast.rb index 29d3f439..c0c68d01 100644 --- a/lib/typeprof/core/ast.rb +++ b/lib/typeprof/core/ast.rb @@ -18,8 +18,8 @@ def self.parse_rb(path, src) ProgramNode.new(raw_scope, lenv) end - #: (untyped, TypeProf::Core::LocalEnv) -> TypeProf::Core::AST::Node - def self.create_node(raw_node, lenv) + #: (untyped, TypeProf::Core::LocalEnv, ?bool) -> TypeProf::Core::AST::Node + def self.create_node(raw_node, lenv, use_result = true) while true case raw_node.type when :parentheses_node @@ -34,10 +34,10 @@ def self.create_node(raw_node, lenv) case raw_node.type # definition - when :statements_node then StatementsNode.new(raw_node, lenv) - when :module_node then ModuleNode.new(raw_node, lenv) - when :class_node then ClassNode.new(raw_node, lenv) - when :def_node then DefNode.new(raw_node, lenv) + when :statements_node then StatementsNode.new(raw_node, lenv, use_result) + when :module_node then ModuleNode.new(raw_node, lenv, use_result) + when :class_node then ClassNode.new(raw_node, lenv, use_result) + when :def_node then DefNode.new(raw_node, lenv, use_result) when :alias_method_node then AliasNode.new(raw_node, lenv) # control diff --git a/lib/typeprof/core/ast/base.rb b/lib/typeprof/core/ast/base.rb index 35cd1795..6a582512 100644 --- a/lib/typeprof/core/ast/base.rb +++ b/lib/typeprof/core/ast/base.rb @@ -20,6 +20,7 @@ def initialize(raw_node, lenv) def subnodes = {} def attrs = {} + #: { (TypeProf::Core::AST::Node) -> void } -> nil def each_subnode queue = subnodes.values @@ -196,7 +197,7 @@ def initialize(raw_node, lenv) @tbl = raw_node.locals raw_body = raw_node.statements - @body = AST.create_node(raw_body, lenv) + @body = AST.create_node(raw_body, lenv, false) end attr_reader :tbl, :body diff --git a/lib/typeprof/core/ast/method.rb b/lib/typeprof/core/ast/method.rb index 3f00abad..b7e43963 100644 --- a/lib/typeprof/core/ast/method.rb +++ b/lib/typeprof/core/ast/method.rb @@ -102,7 +102,7 @@ def self.parse_params(tbl, raw_args, lenv) end class DefNode < Node - def initialize(raw_node, lenv) + def initialize(raw_node, lenv, use_result) super(raw_node, lenv) singleton = !!raw_node.receiver mid = raw_node.name @@ -139,6 +139,10 @@ def initialize(raw_node, lenv) @rest_keywords = h[:rest_keywords] @block = h[:block] @args_code_ranges = h[:args_code_ranges] || [] + + # If the result of `def` statement, stop reusing this node + # TODO: `private def ...` should be handled well + @reusable = !use_result end attr_reader :singleton, :mid, :mid_code_range @@ -155,6 +159,7 @@ def initialize(raw_node, lenv) attr_reader :block attr_reader :body attr_reader :rbs_method_type + attr_reader :reusable def subnodes = { body:, @@ -175,17 +180,18 @@ def attrs = { opt_keywords:, rest_keywords:, block:, + reusable:, } def mname_code_range(_name) = @mid_code_range def define(genv) # NOT define0 - return define_copy(genv) if @prev_node + return define_copy(genv) if @prev_node && @reusable super(genv) end def install(genv) # NOT install0 - return install_copy(genv) if @prev_node + return install_copy(genv) if @prev_node && @reusable super(genv) end diff --git a/lib/typeprof/core/ast/misc.rb b/lib/typeprof/core/ast/misc.rb index 94e3c559..14204d1e 100644 --- a/lib/typeprof/core/ast/misc.rb +++ b/lib/typeprof/core/ast/misc.rb @@ -1,11 +1,12 @@ module TypeProf::Core class AST class StatementsNode < Node - def initialize(raw_node, lenv) + def initialize(raw_node, lenv, use_result) super(raw_node, lenv) - @stmts = raw_node.body.map do |n| + stmts = raw_node.body + @stmts = stmts.map.with_index do |n, i| if n - AST.create_node(n, lenv) + AST.create_node(n, lenv, i == stmts.length - 1 ? use_result : false) else last = code_range.last DummyNilNode.new(TypeProf::CodeRange.new(last, last), lenv) diff --git a/lib/typeprof/core/ast/module.rb b/lib/typeprof/core/ast/module.rb index ece63054..9e55aec0 100644 --- a/lib/typeprof/core/ast/module.rb +++ b/lib/typeprof/core/ast/module.rb @@ -1,7 +1,7 @@ module TypeProf::Core class AST class ModuleBaseNode < Node - def initialize(raw_node, lenv, raw_cpath, raw_scope) + def initialize(raw_node, lenv, raw_cpath, raw_scope, use_result) super(raw_node, lenv) @cpath = AST.create_node(raw_cpath, lenv) @@ -13,7 +13,7 @@ def initialize(raw_node, lenv, raw_cpath, raw_scope) if @static_cpath ncref = CRef.new(@static_cpath, true, nil, lenv.cref) nlenv = LocalEnv.new(@lenv.path, ncref, {}, []) - @body = raw_scope ? AST.create_node(raw_scope, nlenv) : DummyNilNode.new(code_range, lenv) + @body = raw_scope ? AST.create_node(raw_scope, nlenv, use_result) : DummyNilNode.new(code_range, lenv) else @body = nil end @@ -77,14 +77,14 @@ def modified_vars(tbl, vars) end class ModuleNode < ModuleBaseNode - def initialize(raw_node, lenv) - super(raw_node, lenv, raw_node.constant_path, raw_node.body) + def initialize(raw_node, lenv, use_result) + super(raw_node, lenv, raw_node.constant_path, raw_node.body, use_result) end end class ClassNode < ModuleBaseNode - def initialize(raw_node, lenv) - super(raw_node, lenv, raw_node.constant_path, raw_node.body) + def initialize(raw_node, lenv, use_result) + super(raw_node, lenv, raw_node.constant_path, raw_node.body, use_result) raw_superclass = raw_node.superclass @superclass_cpath = raw_superclass ? AST.create_node(raw_superclass, lenv) : nil end diff --git a/scenario/method/prevent-reuse.rb b/scenario/method/prevent-reuse.rb new file mode 100644 index 00000000..82d761b9 --- /dev/null +++ b/scenario/method/prevent-reuse.rb @@ -0,0 +1,13 @@ +## update: test.rb +class Foo + ary = + def foo + end +end + +## update: test.rb +class Foo + ary = + def foo + end +end