SumDispatch

scalus.compiler.sir.lowering.SumDispatch
object SumDispatch

Dispatch layer for sum-typed operations. Single entry point for Sum-side toRepresentation; routing typegens (DataConstrEmitter, SumCaseUplcConstr*, SumListEmitterCommon subclasses, plus the Prod typegens that delegate via ProdDispatch) extend the base SirTypeUplcGenerator only — they don't have toRepresentation at all, so direct calls are compile-time errors. See docs/local/claude/compiler/sum-prod-dispatch-design.md.

Attributes

Graph
Supertypes
class Object
trait Matchable
class Any
Self type

Members list

Type members

Classlikes

The scrutinee-repr-driven half of a sum match. A MatchScaffolding captures the Case-builtin shape and any pre-bound state derived from the scrutinee (e.g. an unpacked field-list var, a tag binding) — but it does NOT decide the result repr. assembleMatch calls assemble once it has the aligned branches and the chosen target repr.

The scrutinee-repr-driven half of a sum match. A MatchScaffolding captures the Case-builtin shape and any pre-bound state derived from the scrutinee (e.g. an unpacked field-list var, a tag binding) — but it does NOT decide the result repr. assembleMatch calls assemble once it has the aligned branches and the chosen target repr.

One scaffolding implementation per scrutinee repr (Term.Case for UplcConstr, CaseListLoweredValue for SumBuiltinList, …). The trait stays small so future per-repr emitters can implement it without pulling in the assembly machinery.

Attributes

Supertypes
class Object
trait Matchable
class Any

Value members

Concrete methods

def assembleMatch(scaffolding: MatchScaffolding, branches: Seq[LoweredValue], optTargetType: Option[SIRType], matchTp: SIRType, pos: SIRPosition)(using lctx: LoweringContext): LoweredValue

Branch-driven assembly. Universal across scrutinee reprs: upcasts each branch to the result type, runs the Phase-3b transparentSumUplcConstrAlignment override (or chooseCommonRepresentation as fallback) to pick the result repr, and asks the scaffolding to assemble the final value.

Branch-driven assembly. Universal across scrutinee reprs: upcasts each branch to the result type, runs the Phase-3b transparentSumUplcConstrAlignment override (or chooseCommonRepresentation as fallback) to pick the result repr, and asks the scaffolding to assemble the final value.

Attributes

def chooseConstrOutputEmitter(constr: Constr, loweredArgs: List[LoweredValue], optTargetType: Option[SIRType])(using lctx: LoweringContext): SirTypeUplcGenerator

Choose the typegen that should emit this Constr, considering both the static type and surrounding-arg/context cues. Centralizes the rules formerly in ConstrDispatcher.shouldDelegateToUplcConstr:

Choose the typegen that should emit this Constr, considering both the static type and surrounding-arg/context cues. Centralizes the rules formerly in ConstrDispatcher.shouldDelegateToUplcConstr:

  1. Parent sum's default representation is SumUplcConstr → use parent's gen.
  2. The constr is List/Option-shaped AND either: a. it's a List.Cons whose tail's actual representation is already SumUplcConstr (spine propagation), or b. lctx.inUplcConstrListScope == true (caller asked for native lists).
  3. Caller's optTargetType is @UplcRepr(UplcConstr)-annotated.

Returns the typegen to dispatch to; default is the static-type's own typegen.

Attributes

Pick the parent-sum repr that an upcastOne from input to targetType should produce — the "preserve concrete vs coerce to default" decision:

