Struct Inlining

Source
pub struct Inlining<'a> { /* private fields */ }
Expand description

This pass performs the following transformations on a Program:

  • Monomorphizing and inlining evaluators/functions at their call sites
  • Unrolling constraint comprehensions into a sequence of scalar constraints
  • Unrolling list comprehensions into a tree of let statements which end in a vector expression (the implicit result of the tree). Each iteration of the unrolled comprehension is reified as a value and bound to a variable so that other transformations may refer to it directly.
  • Rewriting aliases of top-level declarations to refer to those declarations directly
  • Removing let-bound variables which are unused, which is also used to clean up after the aliasing rewrite mentioned above.

The trickiest transformation comes with inlining the body of evaluators at their call sites, as evaluator parameter lists can arbitrarily destructure/regroup columns provided as arguments for each trace segment. This means that columns can be passed in a variety of configurations as arguments, and the patterns expressed in the evaluator parameter list can arbitrarily reconfigure them for use in the evaluator body.

For example, let’s say you call an evaluator foo with three columns, passed as individual bindings, like so: foo([a, b, c]). Let’s further assume that the evaluator signature is defined as ev foo([x[2], y]). While you might expect that this would be an error, and that the caller would need to provide the columns in the same configuration, that is not the case. Instead, a and b are implicitly re-bound as a vector of trace column bindings for use in the function body. There is further no requirement that a and b are consecutive bindings either, as long as they are from the same trace segment. During compilation however, accesses to individual elements of the vector will be rewritten to use the correct binding in the caller after inlining, e.g. an access like x[1] becomes b.

This pass accomplishes three goals:

  • Remove all function abstractions from the program
  • Remove all comprehensions from the program
  • Inline all constraints into the integrity and boundary constraints sections
  • Make all references to top-level declarations concrete

When done, it should be impossible for there to be any invalid trace column references.

It is expected that the provided Program has already been run through semantic analysis and constant propagation, so a number of assumptions are made with regard to what syntax can be observed at this stage of compilation (e.g. no references to constant declarations, no undefined variables, expressions are well-typed, etc.).

Implementations§

Source§

impl<'a> Inlining<'a>

Source

pub fn new(diagnostics: &'a DiagnosticsHandler) -> Inlining<'a>

Trait Implementations§

Source§

impl<'p> Pass for Inlining<'p>

Source§

type Input<'a> = Program

Source§

type Output<'a> = Program

Source§

type Error = SemanticAnalysisError

Source§

fn run<'a>( &mut self, program: <Inlining<'p> as Pass>::Input<'a>, ) -> Result<<Inlining<'p> as Pass>::Output<'a>, <Inlining<'p> as Pass>::Error>

Runs the pass on the given input Read more
Source§

fn chain<P, E>(self, pass: P) -> Chain<Self, P>
where Self: Sized, E: From<Self::Error>, P: for<'a> Pass<Input<'a> = Self::Output<'a>, Error = E>,

Chains two passes together to form a new, fused pass

Auto Trait Implementations§

§

impl<'a> Freeze for Inlining<'a>

§

impl<'a> !RefUnwindSafe for Inlining<'a>

§

impl<'a> Send for Inlining<'a>

§

impl<'a> Sync for Inlining<'a>

§

impl<'a> Unpin for Inlining<'a>

§

impl<'a> !UnwindSafe for Inlining<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.