Class MultipleAssignmentSupport
These are called from generated bytecode only. User code should not rely on them.
- Since:
- 6.0.0
-
Method Summary
Modifier and TypeMethodDescriptionstatic ObjectnonTailRestSlice(Object rhs, int fromIndex, int toIndex) Resolve the value for a head or middle rest binding.static ObjectResolve the value for a tail rest binding (*t) at declarator indexfromIndex.
-
Method Details
-
tailRest
Resolve the value for a tail rest binding (*t) at declarator indexfromIndex. The GEP-20 dispatch model has three paths:- Path A —
Stream<T>: wrap the already-advanced iterator in a fresh sequential Stream and chainonCloseto 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-pathinstanceofbranches forList,CharSequence, and Java arrays (size-aware so out-of-boundsfromIndexreturns the canonical empty value without calling user code), with an MOP-dispatched fallback for any other Path B receiver —BitSet(returnsBitSet), user custom classes, etc. - Path C — anything else iterable: return the already-advanced iterator.
The actual
instanceofchecks 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 ofStream<T>and therefore fall through to Path B (if they exposegetAt(IntRange)) or Path C; their elements are boxed by the underlying iterator.- Parameters:
rhs- the original RHS valuefromIndex- the declarator position of the rest bindingseq- the iterator that has already yielded the preceding fixed-slot values
- Path A —
-
nonTailRestSlice
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-reversinggetAt(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 withMissingMethodException— preventing silent materialisation of unbounded sources. StreamRHS resolvesStreamGroovyMethods.getAt(Stream, IntRange), which rejects the destructuring slice's reverse range withIllegalArgumentException("reverse range")— also fail-fast, also no materialisation. (Head/middle rest fromStreamis 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 valuefromIndex- positive index where the slice beginstoIndex- negative index where the slice ends (inclusive)
- Truly non-indexable sources (iterators, sets, custom Iterables without a
-