Pick the parent-sum repr that an upcastOne from input to targetType should produce — the "preserve concrete vs coerce to default" decision:

  • ProdUplcConstr input → overlay the variant onto buildSumUplcConstr(targetType) so concrete field reprs (e.g. Unwrapped element types that differ from the DataDecl's abstract defaults) survive the upcast. Avoids a Data round-trip that fails for abstract TypeVar fields in isolation. Fires unconditionally; don't gate on target's default repr.
  • SumUplcConstr input → keep the refined variant set as-is.
  • Same-shape sum input (SumBuiltinList, SumPairBuiltinList, PackedSumDataList, SumDataAssocMap) → keep input's parameterization (preserves element repr).
  • Otherwise → target's default repr.

Returns the parent-sum repr only. Each emitter still chooses the matching byte-level conversion (ProdDataList → SumBuiltinList, ProdDataConstr → DataConstr, etc.) before relabeling.

Attributes

def dispatchNil(constr: Constr, resolvedType: SIRType, optTargetType: Option[SIRType])(using lctx: LoweringContext): (SirTypeUplcGenerator, Constr)

Pick the type generator for a Nil constructor.

Pick the type generator for a Nil constructor.

Lowering.lowerSIR routes Nil straight to typeGenerator.genConstrLowered, bypassing chooseConstrOutputEmitter. So this path also has to apply the inUplcConstrListScope override (the rule that, pre-Phase-3a, the typegen- internal ConstrDispatcher.shouldDelegateToUplcConstr rule #4 supplied); without it, a Nil produced inside an UplcConstr-scoped intrinsic body whose surrounding target type is unannotated List[A] would emerge as SumBuiltinList, desyncing from match-branch SumUplcConstr reprs.

Returns (generator, effective-constr): effective-constr rewrites constr.tp to targetType when one is supplied so the generator sees the right type info for type-correct Nil emission.

Attributes

def genConstr(constr: Constr, loweredArgs: List[LoweredValue], optTargetType: Option[SIRType])(using lctx: LoweringContext): LoweredValue
def genMatch(matchData: Match, loweredScrutinee: LoweredValue, optTargetType: Option[SIRType])(using lctx: LoweringContext): LoweredValue

Representation-aware dispatch for sum-typed genMatch. The Case-builtin shape varies by loweredScrutinee.representation:

Representation-aware dispatch for sum-typed genMatch. The Case-builtin shape varies by loweredScrutinee.representation:

  • SumUplcConstr → tag-ordered Case via genMatchUplcConstr (the scrutinee's UPLC bytes are already a Constr(tag, fields) so branches index by tag directly).
  • DataConstr → Data-shape Case in DataConstrEmitter. genMatchDataConstr (unConstrData → tag/field-list → if/else chain, or Case on integer for V4+).
  • SumBuiltinList(elemRepr) → caseList-ordered Case via the element-repr-parameterized SumBuiltinListEmitter.genMatch.
  • PackedSumDataList → unpack to SumBuiltinList(<elem-default>), bind a fresh var, recurse.
  • TypeVarRepresentation(_) → relabel to the type's defaultTypeVarRepresentation and recurse.
  • everything else → fall back to the type-keyed typegen's genMatch (same routing as before this dispatcher existed).

Pre-Phase-4 this match lived inside DataConstrEmitter.genMatch (formerly SumCaseSirTypeGenerator) and the SumUplcConstr short-circuit lived in Lowering.lowerSIR; routing them through the dispatcher consolidates the choice.

Attributes

def genSelect(sel: Select, loweredScrutinee: LoweredValue)(using lctx: LoweringContext): LoweredValue
def transparentSumUplcConstrAlignment(branches: Seq[LoweredValue], resultType: SIRType, pos: SIRPosition)(using lctx: LoweringContext): Option[(SumUplcConstr, Seq[LoweredValue])]

Choose-and-align step for SumUplcConstr matches when any branch carries a (Sum|Prod)UplcConstr whose field reprs include a Transparent TypeVar. Returns Some((sumRepr, aligned)) when the override fires, None otherwise (caller should fall back to its own convergence — typically LoweredValue.chooseCommonRepresentation).

Choose-and-align step for SumUplcConstr matches when any branch carries a (Sum|Prod)UplcConstr whose field reprs include a Transparent TypeVar. Returns Some((sumRepr, aligned)) when the override fires, None otherwise (caller should fall back to its own convergence — typically LoweredValue.chooseCommonRepresentation).

The override fires because Transparent TypeVar fields cannot be folded to a Data-shaped repr — we must keep a SumUplcConstr shape and align branches structurally. Alignment: (Sum|Prod)UplcConstr branches and ErrorRepresentation stay as-is; others route through toRepresentation(sumRepr, pos) for Data→UplcConstr conversion.

The synthesized SumUplcConstr uses buildSumUplcConstr's default variants for tags without a matching branch puc; hand-rolled defaultRepresentation lookups would produce TypeVarRepresentation(Fixed) (because the DataDecl's A carries Fixed kind), which then leaks into downstream inference and surfaces as Fixed → Unwrapped aborts.

Attributes

def upcastOne(input: LoweredValue, targetType: SIRType, pos: SIRPosition)(using lctx: LoweringContext): LoweredValue