LoweringEq

scalus.compiler.sir.lowering.LoweringEq
object LoweringEq

Equality lowering — recognizes equalsRepr(a, b) (and the FunctionalInterface Eq path) and emits the most efficient comparison for the lhs/rhs representation pair.

Dispatch order in generateEqualsForRepr:

  • Primitives (Integer, ByteString, String): specialized builtins
  • BLS curve elements: bls12_381_G1/G2_equal
  • BLS MlResult, Fun: compile error (no equality)
  • @UplcRepr(UplcConstr) products: field-by-field via generateProdUplcConstrEquals
  • @UplcRepr(UplcConstr) sums: native letrec via generateSumUplcConstrEquals
  • Everything else: convert to Data, equalsData

Attributes

Graph
Supertypes
class Object
trait Matchable
class Any
Self type
LoweringEq.type

Members list

Value members

Concrete methods

Generate equalsData after converting both values to their Data representation.

Generate equalsData after converting both values to their Data representation.

Attributes

Generate repr-specific equality comparison.

Generate repr-specific equality comparison.

Dispatches based on resolved type and representation; see LoweringEq doc for the dispatch order.

Attributes

Generate Case-based field comparison for ProdUplcConstr values. Each field is extracted via genSelect and compared recursively.

Generate Case-based field comparison for ProdUplcConstr values. Each field is extracted via genSelect and compared recursively.

Value parameters

knownType

concrete type for field extraction (may differ from lhs.sirType when lhs has TypeVar type but the concrete type is known from annotation)

Attributes

Native equality for SumUplcConstr-represented values.

Native equality for SumUplcConstr-represented values.

Emits letrec eqSum(a, b) = case a of ... where each variant branch matches b against the same variant tag (returning False on mismatch) and ANDs field comparisons. For fields whose substituted type matches the outer sum type, the recursive eqSum reference is used instead of recursing into a fresh generateEqualsForRepr (which would emit a duplicate letrec for self-referential types like List).

For non-recursive sums (e.g., Option) the letrec is harmless overhead — the function never references itself.

Attributes

def isEqIntrinsicApp(app: Apply): Boolean

Check if this is a fully-applied FunctionalInterface call with known Eq semantics.

Check if this is a fully-applied FunctionalInterface call with known Eq semantics.

Attributes

def isEqualsReprApp(app: Apply): Boolean

Check if this is equalsRepr(a, b) — the outer Apply of curried application. Handles both Apply(Apply(ExternalVar, a), b) and Apply(Apply(TypeApply(ExternalVar, A), a), b) (when type parameter is present).

Check if this is equalsRepr(a, b) — the outer Apply of curried application. Handles both Apply(Apply(ExternalVar, a), b) and Apply(Apply(TypeApply(ExternalVar, A), a), b) (when type parameter is present).

Attributes

Lower an Eq application using repr-specific equality.

Lower an Eq application using repr-specific equality.

The plugin annotates Apply nodes for FunctionalInterface types with "functionalInterfaceType". For Eq, we always inline an optimal comparison based on the argument representation instead of calling the Eq function. This is sound because every Eq instance is structurally consistent (a === b iff a.toData == b.toData) by construction: the compiler plugin rejects hand-written Eq lambdas at creation, so an instance can only come from Eq.derived (structural by generation) or Eq.structural(...) (an explicit assertion of structurality by the author). Non-structural types are excluded from the Eq system entirely (see RationalEq/AssocMapEq), and the non-structural combinators (Eq.by/orElse/orElseBy) are rejected in on-chain code (audit 2026-07-10 I1).

Attributes

Lower equalsRepr(a, b) — picks the optimal comparison for the resolved types/reprs.

Lower equalsRepr(a, b) — picks the optimal comparison for the resolved types/reprs.

Attributes

Concrete fields

val EqTypeName: String
val EqualsReprName: String