From 25a15d40364bfb65f211554a0dc380a657ba7e5b Mon Sep 17 00:00:00 2001 From: pvcresin Date: Sat, 22 Nov 2025 13:38:56 +0000 Subject: [PATCH 1/2] Fix crash in multiple Hash#merge! calls due to duplicate graph edges --- lib/typeprof/core/graph/vertex.rb | 2 ++ scenario/regressions/hash-merge-bang.rb | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 scenario/regressions/hash-merge-bang.rb diff --git a/lib/typeprof/core/graph/vertex.rb b/lib/typeprof/core/graph/vertex.rb index a6e2a416..33a61c7f 100644 --- a/lib/typeprof/core/graph/vertex.rb +++ b/lib/typeprof/core/graph/vertex.rb @@ -188,11 +188,13 @@ def new_vertex(genv, origin) end def add_edge(genv, nvtx) + return if @next_vtxs.include?(nvtx) @next_vtxs << nvtx nvtx.on_type_added(genv, self, @types.keys) unless @types.empty? end def remove_edge(genv, nvtx) + return unless @next_vtxs.include?(nvtx) @next_vtxs.delete(nvtx) || raise nvtx.on_type_removed(genv, self, @types.keys) unless @types.empty? end diff --git a/scenario/regressions/hash-merge-bang.rb b/scenario/regressions/hash-merge-bang.rb new file mode 100644 index 00000000..364f66f3 --- /dev/null +++ b/scenario/regressions/hash-merge-bang.rb @@ -0,0 +1,22 @@ +## update +def option + { a: 1 } +end + +def foo1 + option.merge!(bar) +end + +def foo2 + option.merge!(bar) +end + +def bar = {} + +## assert +class Object + def option: -> Hash[:a, Integer] + def foo1: -> Hash[:a, Integer] + def foo2: -> Hash[:a, Integer] + def bar: -> Hash[untyped, untyped] +end From 739d8774d161c9fe21cd96e0c7aabe796343b145 Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Wed, 3 Dec 2025 18:00:27 +0900 Subject: [PATCH 2/2] Fix the previous issue by `new_vertex` instead of duplication check --- lib/typeprof/core/ast/sig_type.rb | 2 +- lib/typeprof/core/graph/vertex.rb | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/typeprof/core/ast/sig_type.rb b/lib/typeprof/core/ast/sig_type.rb index f48da01d..c400d916 100644 --- a/lib/typeprof/core/ast/sig_type.rb +++ b/lib/typeprof/core/ast/sig_type.rb @@ -826,7 +826,7 @@ def contravariant_vertex0(genv, changes, vtx, subst) end def typecheck(genv, changes, vtx, subst) - changes.add_edge(genv, vtx, subst[@var]) unless vtx == subst[@var] + changes.add_edge(genv, vtx.new_vertex(genv, self), subst[@var]) unless vtx == subst[@var] true end diff --git a/lib/typeprof/core/graph/vertex.rb b/lib/typeprof/core/graph/vertex.rb index 33a61c7f..a6e2a416 100644 --- a/lib/typeprof/core/graph/vertex.rb +++ b/lib/typeprof/core/graph/vertex.rb @@ -188,13 +188,11 @@ def new_vertex(genv, origin) end def add_edge(genv, nvtx) - return if @next_vtxs.include?(nvtx) @next_vtxs << nvtx nvtx.on_type_added(genv, self, @types.keys) unless @types.empty? end def remove_edge(genv, nvtx) - return unless @next_vtxs.include?(nvtx) @next_vtxs.delete(nvtx) || raise nvtx.on_type_removed(genv, self, @types.keys) unless @types.empty? end