toasty_core/stmt/expr.rs
1use crate::stmt::{ExprExists, Input};
2
3use super::{
4 Entry, EntryMut, EntryPath, ExprAnd, ExprAny, ExprArg, ExprBinaryOp, ExprCast, ExprError,
5 ExprFunc, ExprInList, ExprInSubquery, ExprIsNull, ExprIsVariant, ExprLet, ExprLike, ExprList,
6 ExprMap, ExprMatch, ExprNot, ExprOr, ExprProject, ExprRecord, ExprStartsWith, ExprStmt, Node,
7 Projection, Substitute, Value, Visit, VisitMut, expr_reference::ExprReference,
8};
9use std::fmt;
10
11/// An expression node in Toasty's query AST.
12///
13/// `Expr` is the central type in the statement intermediate representation. Every
14/// filter, projection, value, and computed result in a Toasty query is
15/// represented as an `Expr` tree. The query engine compiles these trees through
16/// several phases (simplify, lower, plan, execute) before they reach a database
17/// driver.
18///
19/// # Examples
20///
21/// ```ignore
22/// use toasty_core::stmt::{Expr, Value};
23///
24/// // Constant value expressions
25/// let t = Expr::TRUE;
26/// assert!(t.is_true());
27///
28/// let n = Expr::null();
29/// assert!(n.is_value_null());
30///
31/// // From conversions
32/// let i: Expr = 42i64.into();
33/// assert!(i.is_value());
34/// ```
35#[derive(Clone, PartialEq)]
36pub enum Expr {
37 /// Logical AND of multiple expressions. See [`ExprAnd`].
38 And(ExprAnd),
39
40 /// Returns `true` if any item in a collection is truthy. See [`ExprAny`].
41 Any(ExprAny),
42
43 /// Positional argument placeholder. See [`ExprArg`].
44 Arg(ExprArg),
45
46 /// Binary comparison or arithmetic operation. See [`ExprBinaryOp`].
47 BinaryOp(ExprBinaryOp),
48
49 /// Type cast. See [`ExprCast`].
50 Cast(ExprCast),
51
52 /// Instructs the database to use its default value for a column. Useful for
53 /// auto-increment fields and other columns with server-side defaults.
54 Default,
55
56 /// An error expression that fails evaluation with a message. See [`ExprError`].
57 Error(ExprError),
58
59 /// `[NOT] EXISTS(SELECT ...)` check. See [`ExprExists`].
60 Exists(ExprExists),
61
62 /// Aggregate or scalar function call. See [`ExprFunc`].
63 Func(ExprFunc),
64
65 /// An **unresolved** reference to a name (e.g. a column name in a DDL
66 /// context).
67 ///
68 /// Unlike [`Expr::Reference`] / [`ExprReference`], which hold **resolved**
69 /// index-based references into the schema, `Ident` carries only the raw
70 /// name string. It is used in contexts where schema resolution is not
71 /// applicable, such as CHECK constraints in CREATE TABLE statements.
72 Ident(String),
73
74 /// `expr IN (list)` membership test. See [`ExprInList`].
75 InList(ExprInList),
76
77 /// `expr IN (SELECT ...)` membership test. See [`ExprInSubquery`].
78 InSubquery(ExprInSubquery),
79
80 /// `IS [NOT] NULL` check. Separate from binary operators because of
81 /// three-valued logic semantics in SQL. See [`ExprIsNull`].
82 IsNull(ExprIsNull),
83
84 /// Tests whether a value is a specific enum variant. See [`ExprIsVariant`].
85 IsVariant(ExprIsVariant),
86
87 /// Scoped binding expression (transient -- inlined before planning).
88 /// See [`ExprLet`].
89 Let(ExprLet),
90
91 /// SQL `LIKE` pattern match: `expr LIKE pattern`. See [`ExprLike`].
92 Like(ExprLike),
93
94 /// Applies a transformation to each item in a collection. See [`ExprMap`].
95 Map(ExprMap),
96
97 /// Pattern-match dispatching on a subject. See [`ExprMatch`].
98 Match(ExprMatch),
99
100 /// Boolean negation. See [`ExprNot`].
101 Not(ExprNot),
102
103 /// Logical OR of multiple expressions. See [`ExprOr`].
104 Or(ExprOr),
105
106 /// Field projection from a composite value. See [`ExprProject`].
107 Project(ExprProject),
108
109 /// Fixed-size heterogeneous tuple of expressions. See [`ExprRecord`].
110 Record(ExprRecord),
111
112 // TODO: delete this
113 /// Reference to a field, column, or model in the current or an outer query
114 /// scope. See [`ExprReference`].
115 Reference(ExprReference),
116
117 /// Ordered, homogeneous collection of expressions. See [`ExprList`].
118 List(ExprList),
119
120 /// String prefix match: `starts_with(expr, prefix)`. See [`ExprStartsWith`].
121 StartsWith(ExprStartsWith),
122
123 /// Embedded sub-statement (e.g., a subquery). See [`ExprStmt`].
124 Stmt(ExprStmt),
125
126 /// Constant value. See [`Value`].
127 Value(Value),
128}
129
130impl Expr {
131 /// The boolean `true` constant expression.
132 pub const TRUE: Expr = Expr::Value(Value::Bool(true));
133
134 /// The boolean `false` constant expression.
135 pub const FALSE: Expr = Expr::Value(Value::Bool(false));
136
137 /// Alias for [`Expr::Default`] as a constant.
138 pub const DEFAULT: Expr = Expr::Default;
139
140 /// Creates a null value expression.
141 pub fn null() -> Self {
142 Self::Value(Value::Null)
143 }
144
145 /// Is a value that evaluates to null
146 pub fn is_value_null(&self) -> bool {
147 matches!(self, Self::Value(Value::Null))
148 }
149
150 /// Returns true if the expression is the `true` boolean expression
151 pub fn is_true(&self) -> bool {
152 matches!(self, Self::Value(Value::Bool(true)))
153 }
154
155 /// Returns `true` if the expression is the `false` boolean expression
156 pub fn is_false(&self) -> bool {
157 matches!(self, Self::Value(Value::Bool(false)))
158 }
159
160 /// Returns `true` if the expression can never evaluate to `true`.
161 ///
162 /// In SQL's three-valued logic, both `false` and `null` are unsatisfiable:
163 /// a filter producing either value will never match any rows.
164 pub fn is_unsatisfiable(&self) -> bool {
165 self.is_false() || self.is_value_null()
166 }
167
168 /// Returns `true` if the expression is the default expression
169 pub fn is_default(&self) -> bool {
170 matches!(self, Self::Default)
171 }
172
173 /// Returns true if the expression is a constant value.
174 pub fn is_value(&self) -> bool {
175 matches!(self, Self::Value(..))
176 }
177
178 /// Returns `true` if the expression is a sub-statement.
179 pub fn is_stmt(&self) -> bool {
180 matches!(self, Self::Stmt(..))
181 }
182
183 /// Returns true if the expression is a binary operation
184 pub fn is_binary_op(&self) -> bool {
185 matches!(self, Self::BinaryOp(..))
186 }
187
188 /// Returns `true` if the expression is an argument placeholder.
189 pub fn is_arg(&self) -> bool {
190 matches!(self, Self::Arg(_))
191 }
192
193 /// Returns true if the expression is always non-nullable.
194 ///
195 /// This method is conservative and only returns true for expressions we can
196 /// prove are non-nullable.
197 pub fn is_always_non_nullable(&self) -> bool {
198 match self {
199 // A constant value is non-nullable if it's not null.
200 Self::Value(value) => !value.is_null(),
201 // Boolean logic expressions always evaluate to true or false.
202 Self::And(_) | Self::Or(_) | Self::Not(_) => true,
203 // ANY returns true if any item matches, always boolean.
204 Self::Any(_) => true,
205 // Comparisons always evaluate to true or false.
206 Self::BinaryOp(_) => true,
207 // IS NULL checks always evaluate to true or false.
208 Self::IsNull(_) => true,
209 // Variant checks always evaluate to true or false.
210 Self::IsVariant(_) => true,
211 // EXISTS checks always evaluate to true or false.
212 Self::Exists(_) => true,
213 // IN expressions always evaluate to true or false.
214 Self::InList(_) | Self::InSubquery(_) => true,
215 // For other expressions, we cannot prove non-nullability.
216 _ => false,
217 }
218 }
219
220 /// Consumes the expression and returns the inner [`Value`].
221 ///
222 /// # Panics
223 ///
224 /// Panics (via `todo!()`) if `self` is not an `Expr::Value`.
225 pub fn into_value(self) -> Value {
226 match self {
227 Self::Value(value) => value,
228 _ => todo!(),
229 }
230 }
231
232 /// Consumes the expression and returns the inner [`ExprStmt`].
233 ///
234 /// # Panics
235 ///
236 /// Panics (via `todo!()`) if `self` is not an `Expr::Stmt`.
237 pub fn into_stmt(self) -> ExprStmt {
238 match self {
239 Self::Stmt(stmt) => stmt,
240 _ => todo!(),
241 }
242 }
243
244 /// Returns `true` if the expression is stable
245 ///
246 /// An expression is stable if it yields the same value each time it is evaluated
247 pub fn is_stable(&self) -> bool {
248 match self {
249 // Always stable - constant values
250 Self::Value(_) => true,
251
252 // Unresolved identifiers refer to external state (e.g. a column)
253 Self::Ident(_) => false,
254
255 // Never stable - generates new values each evaluation
256 Self::Default => false,
257
258 // Error expressions are stable (they always produce the same error)
259 Self::Error(_) => true,
260
261 // Stable if all children are stable
262 Self::Record(expr_record) => expr_record.iter().all(|expr| expr.is_stable()),
263 Self::List(expr_list) => expr_list.items.iter().all(|expr| expr.is_stable()),
264 Self::Cast(expr_cast) => expr_cast.expr.is_stable(),
265 Self::StartsWith(e) => e.expr.is_stable() && e.prefix.is_stable(),
266 Self::Like(e) => e.expr.is_stable() && e.pattern.is_stable(),
267 Self::BinaryOp(expr_binary) => {
268 expr_binary.lhs.is_stable() && expr_binary.rhs.is_stable()
269 }
270 Self::And(expr_and) => expr_and.iter().all(|expr| expr.is_stable()),
271 Self::Any(expr_any) => expr_any.expr.is_stable(),
272 Self::Or(expr_or) => expr_or.iter().all(|expr| expr.is_stable()),
273 Self::IsNull(expr_is_null) => expr_is_null.expr.is_stable(),
274 Self::IsVariant(expr_is_variant) => expr_is_variant.expr.is_stable(),
275 Self::Not(expr_not) => expr_not.expr.is_stable(),
276 Self::InList(expr_in_list) => {
277 expr_in_list.expr.is_stable() && expr_in_list.list.is_stable()
278 }
279 Self::Project(expr_project) => expr_project.base.is_stable(),
280 Self::Let(expr_let) => {
281 expr_let.bindings.iter().all(|b| b.is_stable()) && expr_let.body.is_stable()
282 }
283 Self::Map(expr_map) => expr_map.base.is_stable() && expr_map.map.is_stable(),
284 Self::Match(expr_match) => {
285 expr_match.subject.is_stable()
286 && expr_match.arms.iter().all(|arm| arm.expr.is_stable())
287 }
288
289 // References and statements - stable (they reference existing data)
290 Self::Reference(_) | Self::Arg(_) => true,
291
292 // Subqueries and functions - could be unstable
293 // For now, conservatively mark as unstable
294 Self::Stmt(_) | Self::Func(_) | Self::InSubquery(_) | Self::Exists(_) => false,
295 }
296 }
297
298 /// Returns `true` if `self` and `other` are syntactically identical **and**
299 /// both sides are stable.
300 ///
301 /// This is the soundness-preserving comparison used by simplification
302 /// rules that rewrite on the assumption that two equal sub-expressions
303 /// produce the same value (idempotent, absorption, complement,
304 /// range-to-equality, OR-to-IN, factoring, variant tautology).
305 ///
306 /// Syntactic identity alone is not enough: `LAST_INSERT_ID() =
307 /// LAST_INSERT_ID()` is two independent evaluations and may yield
308 /// different values, so rewriting `a AND a` to `a` would be unsound when
309 /// `a` is non-deterministic. Gating on [`Self::is_stable`] excludes any
310 /// sub-expression whose value may change across evaluations.
311 pub fn is_equivalent_to(&self, other: &Self) -> bool {
312 self == other && self.is_stable()
313 }
314
315 /// Returns `true` if the expression is a constant expression.
316 ///
317 /// A constant expression is one that does not reference any external data.
318 /// This means it contains no `Reference`, `Stmt`, or `Arg` expressions that
319 /// reference external inputs.
320 ///
321 /// `Arg` expressions inside `Map` bodies *with `nesting` less than the current
322 /// map depth* are local bindings (bound to the mapped element), not external
323 /// inputs, and are therefore considered const in that context.
324 pub fn is_const(&self) -> bool {
325 self.is_const_at_depth(0)
326 }
327
328 /// Inner implementation of [`is_const`] that tracks the number of enclosing
329 /// `Map` scopes. An `Arg` with `nesting < map_depth` is a local binding
330 /// introduced by one of those `Map`s and does not count as external input.
331 fn is_const_at_depth(&self, map_depth: usize) -> bool {
332 match self {
333 // Always constant
334 Self::Value(_) => true,
335
336 // Unresolved identifiers reference external data
337 Self::Ident(_) => false,
338
339 // Arg: local if nesting is within map_depth, otherwise external
340 Self::Arg(arg) => arg.nesting < map_depth,
341
342 // Error expressions are constant (no external data)
343 Self::Error(_) => true,
344
345 // Never constant - references external data
346 Self::Reference(_)
347 | Self::Stmt(_)
348 | Self::InSubquery(_)
349 | Self::Exists(_)
350 | Self::Default
351 | Self::Func(_) => false,
352
353 // Const if all children are const at the same depth
354 Self::Record(expr_record) => expr_record
355 .iter()
356 .all(|expr| expr.is_const_at_depth(map_depth)),
357 Self::List(expr_list) => expr_list
358 .items
359 .iter()
360 .all(|expr| expr.is_const_at_depth(map_depth)),
361 Self::Cast(expr_cast) => expr_cast.expr.is_const_at_depth(map_depth),
362 Self::StartsWith(e) => {
363 e.expr.is_const_at_depth(map_depth) && e.prefix.is_const_at_depth(map_depth)
364 }
365 Self::Like(e) => {
366 e.expr.is_const_at_depth(map_depth) && e.pattern.is_const_at_depth(map_depth)
367 }
368 Self::BinaryOp(expr_binary) => {
369 expr_binary.lhs.is_const_at_depth(map_depth)
370 && expr_binary.rhs.is_const_at_depth(map_depth)
371 }
372 Self::And(expr_and) => expr_and
373 .iter()
374 .all(|expr| expr.is_const_at_depth(map_depth)),
375 Self::Any(expr_any) => expr_any.expr.is_const_at_depth(map_depth),
376 Self::Not(expr_not) => expr_not.expr.is_const_at_depth(map_depth),
377 Self::Or(expr_or) => expr_or.iter().all(|expr| expr.is_const_at_depth(map_depth)),
378 Self::IsNull(expr_is_null) => expr_is_null.expr.is_const_at_depth(map_depth),
379 Self::IsVariant(expr_is_variant) => expr_is_variant.expr.is_const_at_depth(map_depth),
380 Self::InList(expr_in_list) => {
381 expr_in_list.expr.is_const_at_depth(map_depth)
382 && expr_in_list.list.is_const_at_depth(map_depth)
383 }
384 Self::Project(expr_project) => expr_project.base.is_const_at_depth(map_depth),
385
386 // Let: binding is checked at the current depth; the body is checked
387 // at depth+1 so that arg(nesting=0) in the body is treated as local.
388 Self::Let(expr_let) => {
389 expr_let
390 .bindings
391 .iter()
392 .all(|b| b.is_const_at_depth(map_depth))
393 && expr_let.body.is_const_at_depth(map_depth + 1)
394 }
395 // Map: base is checked at the current depth; the map body is checked
396 // at depth+1 so that arg(nesting=0) in the body is treated as local.
397 Self::Map(expr_map) => {
398 expr_map.base.is_const_at_depth(map_depth)
399 && expr_map.map.is_const_at_depth(map_depth + 1)
400 }
401 Self::Match(expr_match) => {
402 expr_match.subject.is_const_at_depth(map_depth)
403 && expr_match
404 .arms
405 .iter()
406 .all(|arm| arm.expr.is_const_at_depth(map_depth))
407 }
408 }
409 }
410
411 /// Returns `true` if the expression can be evaluated.
412 ///
413 /// An expression can be evaluated if it doesn't contain references to external
414 /// data sources like subqueries or references. Args are allowed since they
415 /// represent function parameters that can be bound at evaluation time.
416 pub fn is_eval(&self) -> bool {
417 match self {
418 // Always evaluable
419 Self::Value(_) => true,
420
421 // Unresolved identifiers cannot be evaluated
422 Self::Ident(_) => false,
423
424 // Args are OK for evaluation
425 Self::Arg(_) => true,
426
427 // Error expressions are evaluable (they produce an error)
428 Self::Error(_) => true,
429
430 // Never evaluable - references external data or requires a database driver
431 Self::Default
432 | Self::Reference(_)
433 | Self::Stmt(_)
434 | Self::InSubquery(_)
435 | Self::Exists(_)
436 | Self::StartsWith(_)
437 | Self::Like(_) => false,
438
439 // Evaluable if all children are evaluable
440 Self::Record(expr_record) => expr_record.iter().all(|expr| expr.is_eval()),
441 Self::List(expr_list) => expr_list.items.iter().all(|expr| expr.is_eval()),
442 Self::Cast(expr_cast) => expr_cast.expr.is_eval(),
443 Self::BinaryOp(expr_binary) => expr_binary.lhs.is_eval() && expr_binary.rhs.is_eval(),
444 Self::And(expr_and) => expr_and.iter().all(|expr| expr.is_eval()),
445 Self::Any(expr_any) => expr_any.expr.is_eval(),
446 Self::Or(expr_or) => expr_or.iter().all(|expr| expr.is_eval()),
447 Self::Not(expr_not) => expr_not.expr.is_eval(),
448 Self::IsNull(expr_is_null) => expr_is_null.expr.is_eval(),
449 Self::IsVariant(expr_is_variant) => expr_is_variant.expr.is_eval(),
450 Self::InList(expr_in_list) => {
451 expr_in_list.expr.is_eval() && expr_in_list.list.is_eval()
452 }
453 Self::Project(expr_project) => expr_project.base.is_eval(),
454 Self::Let(expr_let) => {
455 expr_let.bindings.iter().all(|b| b.is_eval()) && expr_let.body.is_eval()
456 }
457 Self::Map(expr_map) => expr_map.base.is_eval() && expr_map.map.is_eval(),
458 Self::Match(expr_match) => {
459 expr_match.subject.is_eval() && expr_match.arms.iter().all(|arm| arm.expr.is_eval())
460 }
461 Self::Func(_) => false,
462 }
463 }
464
465 /// Returns a clone of this expression with all [`Projection`] nodes
466 /// transformed by `f`.
467 pub fn map_projections(&self, f: impl FnMut(&Projection) -> Projection) -> Self {
468 struct MapProjections<T>(T);
469
470 impl<T: FnMut(&Projection) -> Projection> VisitMut for MapProjections<T> {
471 fn visit_projection_mut(&mut self, i: &mut Projection) {
472 *i = self.0(i);
473 }
474 }
475
476 let mut mapped = self.clone();
477 MapProjections(f).visit_expr_mut(&mut mapped);
478 mapped
479 }
480
481 /// Navigates into a nested record or list expression by `path` and returns
482 /// a read-only [`Entry`] reference.
483 ///
484 /// Returns `None` if the path cannot be followed (e.g., the expression is
485 /// not a record or list at the expected depth).
486 #[track_caller]
487 pub fn entry(&self, path: impl EntryPath) -> Option<Entry<'_>> {
488 let mut ret = Entry::Expr(self);
489
490 for step in path.step_iter() {
491 ret = match ret {
492 Entry::Expr(Self::Record(expr)) => Entry::Expr(&expr[step]),
493 Entry::Expr(Self::List(expr)) => Entry::Expr(&expr.items[step]),
494 Entry::Value(Value::Record(record))
495 | Entry::Expr(Self::Value(Value::Record(record))) => Entry::Value(&record[step]),
496 Entry::Value(Value::List(items)) | Entry::Expr(Self::Value(Value::List(items))) => {
497 Entry::Value(&items[step])
498 }
499 _ => return None,
500 }
501 }
502
503 Some(ret)
504 }
505
506 /// Navigates into a nested record or list expression by `path` and returns
507 /// a mutable [`EntryMut`] reference.
508 ///
509 /// # Panics
510 ///
511 /// Panics if the path cannot be followed on the current expression shape.
512 #[track_caller]
513 pub fn entry_mut(&mut self, path: impl EntryPath) -> EntryMut<'_> {
514 let mut ret = EntryMut::Expr(self);
515
516 for step in path.step_iter() {
517 ret = match ret {
518 EntryMut::Expr(Self::Record(expr)) => EntryMut::Expr(&mut expr[step]),
519 EntryMut::Value(Value::Record(record))
520 | EntryMut::Expr(Self::Value(Value::Record(record))) => {
521 EntryMut::Value(&mut record[step])
522 }
523 _ => todo!("ret={ret:#?}; step={step:#?}"),
524 }
525 }
526
527 ret
528 }
529
530 /// Takes the expression out, leaving `Expr::Value(Value::Null)` in its
531 /// place. Equivalent to `std::mem::replace(self, Expr::null())`.
532 pub fn take(&mut self) -> Self {
533 std::mem::replace(self, Self::Value(Value::Null))
534 }
535
536 /// Replaces every [`ExprArg`] in this expression tree with the
537 /// corresponding value from `input`.
538 pub fn substitute(&mut self, input: impl Input) {
539 Substitute::new(input).visit_expr_mut(self);
540 }
541}
542
543impl Node for Expr {
544 fn visit<V: Visit>(&self, mut visit: V) {
545 visit.visit_expr(self);
546 }
547
548 fn visit_mut<V: VisitMut>(&mut self, mut visit: V) {
549 visit.visit_expr_mut(self);
550 }
551}
552
553// === Conversions ===
554
555impl From<bool> for Expr {
556 fn from(value: bool) -> Self {
557 Self::Value(Value::from(value))
558 }
559}
560
561impl From<i64> for Expr {
562 fn from(value: i64) -> Self {
563 Self::Value(value.into())
564 }
565}
566
567impl From<&i64> for Expr {
568 fn from(value: &i64) -> Self {
569 Self::Value(value.into())
570 }
571}
572
573impl From<String> for Expr {
574 fn from(value: String) -> Self {
575 Self::Value(value.into())
576 }
577}
578
579impl From<&String> for Expr {
580 fn from(value: &String) -> Self {
581 Self::Value(value.into())
582 }
583}
584
585impl From<&str> for Expr {
586 fn from(value: &str) -> Self {
587 Self::Value(value.into())
588 }
589}
590
591impl From<Value> for Expr {
592 fn from(value: Value) -> Self {
593 Self::Value(value)
594 }
595}
596
597impl<E1, E2> From<(E1, E2)> for Expr
598where
599 E1: Into<Self>,
600 E2: Into<Self>,
601{
602 fn from(value: (E1, E2)) -> Self {
603 Self::Record(value.into())
604 }
605}
606
607impl fmt::Debug for Expr {
608 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
609 match self {
610 Self::And(e) => e.fmt(f),
611 Self::Any(e) => e.fmt(f),
612 Self::Arg(e) => e.fmt(f),
613 Self::BinaryOp(e) => e.fmt(f),
614 Self::Cast(e) => e.fmt(f),
615 Self::Default => write!(f, "Default"),
616 Self::Error(e) => e.fmt(f),
617 Self::Exists(e) => e.fmt(f),
618 Self::Func(e) => e.fmt(f),
619 Self::Ident(e) => write!(f, "Ident({e:?})"),
620 Self::InList(e) => e.fmt(f),
621 Self::InSubquery(e) => e.fmt(f),
622 Self::IsNull(e) => e.fmt(f),
623 Self::IsVariant(e) => e.fmt(f),
624 Self::Let(e) => e.fmt(f),
625 Self::Like(e) => e.fmt(f),
626 Self::Map(e) => e.fmt(f),
627 Self::Match(e) => e.fmt(f),
628 Self::Not(e) => e.fmt(f),
629 Self::Or(e) => e.fmt(f),
630 Self::Project(e) => e.fmt(f),
631 Self::Record(e) => e.fmt(f),
632 Self::Reference(e) => e.fmt(f),
633 Self::List(e) => e.fmt(f),
634 Self::StartsWith(e) => e.fmt(f),
635 Self::Stmt(e) => e.fmt(f),
636 Self::Value(e) => e.fmt(f),
637 }
638 }
639}