Package: org.codehaus.groovy.runtime

## [Java] Class MultipleAssignmentSupport

- org.codehaus.groovy.runtime.MultipleAssignmentSupport

-     @GroovyABI(since = "6.0.0")
      public final class MultipleAssignmentSupport
      extends Object

  Runtime helpers used by the GEP-20 multi-assignment destructuring bytecode.

  These are called from generated bytecode only. User code should not rely on them.

  Since:
    6.0.0

- - ### Methods Summary

    Methods
    Type Params | Return Type | Name and description
    --- | --- | ---
    `` | `public static Object` | `nonTailRestSlice(Object rhs, int fromIndex, int toIndex)` Resolve the value for a head or middle rest binding.
    `` | `public static Object` | `tailRest(Object rhs, int fromIndex, Iterator<?> seq)` Resolve the value for a tail rest binding (`*t`) at declarator index `fromIndex`.

  - ### Inherited Methods Summary

    Inherited Methods
    Methods inherited from class | Name
    --- | ---
    `class Object` | `equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- - ### Method Detail

    - #### public static Object nonTailRestSlice(Object rhs, int fromIndex, int toIndex)

      Resolve the value for a head or middle rest binding. Requires a sized, indexable RHS (List, CharSequence, or array — or any other receiver with a non-reversing `getAt(IntRange)`); for other RHS types this routes through the MOP so that:

      - Truly non-indexable sources (iterators, sets, custom Iterables without a `getAt(IntRange)` extension) fail fast with `MissingMethodException` — preventing silent materialisation of unbounded sources.
      - `Stream` RHS resolves `StreamGroovyMethods.getAt(Stream, IntRange)`, which rejects the destructuring slice's reverse range with `IllegalArgumentException("reverse range")` — also fail-fast, also no materialisation. (Head/middle rest from `Stream` is rejected at compile time under `@CompileStatic`; the IAE only surfaces in dynamic mode.)

      When the RHS is shorter than the sum of fixed slots around the rest, the computed range is inverted. DGM's `getAt(IntRange)` would reverse an inverted range; for destructuring we want an empty slice instead, so this helper short-circuits that case for the sized fast paths (List/CharSequence/array). Other indexable receivers are responsible for their own bounds handling.

      Parameters:
        `rhs` - the original RHS value
        `fromIndex` - positive index where the slice begins
        `toIndex` - negative index where the slice ends (inclusive)

    - #### public static Object tailRest(Object rhs, int fromIndex, Iterator<?> seq)

      Resolve the value for a tail rest binding (`*t`) at declarator index `fromIndex`. The GEP-20 dispatch model has three paths:

      - Path A — `Stream<T>`: wrap the already-advanced iterator in a fresh sequential Stream and chain `onClose` to the original. The new Stream reports no spliterator characteristics (preserving them would require reading the original spliterator, which is mutually exclusive with the iterator path used for head extraction).
      - Path B — receiver with a resolvable `getAt(IntRange)`. Implemented as fast-path `instanceof` branches for `List`, `CharSequence`, and Java arrays (size-aware so out-of-bounds `fromIndex` returns the canonical empty value without calling user code), with an MOP-dispatched fallback for any other Path B receiver — BitSet (returns `BitSet`), user custom classes, etc.
      - Path C — anything else iterable: return the already-advanced iterator.

      The actual `instanceof` checks are ordered for performance (List/CharSequence/array fast paths first, then Stream, then MOP fallback, then iterator) but the conceptual dispatch order is A, then B, then C.

      Primitive streams (`IntStream`, `LongStream`, `DoubleStream`) are not subtypes of `Stream<T>` and therefore fall through to Path B (if they expose `getAt(IntRange)`) or Path C; their elements are boxed by the underlying iterator.

      Parameters:
        `rhs` - the original RHS value
        `fromIndex` - the declarator position of the rest binding
        `seq` - the iterator that has already yielded the preceding fixed-slot values