Package org.apache.groovy.contracts

# Class VariantSupport

java.lang.Object
org.apache.groovy.contracts.VariantSupport

public final class VariantSupport extends Object
Shared runtime support for `Decreases` termination measures, used by both the loop variant (`@Decreases` on a loop) and the recursion variant (`@Decreases` on a method, via `MethodVariantSupport`).

It is the single source of truth for what "strictly decreases and stays well-founded" means — a scalar `Comparable` (with a non-negative floor for `Number`s) or a `List` compared lexicographically — and for whether the check runs at all under the `-ea`/`-da` configuration. The comparison itself is violation-agnostic (`describeFailure(java.lang.Object, java.lang.Object)` returns a description rather than throwing) so each caller can raise the appropriate violation type.

Since:
  6.0.0

- ## Method Summary

  Modifier and Type
  Method
  Description
  `static void`
  `checkLoopVariant(Object prev, Object curr, String className)`
  Loop-variant entry point invoked from generated loop-body code: if enabled, verify `curr` strictly decreased from `prev` and stayed well-founded, throwing `LoopVariantViolation` otherwise.
  `static void`
  `checkLoopVariantEntry(Object curr, String className)`
  Loop-variant entry point for the first iteration of a loop, where no previous value exists to compare against: if enabled, verify a scalar `Number` measure is non-negative at loop entry (GROOVY-12128), throwing `LoopVariantViolation` otherwise.
  `static String`
  `describeFailure(Object prev, Object curr)`
  Describe how `curr` fails to be a valid strict, well-founded decrease from `prev`, or `null` if it is valid.
  `static boolean`
  `enabled(String className)`
  Whether termination-measure checks are enabled for `className` under the current `-ea`/`-da` configuration (a `null` class name uses the global default).

  ### Methods inherited from class java.lang.Object

  `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- ## Method Details

  - ### enabled

    public static boolean enabled(String className)
    Whether termination-measure checks are enabled for `className` under the current `-ea`/`-da` configuration (a `null` class name uses the global default). Mirrors how `@Requires`/`@Ensures` gate.
    Parameters:
      `className` - the enclosing class name, or `null` for the global default
    Returns:
      `true` if the check should run

  - ### describeFailure

    public static String describeFailure(Object prev, Object curr)
    Describe how `curr` fails to be a valid strict, well-founded decrease from `prev`, or `null` if it is valid. `List` measures are compared lexicographically.
    Parameters:
      `prev` - the measure before
      `curr` - the measure after
    Returns:
      a failure description suffix, or `null` if the decrease is valid

  - ### checkLoopVariant

    public static void checkLoopVariant(Object prev, Object curr, String className)
    Loop-variant entry point invoked from generated loop-body code: if enabled, verify `curr` strictly decreased from `prev` and stayed well-founded, throwing `LoopVariantViolation` otherwise.
    Parameters:
      `prev` - the variant before the iteration
      `curr` - the variant after the iteration
      `className` - the enclosing class name (for `-ea`/`-da` gating)

  - ### checkLoopVariantEntry

    public static void checkLoopVariantEntry(Object curr, String className)
    Loop-variant entry point for the first iteration of a loop, where no previous value exists to compare against: if enabled, verify a scalar `Number` measure is non-negative at loop entry (GROOVY-12128), throwing `LoopVariantViolation` otherwise. This mirrors the non-negative floor `describeFailure(java.lang.Object, java.lang.Object)` applies to every subsequent iteration-start value. `List` (lexicographic) measures have no single deciding component at entry, so they are not floor-checked here.
    Parameters:
      `curr` - the variant at first loop entry
      `className` - the enclosing class name (for `-ea`/`-da` gating)