Skip to content

Fix type inference for multiple assignment of generic Array[T]#403

Merged
mame merged 1 commit intoruby:masterfrom
sekito1107:fix/masgn-generic-array-type-inference
Mar 2, 2026
Merged

Fix type inference for multiple assignment of generic Array[T]#403
mame merged 1 commit intoruby:masterfrom
sekito1107:fix/masgn-generic-array-type-inference

Conversation

@sekito1107
Copy link
Contributor

Problem

Previously, multiple assignment from instances of generic arrays (e.g., Array[Integer] defined in RBS) resulted in incorrect type inference. MAsgnBox#run0 only handled literal Type::Array correctly. For other types, it assigned the entire array object to the first variable on the left-hand side, leaving others as untyped.

Example

# sig: def get_ints: -> Array[Integer]
a, b = get_ints 
# Before: a: Array[Integer] (the array itself), b: untyped
# After:  a: Integer, b: Integer

Fix

Handled Type::Instance with mod_ary in MAsgnBox#run0 by distributing its element type (ty.args[0]) to all left-hand side variables and the rest element.

Changes

  • Update lib/typeprof/core/graph/box.rb to handle Type::Instance in MAsgnBox#run0.
  • Add scenario/variable/masgn-generic-array.rb as a regression test.

How to reproduce

Save the following as repro.rb in the typeprof root and run with ruby -Ilib repro.rb

Note:
In repro.rb, update_rbs_file, and update_rb_file are called twice. I observed that this was necessary to correctly trigger the type inference in this standalone script (possibly related to the diff-based analysis). If this is not the recommended way to use the internal API, please let me know with your advice.

require "typeprof"

core = TypeProf::Core::Service.new({})

rbs = <<~RBS
  class Foo
    def get_ints: () -> Array[Integer]
  end
RBS

rb = <<~RUBY
  class Foo
    def test_masgn
      a, b, c = get_ints
      [a, b, c]
    end
    def test_star
      a, *rest = get_ints
      [a, rest]
    end
  end
RUBY

2.times { core.update_rbs_file("test.rbs", rbs) }
2.times { core.update_rb_file("test.rb", rb) }

puts core.dump_declarations("test.rb")

Output without fix

class Foo
  def test_masgn: -> [Array[Integer], untyped, untyped]
  def test_star: -> [Array[Integer], Array[untyped]]
end

Output with fix

class Foo
  def test_masgn: -> [Integer, Integer, Integer]
  def test_star: -> [Integer, Array[Integer]]
end

Handle Type::Instance (e.g. from RBS Array[T]) in MAsgnBox#run0 by
distributing the element type to variables.

Previously, only Type::Array (literal arrays) was handled correctly.
For other types, it assigned the entire array object to the first variable
on the left-hand side, leaving subsequent variables as untyped.
Copy link
Member

@mame mame left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! (I had just made a similar patch in my working copy a few days ago :-)

@mame mame merged commit f9e67e6 into ruby:master Mar 2, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants