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

Method action

src/transform/src/normalize_lets.rs:98–190  ·  view source on GitHub ↗

Normalize `Let` and `LetRec` bindings in `relation`. Mechanically, `action` first renumbers all bindings, erroring if any shadowing is encountered. It then promotes all `Let` and `LetRec` expressions to the roots of their expressions, fusing `Let` bindings into containing `LetRec` bindings, but leaving stacked `LetRec` bindings unfused to each other (for reasons of correctness). It then considers

(
        &self,
        relation: &mut MirRelationExpr,
        features: &OptimizerFeatures,
    )

Source from the content-addressed store, hash-verified

96 ///
97 /// We then perform a final renumbering.
98 pub fn action(
99 &self,
100 relation: &mut MirRelationExpr,
101 features: &OptimizerFeatures,
102 ) -> Result<(), crate::TransformError> {
103 // Record whether the relation was initially recursive, to confirm that we do not introduce
104 // recursion to a non-recursive expression.
105 let was_recursive = relation.is_recursive();
106
107 // Renumber all bindings to ensure that identifier order matches binding order.
108 // In particular, as we use `BTreeMap` for binding order, we want to ensure that
109 // 1. Bindings within a `LetRec` are assigned increasing identifiers, and
110 // 2. Bindings across `LetRec`s are assigned identifiers in "visibility order", corresponding to an
111 // in-order traversal.
112 // TODO: More can and perhaps should be said about "visibility order" and how let promotion is correct.
113 renumbering::renumber_bindings(relation, &mut IdGen::default())?;
114
115 // Promote all `Let` and `LetRec` AST nodes to the roots.
116 // After this, all non-`LetRec` nodes contain no further `Let` or `LetRec` nodes,
117 // placing all `LetRec` nodes around the root, if not always in a single AST node.
118 let_motion::promote_let_rec(relation);
119 let_motion::assert_no_lets(relation);
120 let_motion::assert_letrec_major(relation);
121
122 // Inlining may violate letrec-major form.
123 inlining::inline_lets(relation, self.inline_mfp)?;
124
125 // Return to letrec-major form to refresh types.
126 let_motion::promote_let_rec(relation);
127 support::refresh_types(relation, features)?;
128
129 // Renumber bindings for good measure.
130 // Ideally we could skip when `action` is a no-op, but hard to thread that through at the moment.
131 renumbering::renumber_bindings(relation, &mut IdGen::default())?;
132
133 // A final bottom-up traversal to normalize the shape of nested LetRec blocks
134 relation.try_visit_mut_post(&mut |relation| -> Result<(), RecursionLimitError> {
135 // Move a non-recursive suffix of bindings from the end of the LetRec
136 // to the LetRec body.
137 // This is unsafe when applied to expressions which contain `ArrangeBy`,
138 // as if the extracted suffixes reference arrangements they will not be
139 // able to access those arrangements from outside the `LetRec` scope.
140 // It happens to work at the moment, so we don't touch it but should fix.
141 let bindings = let_motion::harvest_nonrec_suffix(relation)?;
142 if let MirRelationExpr::LetRec {
143 ids: _,
144 values: _,
145 limits: _,
146 body,
147 } = relation
148 {
149 for (id, value) in bindings.into_iter().rev() {
150 **body = MirRelationExpr::Let {
151 id,
152 value: Box::new(value),
153 body: Box::new(body.take_dangerous()),
154 };
155 }

Callers 2

normalize_letsFunction · 0.45

Calls 13

renumber_bindingsFunction · 0.85
promote_let_recFunction · 0.85
assert_no_letsFunction · 0.85
assert_letrec_majorFunction · 0.85
inline_letsFunction · 0.85
refresh_typesFunction · 0.85
harvest_nonrec_suffixFunction · 0.85
harvest_non_recursiveFunction · 0.85
try_visit_mut_postMethod · 0.80
take_dangerousMethod · 0.80
is_recursiveMethod · 0.45
into_iterMethod · 0.45

Tested by

no test coverage detected