Documentation

Strata.Transform.MonomorphizeProcedures

Monomorphize Procedures #

The MonomorphizeProcedures program transformation monomorphizes every polymorphic procedure so that no procedure's types mention type variables.

Where it runs #

This pass runs in corePipelinePhases immediately before typeCheckPhase (and therefore after CallElim in transformPipelinePhases). Two consequences of this position matter:

The subsequent typeCheckPhase then re-checks the now-monomorphic procedure against its opaque-typed signature, propagating the opaque types through the body.

How it works #

For each procedure whose header.typeArgs is x₁, …, xₖ:

  1. A fresh, globally-unique opaque type is minted per type parameter, named $__opaque_{procName}_{xᵢ}_N (the $__ prefix reserves the internal namespace so the name cannot collide with a user-declared type; the trailing _N is a fresh counter from the shared CoreGenState, guaranteeing uniqueness). Each becomes a nullary top-level type declaration type {name}; emitted immediately before the procedure.
  2. A type substitution mapping each xᵢ to its opaque nullary type constructor is applied to the whole procedure: input/output signatures, precondition and postcondition expressions, and every expression and local declaration type in the body (LExpr.applySubst for expression annotations, LMonoTy.subst for signature and declaration types).
  3. header.typeArgs is cleared, so the procedure is now monomorphic.

The statement-level substitution reuses the type checker's Core.Statement.subst (StatementType.lean, which in turn uses Command.subst and Lambda.LTy.subst). Only structured bodies are monomorphized: a CFG body is reported as an error.

Applying the type substitution #

The statement / command / declared-type substitution is the type checker's existing Core.Statement.subst (which uses Command.subst and Lambda.LTy.subst, in StatementType.lean / LTyUnify.lean). Here we only assemble the whole-procedure substitution on top of it.

Apply S to a whole procedure: its signature, spec clauses, and body, and clear header.typeArgs. Throws if the body is a CFG (unsupported). The body substitution reuses Statement.subst.

Equations
  • One or more equations did not get rendered due to their size.
Instances For

    The transformation #

    Monomorphize a single procedure. One fresh opaque type is minted per declared type parameter (header.typeArgs); the opaque type declarations are returned first, followed by the substituted procedure. A procedure with no type parameters is returned unchanged.

    Equations
    • One or more equations did not get rendered due to their size.
    Instances For

      Monomorphize every procedure in the program, introducing opaque types for the free type variables of each polymorphic procedure.

      Equations
      • One or more equations did not get rendered due to their size.
      Instances For

        CoreTransformM runner for MonomorphizeProcedures, suitable for use with Core.Transform.run. Reports whether any opaque type declaration was introduced (which happens iff some procedure was monomorphized).

        Equations
        Instances For

          Pipeline phase for MonomorphizeProcedures. Model-preserving: replacing an implicitly universally-quantified type variable with a fresh, arbitrary opaque type is universal generalization (∀-introduction), which preserves the proof obligation and introduces no spurious models.

          Equations
          Instances For