MCPcopy Create free account
hub / github.com/MaterializeInc/materialize / inline_lets_core

Function inline_lets_core

src/transform/src/normalize_lets.rs:747–880  ·  view source on GitHub ↗

Considers inlining actions to perform for a sequence of bindings and a following body. A let binding may be inlined only in subsequent bindings or in the body; other bindings should not "immediately" observe the binding, as that would be a change to the semantics of `LetRec`. For example, it would not be correct to replace `C` with `A` in the definition of `B` here: ```ignore let A = ...; let B =

(
        expr: &mut MirRelationExpr,
        inline_mfp: bool,
    )

Source from the content-addressed store, hash-verified

745 /// be able to apply inlining due to ordering (we cannot inline a binding
746 /// into one that is not strictly later).
747 pub(super) fn inline_lets_core(
748 expr: &mut MirRelationExpr,
749 inline_mfp: bool,
750 ) -> Result<(), crate::TransformError> {
751 if let MirRelationExpr::LetRec {
752 ids,
753 values,
754 limits,
755 body,
756 } = expr
757 {
758 // Count the number of uses of each local id across all expressions.
759 let mut counts = BTreeMap::new();
760 for value in values.iter() {
761 super::support::count_local_id_uses(value, &mut counts);
762 }
763 super::support::count_local_id_uses(body, &mut counts);
764
765 // Each binding can reach one of three positions on its inlineability:
766 // 1. The binding is used once and is available to be directly taken.
767 // 2. The binding is simple enough that it can just be cloned.
768 // 3. The binding is not available for inlining.
769 let mut inline_offers = BTreeMap::new();
770
771 // Each binding may require the expiration of prior inlining offers.
772 // This occurs when an inlined body references the prior iterate of a binding,
773 // and inlining it would change the meaning to be the current iterate.
774 // Roughly, all inlining offers expire just after the binding of the least
775 // identifier they contain that is greater than the bound identifier itself.
776 let mut expire_offers = BTreeMap::new();
777 let mut expired_offers = Vec::new();
778
779 // For each binding, inline `Get`s and then determine if *it* should be inlined.
780 // It is important that we do the substitution in-order and before reasoning
781 // about the inlineability of each binding, to ensure that our conclusion about
782 // the inlineability of a binding stays put. Specifically,
783 // 1. by going in order no substitution will increase the `Get`-count of an
784 // identifier beyond one, as all in values with strictly greater identifiers.
785 // 2. by performing the substitution before reasoning, the structure of the value
786 // as it would be substituted is fixed.
787 for ((id, mut expr), max_iter) in ids
788 .drain(..)
789 .zip_eq(values.drain(..))
790 .zip_eq(limits.drain(..))
791 {
792 // Substitute any appropriate prior let bindings.
793 inline_lets_helper(&mut expr, &mut inline_offers)?;
794
795 // Determine the first `id'` at which any inlining offer must expire.
796 // An inlining offer expires because it references an `id'` that is not yet bound,
797 // indicating a reference to the *prior* iterate of that identifier. Inlining the
798 // expression once `id'` becomes bound would advance the reference to be the
799 // *current* iterate of the identifier.
800 MirRelationExpr::collect_expirations(id, &expr, &mut expire_offers);
801
802 // Gets for `id` only occur in later expressions, so this should still be correct.
803 let num_gets = counts.get(&id).map(|x| *x).unwrap_or(0);
804 // Counts of zero or one lead to substitution; otherwise certain simple structures

Callers 1

inline_letsFunction · 0.85

Calls 15

count_local_id_usesFunction · 0.85
inline_lets_helperFunction · 0.85
for_local_idFunction · 0.85
take_dangerousMethod · 0.80
iterMethod · 0.45
drainMethod · 0.45
mapMethod · 0.45
getMethod · 0.45
insertMethod · 0.45
extendMethod · 0.45
into_iterMethod · 0.45

Tested by

no test coverage detected