From cbc2c1a113618de931471b96b8be20bb4bf7d9f9 Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Mon, 28 Sep 2026 21:24:47 +0900 Subject: [PATCH] Re-run the calls of Struct.[] when its builtin is set or removed Struct.[] is a builtin set on the method entity rather than a method definition, and assigning a builtin does not notify the calls that depend on the entity. After editing `Pt = Struct.new(:x, :y)` into `Pt = Data.define(:x, :y)`, `Pt[1, 2]` still used the removed builtin and reported "wrong number of arguments (2 for 0)" instead of an undefined method. Co-Authored-By: Claude Opus 5.5 --- lib/typeprof/core/ast/meta.rb | 11 +++++-- scenario/incremental/struct-aref-to-data.rb | 35 +++++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 scenario/incremental/struct-aref-to-data.rb diff --git a/lib/typeprof/core/ast/meta.rb b/lib/typeprof/core/ast/meta.rb index f3c2ff69..2a6be0f6 100644 --- a/lib/typeprof/core/ast/meta.rb +++ b/lib/typeprof/core/ast/meta.rb @@ -326,7 +326,12 @@ def define0(genv) end if @kind == :struct # Struct.[] calls the receiver's initialize, like Class#new - genv.resolve_method(struct_base_cpath, true, :[]).builtin = Builtin.new(genv).method(:class_new) + me = genv.resolve_method(struct_base_cpath, true, :[]) + unless me.builtin + me.builtin = Builtin.new(genv).method(:class_new) + # Unlike a method definition, a builtin does not notify the calls itself + me.add_run_all_method_call_boxes(genv) + end end @block_body.define(genv) if @block_body cdef @@ -358,7 +363,9 @@ def undefine0(genv) end # On an update, the new node has already set the builtin if base.module_defs.to_a.none? { _1.kind == :struct } - genv.resolve_method(struct_base_cpath, true, :[]).builtin = nil + me = genv.resolve_method(struct_base_cpath, true, :[]) + me.builtin = nil + me.add_run_all_method_call_boxes(genv) end @block_body.undefine(genv) if @block_body end diff --git a/scenario/incremental/struct-aref-to-data.rb b/scenario/incremental/struct-aref-to-data.rb new file mode 100644 index 00000000..6d45c040 --- /dev/null +++ b/scenario/incremental/struct-aref-to-data.rb @@ -0,0 +1,35 @@ +## update +Pt = Struct.new(:x, :y) +def f = Pt[1, 2] + +## diagnostics + +## assert +class Pt + def x: -> Integer + def x=: (untyped) -> untyped + def y: -> Integer + def y=: (untyped) -> untyped + def initialize: (?Integer, ?Integer) -> void + def self.[]: (?Integer, ?Integer) -> Pt +end +class Object + def f: -> Pt +end + +## update +Pt = Data.define(:x, :y) +def f = Pt[1, 2] + +## diagnostics +(2,10)-(2,16): undefined method: singleton(Pt)#[] + +## assert +class Pt + def x: -> untyped + def y: -> untyped + def initialize: (x: untyped, y: untyped) -> void +end +class Object + def f: -> untyped +end