Enum mz_expr::scalar::MirScalarExpr
source · pub enum MirScalarExpr {
Column(usize),
Literal(Result<Row, EvalError>, ColumnType),
CallUnmaterializable(UnmaterializableFunc),
CallUnary {
func: UnaryFunc,
expr: Box<MirScalarExpr>,
},
CallBinary {
func: BinaryFunc,
expr1: Box<MirScalarExpr>,
expr2: Box<MirScalarExpr>,
},
CallVariadic {
func: VariadicFunc,
exprs: Vec<MirScalarExpr>,
},
If {
cond: Box<MirScalarExpr>,
then: Box<MirScalarExpr>,
els: Box<MirScalarExpr>,
},
}
Variants§
Column(usize)
A column of the input row
Literal(Result<Row, EvalError>, ColumnType)
A literal value. (Stored as a row, because we can’t own a Datum)
CallUnmaterializable(UnmaterializableFunc)
A call to an unmaterializable function.
These functions cannot be evaluated by MirScalarExpr::eval
. They must
be transformed away by a higher layer.
CallUnary
A function call that takes one expression as an argument.
CallBinary
A function call that takes two expressions as arguments.
CallVariadic
A function call that takes an arbitrary number of arguments.
If
Conditionally evaluated expressions.
It is important that then
and els
only be evaluated if
cond
is true or not, respectively. This is the only way
users can guard execution (other logical operator do not
short-circuit) and we need to preserve that.
Implementations§
source§impl MirScalarExpr
impl MirScalarExpr
pub fn columns(is: &[usize]) -> Vec<MirScalarExpr>
pub fn column(column: usize) -> Self
pub fn literal(res: Result<Datum<'_>, EvalError>, typ: ScalarType) -> Self
pub fn literal_ok(datum: Datum<'_>, typ: ScalarType) -> Self
pub fn literal_null(typ: ScalarType) -> Self
pub fn literal_false() -> Self
pub fn literal_true() -> Self
pub fn call_unary(self, func: UnaryFunc) -> Self
pub fn call_binary(self, other: Self, func: BinaryFunc) -> Self
pub fn if_then_else(self, t: Self, f: Self) -> Self
pub fn or(self, other: Self) -> Self
pub fn and(self, other: Self) -> Self
pub fn not(self) -> Self
pub fn call_is_null(self) -> Self
sourcepub fn and_or_args(&self, func_to_match: VariadicFunc) -> Vec<MirScalarExpr>
pub fn and_or_args(&self, func_to_match: VariadicFunc) -> Vec<MirScalarExpr>
Match AND or OR on self and get the args. If no match, then interpret self as if it were wrapped in a 1-arg AND/OR.
sourcepub fn expr_eq_literal(&self, expr: &MirScalarExpr) -> Option<(Row, bool)>
pub fn expr_eq_literal(&self, expr: &MirScalarExpr) -> Option<(Row, bool)>
Try to match a literal equality involving the given expression on one side. Return the (non-null) literal and a bool that indicates whether an inversion was needed.
More specifically:
If self
is an equality with a null
literal on any side, then the match fails!
Otherwise: for a given expr
, if self
is <expr> = <literal>
or <literal> = <expr>
then return Some((<literal>, false))
. In addition to just trying to match <expr>
as it
is, we also try to remove an invertible function call (such as a cast). If the match
succeeds with the inversion, then return Some((<inverted-literal>, true))
. For more
details on the inversion, see invert_casts_on_expr_eq_literal_inner
.
fn expr_eq_literal_inner( expr_to_match: &MirScalarExpr, literal: Row, literal_expr: &MirScalarExpr, other_side: &MirScalarExpr, ) -> Option<(Row, bool)>
sourcepub fn any_expr_eq_literal(&self) -> Option<MirScalarExpr>
pub fn any_expr_eq_literal(&self) -> Option<MirScalarExpr>
If self
is <expr> = <literal>
or <literal> = <expr>
then
return <expr>
. It also tries to remove a cast (or other invertible function call) from
<expr>
before returning it, see invert_casts_on_expr_eq_literal_inner
.
sourcepub fn invert_casts_on_expr_eq_literal(&self) -> MirScalarExpr
pub fn invert_casts_on_expr_eq_literal(&self) -> MirScalarExpr
If the given MirScalarExpr
is a literal equality where one side is an invertible function
call, then calls the inverse function on both sides of the equality and returns the modified
version of the given MirScalarExpr
. Otherwise, it returns the original expression.
For more details, see invert_casts_on_expr_eq_literal_inner
.
sourcefn invert_casts_on_expr_eq_literal_inner(
expr: &MirScalarExpr,
literal: &MirScalarExpr,
) -> (MirScalarExpr, MirScalarExpr)
fn invert_casts_on_expr_eq_literal_inner( expr: &MirScalarExpr, literal: &MirScalarExpr, ) -> (MirScalarExpr, MirScalarExpr)
Given an <expr>
and a <literal>
that were taken out from <expr> = <literal>
or
<literal> = <expr>
, it tries to simplify the equality by applying the inverse function of
the outermost function call of <expr>
(if exists):
<literal> = func(<inner_expr>)
, where func
is invertible
–>
<func^-1(literal)> = <inner_expr>
if func^-1(literal)
doesn’t error out, and both func
and func^-1
preserve uniqueness.
The return value is the <inner_expr>
and the literal value that we get by applying the
inverse function.
sourcepub fn impossible_literal_equality_because_types(&self) -> bool
pub fn impossible_literal_equality_because_types(&self) -> bool
Tries to remove a cast (or other invertible function) in the same way as
invert_casts_on_expr_eq_literal
, but if calling the inverse function fails on the literal,
then it deems the equality to be impossible. For example if a
is a smallint column, then
it catches a::integer = 1000000
to be an always false predicate (where the ::integer
could have been inserted implicitly).
fn impossible_literal_equality_because_types_inner( literal: &MirScalarExpr, other_side: &MirScalarExpr, ) -> bool
sourcepub fn any_expr_ineq_literal(&self) -> bool
pub fn any_expr_ineq_literal(&self) -> bool
Determines if self
is
<expr> < <literal>
or
<expr> > <literal>
or
<literal> < <expr>
or
<literal> > <expr>
or
<expr> <= <literal>
or
<expr> >= <literal>
or
<literal> <= <expr>
or
<literal> >= <expr>
.
sourcepub fn permute(&mut self, permutation: &[usize])
pub fn permute(&mut self, permutation: &[usize])
Rewrites column indices with their value in permutation
.
This method is applicable even when permutation
is not a
strict permutation, and it only needs to have entries for
each column referenced in self
.
sourcepub fn permute_map(&mut self, permutation: &BTreeMap<usize, usize>)
pub fn permute_map(&mut self, permutation: &BTreeMap<usize, usize>)
Rewrites column indices with their value in permutation
.
This method is applicable even when permutation
is not a
strict permutation, and it only needs to have entries for
each column referenced in self
.
pub fn support(&self) -> BTreeSet<usize>
pub fn support_into(&self, support: &mut BTreeSet<usize>)
pub fn take(&mut self) -> Self
pub fn as_literal(&self) -> Option<Result<Datum<'_>, &EvalError>>
pub fn as_literal_owned(&self) -> Option<Result<Row, EvalError>>
pub fn as_literal_str(&self) -> Option<&str>
pub fn as_literal_int64(&self) -> Option<i64>
pub fn as_literal_err(&self) -> Option<&EvalError>
pub fn is_literal(&self) -> bool
pub fn is_literal_true(&self) -> bool
pub fn is_literal_false(&self) -> bool
pub fn is_literal_null(&self) -> bool
pub fn is_literal_ok(&self) -> bool
pub fn is_literal_err(&self) -> bool
pub fn is_column(&self) -> bool
pub fn is_error_if_null(&self) -> bool
pub fn contains_error_if_null(&self) -> bool
might_error
insteadsourcepub fn might_error(&self) -> bool
pub fn might_error(&self) -> bool
A very crude approximation for scalar expressions that might produce an error.
Currently, this is restricted only to expressions that either contain a
literal error or a VariadicFunc::ErrorIfNull
call.
sourcepub fn as_column(&self) -> Option<usize>
pub fn as_column(&self) -> Option<usize>
If self is a column, return the column index, otherwise None
.
sourcepub fn reduce(&mut self, column_types: &[ColumnType])
pub fn reduce(&mut self, column_types: &[ColumnType])
Reduces a complex expression where possible.
This function uses nullability information present in column_types
,
and the result may only continue to be a correct transformation as
long as this information continues to hold (nullability may not hold
as expressions migrate around).
(If you’d like to not use nullability information here, then you can
tweak the nullabilities in column_types
before passing it to this
function, see e.g. in EquivalenceClasses::minimize
.)
Also performs partial canonicalization on the expression.
use mz_expr::MirScalarExpr;
use mz_repr::{ColumnType, Datum, ScalarType};
let expr_0 = MirScalarExpr::Column(0);
let expr_t = MirScalarExpr::literal_true();
let expr_f = MirScalarExpr::literal_false();
let mut test =
expr_t
.clone()
.and(expr_f.clone())
.if_then_else(expr_0, expr_t.clone());
let input_type = vec![ScalarType::Int32.nullable(false)];
test.reduce(&input_type);
assert_eq!(test, expr_t);
sourcefn decompose_is_null(&mut self) -> Option<MirScalarExpr>
fn decompose_is_null(&mut self) -> Option<MirScalarExpr>
Decompose an IsNull expression into a disjunction of simpler expressions.
Assumes that self
is the expression inside of an IsNull.
Returns Some(expressions)
if the outer IsNull is to be
replaced by some other expression. Note: if it returns
None, it might still have mutated *self.
sourcepub fn flatten_associative(&mut self)
pub fn flatten_associative(&mut self)
Flattens a chain of calls to associative variadic functions (For example: ORs or ANDs)
sourcefn reduce_and_canonicalize_and_or(&mut self)
fn reduce_and_canonicalize_and_or(&mut self)
Canonicalizes AND/OR, and does some straightforward simplifications
sourcefn undistribute_and_or(&mut self)
fn undistribute_and_or(&mut self)
AND/OR undistribution (factoring out) to apply at each MirScalarExpr
.
This method attempts to apply one of the distribution laws (in a direction opposite to the their name):
(a && b) || (a && c) --> a && (b || c) // Undistribute-OR
(a || b) && (a || c) --> a || (b && c) // Undistribute-AND
or one of their corresponding two absorption law special cases:
a || (a && c) --> a // Absorb-OR
a && (a || c) --> a // Absorb-AND
The method also works with more than 2 arguments at the top, e.g.
(a && b) || (a && c) || (a && d) --> a && (b || c || d)
It can also factor out only a subset of the top arguments, e.g.
(a && b) || (a && c) || (d && e) --> (a && (b || c)) || (d && e)
Note that sometimes there are two overlapping possibilities to factor out from, e.g.
(a && b) || (a && c) || (d && c)
Here we can factor out a
from from the 1. and 2. terms, or we can
factor out c
from the 2. and 3. terms. One of these might lead to
more/better undistribution opportunities later, but we just pick one
locally, because recursively trying out all of them would lead to
exponential run time.
The local heuristic is that we prefer a candidate that leads to an absorption, or if there is no such one then we simply pick the first. In case of multiple absorption candidates, it doesn’t matter which one we pick, because applying an absorption cannot adversely effect the possibility of applying other absorptions.
§Assumption
Assumes that nested chains of AND/OR applications are flattened (this
can be enforced with Self::flatten_associative
).
§Examples
Absorb-OR:
a || (a && c) || (a && d)
-->
a && (true || c || d)
-->
a && true
-->
a
Here only the first step is performed by this method. The rest is done
by Self::reduce_and_canonicalize_and_or
called after us in
reduce()
.
sourcepub fn non_null_requirements(&self, columns: &mut BTreeSet<usize>)
pub fn non_null_requirements(&self, columns: &mut BTreeSet<usize>)
Adds any columns that must be non-Null for self
to be non-Null.
pub fn typ(&self, column_types: &[ColumnType]) -> ColumnType
pub fn eval<'a>( &'a self, datums: &[Datum<'a>], temp_storage: &'a RowArena, ) -> Result<Datum<'a>, EvalError>
sourcepub fn contains_temporal(&self) -> bool
pub fn contains_temporal(&self) -> bool
True iff the expression contains
UnmaterializableFunc::MzNow
.
sourcepub fn contains_unmaterializable(&self) -> bool
pub fn contains_unmaterializable(&self) -> bool
True iff the expression contains an UnmaterializableFunc
.
sourcepub fn contains_unmaterializable_except(
&self,
exceptions: &[UnmaterializableFunc],
) -> bool
pub fn contains_unmaterializable_except( &self, exceptions: &[UnmaterializableFunc], ) -> bool
True iff the expression contains an UnmaterializableFunc
that is not in the exceptions
list.
sourcepub fn contains_column(&self) -> bool
pub fn contains_column(&self) -> bool
True iff the expression contains a Column
.
source§impl MirScalarExpr
impl MirScalarExpr
sourcepub fn could_error(&self) -> bool
pub fn could_error(&self) -> bool
True iff evaluation could possibly error on non-error input Datum
.
source§impl MirScalarExpr
impl MirScalarExpr
sourcepub fn children(&self) -> impl DoubleEndedIterator<Item = &Self>
pub fn children(&self) -> impl DoubleEndedIterator<Item = &Self>
Iterates through references to child expressions.
sourcepub fn children_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut Self>
pub fn children_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut Self>
Iterates through mutable references to child expressions.
sourcepub fn visit_pre_mut<F: FnMut(&mut Self)>(&mut self, f: F)
pub fn visit_pre_mut<F: FnMut(&mut Self)>(&mut self, f: F)
Iterative pre-order visitor.
Trait Implementations§
source§impl Arbitrary for MirScalarExpr
impl Arbitrary for MirScalarExpr
§type Parameters = ()
type Parameters = ()
arbitrary_with
accepts for configuration
of the generated Strategy
. Parameters must implement Default
.§type Strategy = BoxedStrategy<MirScalarExpr>
type Strategy = BoxedStrategy<MirScalarExpr>
Strategy
used to generate values of type Self
.source§fn arbitrary_with(_: Self::Parameters) -> Self::Strategy
fn arbitrary_with(_: Self::Parameters) -> Self::Strategy
source§impl Clone for MirScalarExpr
impl Clone for MirScalarExpr
source§fn clone(&self) -> MirScalarExpr
fn clone(&self) -> MirScalarExpr
1.0.0 · source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moresource§impl Debug for MirScalarExpr
impl Debug for MirScalarExpr
source§impl<'de> Deserialize<'de> for MirScalarExpr
impl<'de> Deserialize<'de> for MirScalarExpr
source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
source§impl Display for MirScalarExpr
impl Display for MirScalarExpr
source§impl Hash for MirScalarExpr
impl Hash for MirScalarExpr
source§impl MzReflect for MirScalarExpr
impl MzReflect for MirScalarExpr
source§fn add_to_reflected_type_info(rti: &mut ReflectedTypeInfo)
fn add_to_reflected_type_info(rti: &mut ReflectedTypeInfo)
rti
. Read moresource§impl Ord for MirScalarExpr
impl Ord for MirScalarExpr
source§fn cmp(&self, other: &MirScalarExpr) -> Ordering
fn cmp(&self, other: &MirScalarExpr) -> Ordering
1.21.0 · source§fn max(self, other: Self) -> Selfwhere
Self: Sized,
fn max(self, other: Self) -> Selfwhere
Self: Sized,
source§impl PartialEq for MirScalarExpr
impl PartialEq for MirScalarExpr
source§impl PartialOrd for MirScalarExpr
impl PartialOrd for MirScalarExpr
source§impl RustType<ProtoMirScalarExpr> for MirScalarExpr
impl RustType<ProtoMirScalarExpr> for MirScalarExpr
source§fn into_proto(&self) -> ProtoMirScalarExpr
fn into_proto(&self) -> ProtoMirScalarExpr
Self
into a Proto
value.source§fn from_proto(proto: ProtoMirScalarExpr) -> Result<Self, TryFromProtoError>
fn from_proto(proto: ProtoMirScalarExpr) -> Result<Self, TryFromProtoError>
source§fn into_proto_owned(self) -> Proto
fn into_proto_owned(self) -> Proto
Self::into_proto
that types can
optionally implement, otherwise, the default implementation
delegates to Self::into_proto
.source§impl ScalarOps for MirScalarExpr
impl ScalarOps for MirScalarExpr
fn match_col_ref(&self) -> Option<usize>
fn references(&self, column: usize) -> bool
source§impl Serialize for MirScalarExpr
impl Serialize for MirScalarExpr
source§impl VisitChildren<MirScalarExpr> for MirScalarExpr
impl VisitChildren<MirScalarExpr> for MirScalarExpr
source§fn visit_children<F>(&self, f: F)
fn visit_children<F>(&self, f: F)
f
to each direct child.source§fn visit_mut_children<F>(&mut self, f: F)
fn visit_mut_children<F>(&mut self, f: F)
f
to each direct child.impl Eq for MirScalarExpr
impl StructuralPartialEq for MirScalarExpr
Auto Trait Implementations§
impl Freeze for MirScalarExpr
impl RefUnwindSafe for MirScalarExpr
impl Send for MirScalarExpr
impl Sync for MirScalarExpr
impl Unpin for MirScalarExpr
impl UnwindSafe for MirScalarExpr
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
source§default unsafe fn clone_to_uninit(&self, dst: *mut T)
default unsafe fn clone_to_uninit(&self, dst: *mut T)
clone_to_uninit
)source§impl<Q, K> Comparable<K> for Q
impl<Q, K> Comparable<K> for Q
source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key
and return true
if they are equal.source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key
and return true
if they are equal.source§impl<T> FutureExt for T
impl<T> FutureExt for T
source§fn with_context(self, otel_cx: Context) -> WithContext<Self>
fn with_context(self, otel_cx: Context) -> WithContext<Self>
source§fn with_current_context(self) -> WithContext<Self>
fn with_current_context(self) -> WithContext<Self>
source§impl<T> Instrument for T
impl<T> Instrument for T
source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
source§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T
in a tonic::Request
source§impl<T, U> OverrideFrom<Option<&T>> for Uwhere
U: OverrideFrom<T>,
impl<T, U> OverrideFrom<Option<&T>> for Uwhere
U: OverrideFrom<T>,
source§impl<T> Pointable for T
impl<T> Pointable for T
source§impl<T> PreferredContainer for T
impl<T> PreferredContainer for T
source§impl<T> ProgressEventTimestamp for T
impl<T> ProgressEventTimestamp for T
source§impl<P, R> ProtoType<R> for Pwhere
R: RustType<P>,
impl<P, R> ProtoType<R> for Pwhere
R: RustType<P>,
source§fn into_rust(self) -> Result<R, TryFromProtoError>
fn into_rust(self) -> Result<R, TryFromProtoError>
RustType::from_proto
.source§fn from_rust(rust: &R) -> P
fn from_rust(rust: &R) -> P
RustType::into_proto
.source§impl<'a, S, T> Semigroup<&'a S> for Twhere
T: Semigroup<S>,
impl<'a, S, T> Semigroup<&'a S> for Twhere
T: Semigroup<S>,
source§fn plus_equals(&mut self, rhs: &&'a S)
fn plus_equals(&mut self, rhs: &&'a S)
std::ops::AddAssign
, for types that do not implement AddAssign
.source§impl<T> Visit for Twhere
T: VisitChildren<T>,
impl<T> Visit for Twhere
T: VisitChildren<T>,
source§fn visit_post<F>(&self, f: &mut F) -> Result<(), RecursionLimitError>
fn visit_post<F>(&self, f: &mut F) -> Result<(), RecursionLimitError>
self
.source§fn visit_post_nolimit<F>(&self, f: &mut F)
fn visit_post_nolimit<F>(&self, f: &mut F)
visit_post
instead.self
.
Does not enforce a recursion limit.source§fn visit_mut_post<F>(&mut self, f: &mut F) -> Result<(), RecursionLimitError>
fn visit_mut_post<F>(&mut self, f: &mut F) -> Result<(), RecursionLimitError>
self
.source§fn visit_mut_post_nolimit<F>(&mut self, f: &mut F)
fn visit_mut_post_nolimit<F>(&mut self, f: &mut F)
visit_mut_post
instead.self
.
Does not enforce a recursion limit.source§fn try_visit_post<F, E>(&self, f: &mut F) -> Result<(), E>
fn try_visit_post<F, E>(&self, f: &mut F) -> Result<(), E>
self
.source§fn try_visit_mut_post<F, E>(&mut self, f: &mut F) -> Result<(), E>
fn try_visit_mut_post<F, E>(&mut self, f: &mut F) -> Result<(), E>
self
.source§fn visit_pre<F>(&self, f: &mut F) -> Result<(), RecursionLimitError>
fn visit_pre<F>(&self, f: &mut F) -> Result<(), RecursionLimitError>
self
.source§fn visit_pre_with_context<Context, AccFun, Visitor>(
&self,
init: Context,
acc_fun: &mut AccFun,
visitor: &mut Visitor,
) -> Result<(), RecursionLimitError>
fn visit_pre_with_context<Context, AccFun, Visitor>( &self, init: Context, acc_fun: &mut AccFun, visitor: &mut Visitor, ) -> Result<(), RecursionLimitError>
self
, which also accumulates context
information along the path from the root to the current node’s parent.
acc_fun
is a similar closure as in fold
. The accumulated context is passed to the
visitor, along with the current node. Read moresource§fn visit_pre_nolimit<F>(&self, f: &mut F)
fn visit_pre_nolimit<F>(&self, f: &mut F)
visit_pre
instead.self
.
Does not enforce a recursion limit.source§fn visit_mut_pre<F>(&mut self, f: &mut F) -> Result<(), RecursionLimitError>
fn visit_mut_pre<F>(&mut self, f: &mut F) -> Result<(), RecursionLimitError>
self
.source§fn visit_mut_pre_nolimit<F>(&mut self, f: &mut F)
fn visit_mut_pre_nolimit<F>(&mut self, f: &mut F)
visit_mut_pre
instead.self
.
Does not enforce a recursion limit.source§fn try_visit_pre<F, E>(&self, f: &mut F) -> Result<(), E>
fn try_visit_pre<F, E>(&self, f: &mut F) -> Result<(), E>
self
.source§fn try_visit_mut_pre<F, E>(&mut self, f: &mut F) -> Result<(), E>
fn try_visit_mut_pre<F, E>(&mut self, f: &mut F) -> Result<(), E>
self
.source§fn visit_pre_post<F1, F2>(
&self,
pre: &mut F1,
post: &mut F2,
) -> Result<(), RecursionLimitError>
fn visit_pre_post<F1, F2>( &self, pre: &mut F1, post: &mut F2, ) -> Result<(), RecursionLimitError>
source§fn visit_pre_post_nolimit<F1, F2>(&self, pre: &mut F1, post: &mut F2)
fn visit_pre_post_nolimit<F1, F2>(&self, pre: &mut F1, post: &mut F2)
visit
instead.Visit::visit_pre
and Visit::visit_post
.
Does not enforce a recursion limit. Read moresource§fn visit_mut_pre_post<F1, F2>(
&mut self,
pre: &mut F1,
post: &mut F2,
) -> Result<(), RecursionLimitError>
fn visit_mut_pre_post<F1, F2>( &mut self, pre: &mut F1, post: &mut F2, ) -> Result<(), RecursionLimitError>
visit_mut
instead.source§fn visit_mut_pre_post_nolimit<F1, F2>(&mut self, pre: &mut F1, post: &mut F2)
fn visit_mut_pre_post_nolimit<F1, F2>(&mut self, pre: &mut F1, post: &mut F2)
visit_mut_pre_post
instead.Visit::visit_mut_pre
and Visit::visit_mut_post
.
Does not enforce a recursion limit. Read more