IntrinsicResolver

scalus.compiler.sir.lowering.IntrinsicResolver

Resolves intrinsic implementations for method calls based on argument representation and protocol version.

When the lowering encounters a method call like list.isEmpty, the resolver checks if there is an optimized intrinsic implementation for the argument's runtime representation (e.g., SumDataList). If found, it substitutes the provider's body (with the actual argument SIR) and re-lowers it. Already-lowered arguments are tracked via the annotation-keyed argCache mechanism (see LoweringContext.argCache), so re-lowering the substituted SIR returns the pre-lowered value without recomputation.

The registry is hardcoded — adding new intrinsic providers requires editing the registry and creating the @Compile provider object.

Attributes

Graph
Supertypes
class Object
trait Matchable
class Any
Self type

Members list

Value members

Concrete methods

def countTopLambdas(sir: SIR): Int
def defaultIntrinsicModules: Map[String, Module]

Default intrinsic modules, loaded at compile time by the plugin. The plugin intercepts compiledModules(...) and replaces it with SIRLinker.readModules(...) that accesses the objects' sirModule vals.

Default intrinsic modules, loaded at compile time by the plugin. The plugin intercepts compiledModules(...) and replaces it with SIRLinker.readModules(...) that accesses the objects' sirModule vals.

Attributes

def defaultSupportModules: Map[String, Module]

Support modules — bindings resolved on demand when referenced from intrinsic bodies. Unlike intrinsic modules, these are NOT used for provider substitution.

Support modules — bindings resolved on demand when referenced from intrinsic bodies. Unlike intrinsic modules, these are NOT used for provider substitution.

Methods that need a non-default TypeVar kind carry author-written @UplcRepr(TypeVar(...)) annotations on their type parameters, so no blanket post-load stamping is needed. NativeListOperations.find is intentionally left unannotated (loads with default Fixed) — its Option.None/Option.Some if-then-else body has a known interaction with Constr emission that the annotation path doesn't yet handle (see its scaladoc for details). For HO methods that take pre-compiled functions (like contains with Eq), the dispatcher wraps the HO function with representation conversion adapters.

Attributes

def gatherApplyChain(sir: SIR): Option[(SIR, List[SIR])]

Try to resolve an intrinsic for the given application.

Try to resolve an intrinsic for the given application.

Called after lowering the argument. Uses the already-lowered arg's representation to decide whether an intrinsic applies. If found, caches the lowered arg, substitutes at the SIR level, re-lowers, and removes the cache entry.

Value parameters

appType

the SIR type of the application result

argSir

the original SIR argument node (used for substitution and as cache key)

f

the function being applied (Var or ExternalVar with qualified name)

loweredArg

the already-lowered argument (cached to avoid recomputation)

pos

source position

Attributes

Returns

Some(LoweredValue) if an intrinsic was applied, None otherwise

def isIntrinsicDispatchedModule(moduleName: String): Boolean

Modules whose ExternalVar references should have their type-signature TypeLambda TypeVars rewritten to Transparent. These target modules are dispatched by the intrinsic resolver to providers whose TypeVars are already Transparent (see defaultIntrinsicModules post-processing) and whose HO arguments (like eq, ord) are wrapped with toDefaultTypeVarRepr inside the provider body. The Scala plugin stamps Fixed on all user-code types, so without this rewrite Fixed leaks into the SIR tree and downstream representation inference treats native lists as Data-encoded, causing runtime mismatches (e.g., unConstrData applied to a native Constr).

Modules whose ExternalVar references should have their type-signature TypeLambda TypeVars rewritten to Transparent. These target modules are dispatched by the intrinsic resolver to providers whose TypeVars are already Transparent (see defaultIntrinsicModules post-processing) and whose HO arguments (like eq, ord) are wrapped with toDefaultTypeVarRepr inside the provider body. The Scala plugin stamps Fixed on all user-code types, so without this rewrite Fixed leaks into the SIR tree and downstream representation inference treats native lists as Data-encoded, causing runtime mismatches (e.g., unConstrData applied to a native Constr).

Attributes

def isUplcConstrListOrOption(tp: SIRType): Boolean

True if tp (after peeling TypeLambda / TypeProxy / Annotated) is a scalus.cardano.onchain.plutus.prelude.List or Option.

True if tp (after peeling TypeLambda / TypeProxy / Annotated) is a scalus.cardano.onchain.plutus.prelude.List or Option.

Used by IntrinsicResolver.tryResolve / tryResolveFull to detect dispatcher boundaries where inUplcConstrListScope should be flipped while selecting the native-Constr provider binding. LoweringContext.typeGenerator no longer consults the flag (annotation- driven), so the only remaining effect is provider selection inside the resolver.

Attributes

def tryResolve(f: SIR, argSir: SIR, loweredArg: LoweredValue, appType: SIRType, pos: SIRPosition)(using lctx: LoweringContext): Option[LoweredValue]
def tryResolveFull(head: SIR, argSirs0: List[SIR], loweredArgs: List[LoweredValue], appType: SIRType, pos: SIRPosition)(using lctx: LoweringContext): Option[LoweredValue]

Concrete fields

val ArgCacheAnnotKey: String

Annotation key on SIR.Var to signal that the var should be resolved via lctx.argCache(idx) instead of normal scope lookup. The annotation value is SIR.Const(scalus.uplc.Constant.Integer(idx)). Used by substituteSelf to substitute lambda parameters with annotated Var references, so subsequent substitution-walks (which create fresh SIR.Var instances) preserve the cache key in the new annotations.

Annotation key on SIR.Var to signal that the var should be resolved via lctx.argCache(idx) instead of normal scope lookup. The annotation value is SIR.Const(scalus.uplc.Constant.Integer(idx)). Used by substituteSelf to substitute lambda parameters with annotated Var references, so subsequent substitution-walks (which create fresh SIR.Var instances) preserve the cache key in the new annotations.

Attributes