cedar_policy_core/ast/
expr.rs

1/*
2 * Copyright Cedar Contributors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17use crate::{
18    ast::*,
19    expr_builder::{self, ExprBuilder as _},
20    extensions::Extensions,
21    parser::{err::ParseErrors, Loc},
22};
23use educe::Educe;
24use miette::Diagnostic;
25use serde::{Deserialize, Serialize};
26use smol_str::SmolStr;
27use std::{
28    borrow::Cow,
29    collections::{btree_map, BTreeMap, HashMap},
30    hash::{Hash, Hasher},
31    mem,
32    sync::Arc,
33};
34use thiserror::Error;
35
36#[cfg(feature = "wasm")]
37extern crate tsify;
38
39/// Internal AST for expressions used by the policy evaluator.
40/// This structure is a wrapper around an `ExprKind`, which is the expression
41/// variant this object contains. It also contains source information about
42/// where the expression was written in policy source code, and some generic
43/// data which is stored on each node of the AST.
44/// Cloning is O(1).
45#[derive(Educe, Serialize, Deserialize, Debug, Clone)]
46#[educe(PartialEq, Eq, Hash)]
47pub struct Expr<T = ()> {
48    expr_kind: ExprKind<T>,
49    #[educe(PartialEq(ignore))]
50    #[educe(Hash(ignore))]
51    source_loc: Option<Loc>,
52    data: T,
53}
54
55/// The possible expression variants. This enum should be matched on by code
56/// recursively traversing the AST.
57#[derive(Serialize, Deserialize, Hash, Debug, Clone, PartialEq, Eq)]
58pub enum ExprKind<T = ()> {
59    /// Literal value
60    Lit(Literal),
61    /// Variable
62    Var(Var),
63    /// Template Slots
64    Slot(SlotId),
65    /// Symbolic Unknown for partial-eval
66    Unknown(Unknown),
67    /// Ternary expression
68    If {
69        /// Condition for the ternary expression. Must evaluate to Bool type
70        test_expr: Arc<Expr<T>>,
71        /// Value if true
72        then_expr: Arc<Expr<T>>,
73        /// Value if false
74        else_expr: Arc<Expr<T>>,
75    },
76    /// Boolean AND
77    And {
78        /// Left operand, which will be eagerly evaluated
79        left: Arc<Expr<T>>,
80        /// Right operand, which may not be evaluated due to short-circuiting
81        right: Arc<Expr<T>>,
82    },
83    /// Boolean OR
84    Or {
85        /// Left operand, which will be eagerly evaluated
86        left: Arc<Expr<T>>,
87        /// Right operand, which may not be evaluated due to short-circuiting
88        right: Arc<Expr<T>>,
89    },
90    /// Application of a built-in unary operator (single parameter)
91    UnaryApp {
92        /// Unary operator to apply
93        op: UnaryOp,
94        /// Argument to apply operator to
95        arg: Arc<Expr<T>>,
96    },
97    /// Application of a built-in binary operator (two parameters)
98    BinaryApp {
99        /// Binary operator to apply
100        op: BinaryOp,
101        /// First arg
102        arg1: Arc<Expr<T>>,
103        /// Second arg
104        arg2: Arc<Expr<T>>,
105    },
106    /// Application of an extension function to n arguments
107    /// INVARIANT (MethodStyleArgs):
108    ///   if op.style is MethodStyle then args _cannot_ be empty.
109    ///     The first element of args refers to the subject of the method call
110    /// Ideally, we find some way to make this non-representable.
111    ExtensionFunctionApp {
112        /// Extension function to apply
113        fn_name: Name,
114        /// Args to apply the function to
115        args: Arc<Vec<Expr<T>>>,
116    },
117    /// Get an attribute of an entity, or a field of a record
118    GetAttr {
119        /// Expression to get an attribute/field of. Must evaluate to either
120        /// Entity or Record type
121        expr: Arc<Expr<T>>,
122        /// Attribute or field to get
123        attr: SmolStr,
124    },
125    /// Does the given `expr` have the given `attr`?
126    HasAttr {
127        /// Expression to test. Must evaluate to either Entity or Record type
128        expr: Arc<Expr<T>>,
129        /// Attribute or field to check for
130        attr: SmolStr,
131    },
132    /// Regex-like string matching similar to IAM's `StringLike` operator.
133    Like {
134        /// Expression to test. Must evaluate to String type
135        expr: Arc<Expr<T>>,
136        /// Pattern to match on; can include the wildcard *, which matches any string.
137        /// To match a literal `*` in the test expression, users can use `\*`.
138        /// Be careful the backslash in `\*` must not be another escape sequence. For instance, `\\*` matches a backslash plus an arbitrary string.
139        pattern: Pattern,
140    },
141    /// Entity type test. Does the first argument have the entity type
142    /// specified by the second argument.
143    Is {
144        /// Expression to test. Must evaluate to an Entity.
145        expr: Arc<Expr<T>>,
146        /// The [`EntityType`] used for the type membership test.
147        entity_type: EntityType,
148    },
149    /// Set (whose elements may be arbitrary expressions)
150    //
151    // This is backed by `Vec` (and not e.g. `HashSet`), because two `Expr`s
152    // that are syntactically unequal, may actually be semantically equal --
153    // i.e., we can't do the dedup of duplicates until all of the `Expr`s are
154    // evaluated into `Value`s
155    Set(Arc<Vec<Expr<T>>>),
156    /// Anonymous record (whose elements may be arbitrary expressions)
157    Record(Arc<BTreeMap<SmolStr, Expr<T>>>),
158}
159
160impl From<Value> for Expr {
161    fn from(v: Value) -> Self {
162        Expr::from(v.value).with_maybe_source_loc(v.loc)
163    }
164}
165
166impl From<ValueKind> for Expr {
167    fn from(v: ValueKind) -> Self {
168        match v {
169            ValueKind::Lit(lit) => Expr::val(lit),
170            ValueKind::Set(set) => Expr::set(set.iter().map(|v| Expr::from(v.clone()))),
171            // PANIC SAFETY: cannot have duplicate key because the input was already a BTreeMap
172            #[allow(clippy::expect_used)]
173            ValueKind::Record(record) => Expr::record(
174                Arc::unwrap_or_clone(record)
175                    .into_iter()
176                    .map(|(k, v)| (k, Expr::from(v))),
177            )
178            .expect("cannot have duplicate key because the input was already a BTreeMap"),
179            ValueKind::ExtensionValue(ev) => RestrictedExpr::from(ev.as_ref().clone()).into(),
180        }
181    }
182}
183
184impl From<PartialValue> for Expr {
185    fn from(pv: PartialValue) -> Self {
186        match pv {
187            PartialValue::Value(v) => Expr::from(v),
188            PartialValue::Residual(expr) => expr,
189        }
190    }
191}
192
193impl<T> Expr<T> {
194    fn new(expr_kind: ExprKind<T>, source_loc: Option<Loc>, data: T) -> Self {
195        Self {
196            expr_kind,
197            source_loc,
198            data,
199        }
200    }
201
202    /// Access the inner `ExprKind` for this `Expr`. The `ExprKind` is the
203    /// `enum` which specifies the expression variant, so it must be accessed by
204    /// any code matching and recursing on an expression.
205    pub fn expr_kind(&self) -> &ExprKind<T> {
206        &self.expr_kind
207    }
208
209    /// Access the inner `ExprKind`, taking ownership and consuming the `Expr`.
210    pub fn into_expr_kind(self) -> ExprKind<T> {
211        self.expr_kind
212    }
213
214    /// Access the data stored on the `Expr`.
215    pub fn data(&self) -> &T {
216        &self.data
217    }
218
219    /// Access the data stored on the `Expr`, taking ownership and consuming the
220    /// `Expr`.
221    pub fn into_data(self) -> T {
222        self.data
223    }
224
225    /// Consume the `Expr`, returning the `ExprKind`, `source_loc`, and stored
226    /// data.
227    pub fn into_parts(self) -> (ExprKind<T>, Option<Loc>, T) {
228        (self.expr_kind, self.source_loc, self.data)
229    }
230
231    /// Access the `Loc` stored on the `Expr`.
232    pub fn source_loc(&self) -> Option<&Loc> {
233        self.source_loc.as_ref()
234    }
235
236    /// Return the `Expr`, but with the new `source_loc` (or `None`).
237    pub fn with_maybe_source_loc(self, source_loc: Option<Loc>) -> Self {
238        Self { source_loc, ..self }
239    }
240
241    /// Update the data for this `Expr`. A convenient function used by the
242    /// Validator in one place.
243    pub fn set_data(&mut self, data: T) {
244        self.data = data;
245    }
246
247    /// Check whether this expression is an entity reference
248    ///
249    /// This is used for policy scopes, where some syntax is
250    /// required to be an entity reference.
251    pub fn is_ref(&self) -> bool {
252        match &self.expr_kind {
253            ExprKind::Lit(lit) => lit.is_ref(),
254            _ => false,
255        }
256    }
257
258    /// Check whether this expression is a slot.
259    pub fn is_slot(&self) -> bool {
260        matches!(&self.expr_kind, ExprKind::Slot(_))
261    }
262
263    /// Check whether this expression is a set of entity references
264    ///
265    /// This is used for policy scopes, where some syntax is
266    /// required to be an entity reference set.
267    pub fn is_ref_set(&self) -> bool {
268        match &self.expr_kind {
269            ExprKind::Set(exprs) => exprs.iter().all(|e| e.is_ref()),
270            _ => false,
271        }
272    }
273
274    /// Iterate over all sub-expressions in this expression
275    pub fn subexpressions(&self) -> impl Iterator<Item = &Self> {
276        expr_iterator::ExprIterator::new(self)
277    }
278
279    /// Iterate over all of the slots in this policy AST
280    pub fn slots(&self) -> impl Iterator<Item = Slot> + '_ {
281        self.subexpressions()
282            .filter_map(|exp| match &exp.expr_kind {
283                ExprKind::Slot(slotid) => Some(Slot {
284                    id: *slotid,
285                    loc: exp.source_loc().cloned(),
286                }),
287                _ => None,
288            })
289    }
290
291    /// Determine if the expression is projectable under partial evaluation
292    /// An expression is projectable if it's guaranteed to never error on evaluation
293    /// This is true if the expression is entirely composed of values or unknowns
294    pub fn is_projectable(&self) -> bool {
295        self.subexpressions().all(|e| {
296            matches!(
297                e.expr_kind(),
298                ExprKind::Lit(_)
299                    | ExprKind::Unknown(_)
300                    | ExprKind::Set(_)
301                    | ExprKind::Var(_)
302                    | ExprKind::Record(_)
303            )
304        })
305    }
306
307    /// Try to compute the runtime type of this expression. This operation may
308    /// fail (returning `None`), for example, when asked to get the type of any
309    /// variables, any attributes of entities or records, or an `unknown`
310    /// without an explicitly annotated type.
311    ///
312    /// Also note that this is _not_ typechecking the expression. It does not
313    /// check that the expression actually evaluates to a value (as opposed to
314    /// erroring).
315    ///
316    /// Because of these limitations, this function should only be used to
317    /// obtain a type for use in diagnostics such as error strings.
318    pub fn try_type_of(&self, extensions: &Extensions<'_>) -> Option<Type> {
319        match &self.expr_kind {
320            ExprKind::Lit(l) => Some(l.type_of()),
321            ExprKind::Var(_) => None,
322            ExprKind::Slot(_) => None,
323            ExprKind::Unknown(u) => u.type_annotation.clone(),
324            ExprKind::If {
325                then_expr,
326                else_expr,
327                ..
328            } => {
329                let type_of_then = then_expr.try_type_of(extensions);
330                let type_of_else = else_expr.try_type_of(extensions);
331                if type_of_then == type_of_else {
332                    type_of_then
333                } else {
334                    None
335                }
336            }
337            ExprKind::And { .. } => Some(Type::Bool),
338            ExprKind::Or { .. } => Some(Type::Bool),
339            ExprKind::UnaryApp {
340                op: UnaryOp::Neg, ..
341            } => Some(Type::Long),
342            ExprKind::UnaryApp {
343                op: UnaryOp::Not, ..
344            } => Some(Type::Bool),
345            ExprKind::UnaryApp {
346                op: UnaryOp::IsEmpty,
347                ..
348            } => Some(Type::Bool),
349            ExprKind::BinaryApp {
350                op: BinaryOp::Add | BinaryOp::Mul | BinaryOp::Sub,
351                ..
352            } => Some(Type::Long),
353            ExprKind::BinaryApp {
354                op:
355                    BinaryOp::Contains
356                    | BinaryOp::ContainsAll
357                    | BinaryOp::ContainsAny
358                    | BinaryOp::Eq
359                    | BinaryOp::In
360                    | BinaryOp::Less
361                    | BinaryOp::LessEq,
362                ..
363            } => Some(Type::Bool),
364            ExprKind::BinaryApp {
365                op: BinaryOp::HasTag,
366                ..
367            } => Some(Type::Bool),
368            ExprKind::ExtensionFunctionApp { fn_name, .. } => extensions
369                .func(fn_name)
370                .ok()?
371                .return_type()
372                .map(|rty| rty.clone().into()),
373            // We could try to be more complete here, but we can't do all that
374            // much better without evaluating the argument. Even if we know it's
375            // a record `Type::Record` tells us nothing about the type of the
376            // attribute.
377            ExprKind::GetAttr { .. } => None,
378            // similarly to `GetAttr`
379            ExprKind::BinaryApp {
380                op: BinaryOp::GetTag,
381                ..
382            } => None,
383            ExprKind::HasAttr { .. } => Some(Type::Bool),
384            ExprKind::Like { .. } => Some(Type::Bool),
385            ExprKind::Is { .. } => Some(Type::Bool),
386            ExprKind::Set(_) => Some(Type::Set),
387            ExprKind::Record(_) => Some(Type::Record),
388        }
389    }
390}
391
392#[allow(dead_code)] // some constructors are currently unused, or used only in tests, but provided for completeness
393#[allow(clippy::should_implement_trait)] // the names of arithmetic constructors alias with those of certain trait methods such as `add` of `std::ops::Add`
394impl Expr {
395    /// Create an `Expr` that's just a single `Literal`.
396    ///
397    /// Note that you can pass this a `Literal`, an `Integer`, a `String`, etc.
398    pub fn val(v: impl Into<Literal>) -> Self {
399        ExprBuilder::new().val(v)
400    }
401
402    /// Create an `Expr` that's just a single `Unknown`.
403    pub fn unknown(u: Unknown) -> Self {
404        ExprBuilder::new().unknown(u)
405    }
406
407    /// Create an `Expr` that's just this literal `Var`
408    pub fn var(v: Var) -> Self {
409        ExprBuilder::new().var(v)
410    }
411
412    /// Create an `Expr` that's just this `SlotId`
413    pub fn slot(s: SlotId) -> Self {
414        ExprBuilder::new().slot(s)
415    }
416
417    /// Create a ternary (if-then-else) `Expr`.
418    ///
419    /// `test_expr` must evaluate to a Bool type
420    pub fn ite(test_expr: Expr, then_expr: Expr, else_expr: Expr) -> Self {
421        ExprBuilder::new().ite(test_expr, then_expr, else_expr)
422    }
423
424    /// Create a ternary (if-then-else) `Expr`.
425    /// Takes `Arc`s instead of owned `Expr`s.
426    /// `test_expr` must evaluate to a Bool type
427    pub fn ite_arc(test_expr: Arc<Expr>, then_expr: Arc<Expr>, else_expr: Arc<Expr>) -> Self {
428        ExprBuilder::new().ite_arc(test_expr, then_expr, else_expr)
429    }
430
431    /// Create a 'not' expression. `e` must evaluate to Bool type
432    pub fn not(e: Expr) -> Self {
433        ExprBuilder::new().not(e)
434    }
435
436    /// Create a '==' expression
437    pub fn is_eq(e1: Expr, e2: Expr) -> Self {
438        ExprBuilder::new().is_eq(e1, e2)
439    }
440
441    /// Create a '!=' expression
442    pub fn noteq(e1: Expr, e2: Expr) -> Self {
443        ExprBuilder::new().noteq(e1, e2)
444    }
445
446    /// Create an 'and' expression. Arguments must evaluate to Bool type
447    pub fn and(e1: Expr, e2: Expr) -> Self {
448        ExprBuilder::new().and(e1, e2)
449    }
450
451    /// Create an 'or' expression. Arguments must evaluate to Bool type
452    pub fn or(e1: Expr, e2: Expr) -> Self {
453        ExprBuilder::new().or(e1, e2)
454    }
455
456    /// Create a '<' expression. Arguments must evaluate to Long type
457    pub fn less(e1: Expr, e2: Expr) -> Self {
458        ExprBuilder::new().less(e1, e2)
459    }
460
461    /// Create a '<=' expression. Arguments must evaluate to Long type
462    pub fn lesseq(e1: Expr, e2: Expr) -> Self {
463        ExprBuilder::new().lesseq(e1, e2)
464    }
465
466    /// Create a '>' expression. Arguments must evaluate to Long type
467    pub fn greater(e1: Expr, e2: Expr) -> Self {
468        ExprBuilder::new().greater(e1, e2)
469    }
470
471    /// Create a '>=' expression. Arguments must evaluate to Long type
472    pub fn greatereq(e1: Expr, e2: Expr) -> Self {
473        ExprBuilder::new().greatereq(e1, e2)
474    }
475
476    /// Create an 'add' expression. Arguments must evaluate to Long type
477    pub fn add(e1: Expr, e2: Expr) -> Self {
478        ExprBuilder::new().add(e1, e2)
479    }
480
481    /// Create a 'sub' expression. Arguments must evaluate to Long type
482    pub fn sub(e1: Expr, e2: Expr) -> Self {
483        ExprBuilder::new().sub(e1, e2)
484    }
485
486    /// Create a 'mul' expression. Arguments must evaluate to Long type
487    pub fn mul(e1: Expr, e2: Expr) -> Self {
488        ExprBuilder::new().mul(e1, e2)
489    }
490
491    /// Create a 'neg' expression. `e` must evaluate to Long type.
492    pub fn neg(e: Expr) -> Self {
493        ExprBuilder::new().neg(e)
494    }
495
496    /// Create an 'in' expression. First argument must evaluate to Entity type.
497    /// Second argument must evaluate to either Entity type or Set type where
498    /// all set elements have Entity type.
499    pub fn is_in(e1: Expr, e2: Expr) -> Self {
500        ExprBuilder::new().is_in(e1, e2)
501    }
502
503    /// Create a `contains` expression.
504    /// First argument must have Set type.
505    pub fn contains(e1: Expr, e2: Expr) -> Self {
506        ExprBuilder::new().contains(e1, e2)
507    }
508
509    /// Create a `containsAll` expression. Arguments must evaluate to Set type
510    pub fn contains_all(e1: Expr, e2: Expr) -> Self {
511        ExprBuilder::new().contains_all(e1, e2)
512    }
513
514    /// Create a `containsAny` expression. Arguments must evaluate to Set type
515    pub fn contains_any(e1: Expr, e2: Expr) -> Self {
516        ExprBuilder::new().contains_any(e1, e2)
517    }
518
519    /// Create a `isEmpty` expression. Argument must evaluate to Set type
520    pub fn is_empty(e: Expr) -> Self {
521        ExprBuilder::new().is_empty(e)
522    }
523
524    /// Create a `getTag` expression.
525    /// `expr` must evaluate to Entity type, `tag` must evaluate to String type.
526    pub fn get_tag(expr: Expr, tag: Expr) -> Self {
527        ExprBuilder::new().get_tag(expr, tag)
528    }
529
530    /// Create a `hasTag` expression.
531    /// `expr` must evaluate to Entity type, `tag` must evaluate to String type.
532    pub fn has_tag(expr: Expr, tag: Expr) -> Self {
533        ExprBuilder::new().has_tag(expr, tag)
534    }
535
536    /// Create an `Expr` which evaluates to a Set of the given `Expr`s
537    pub fn set(exprs: impl IntoIterator<Item = Expr>) -> Self {
538        ExprBuilder::new().set(exprs)
539    }
540
541    /// Create an `Expr` which evaluates to a Record with the given (key, value) pairs.
542    pub fn record(
543        pairs: impl IntoIterator<Item = (SmolStr, Expr)>,
544    ) -> Result<Self, ExpressionConstructionError> {
545        ExprBuilder::new().record(pairs)
546    }
547
548    /// Create an `Expr` which evaluates to a Record with the given key-value mapping.
549    ///
550    /// If you have an iterator of pairs, generally prefer calling
551    /// `Expr::record()` instead of `.collect()`-ing yourself and calling this,
552    /// potentially for efficiency reasons but also because `Expr::record()`
553    /// will properly handle duplicate keys but your own `.collect()` will not
554    /// (by default).
555    pub fn record_arc(map: Arc<BTreeMap<SmolStr, Expr>>) -> Self {
556        ExprBuilder::new().record_arc(map)
557    }
558
559    /// Create an `Expr` which calls the extension function with the given
560    /// `Name` on `args`
561    pub fn call_extension_fn(fn_name: Name, args: Vec<Expr>) -> Self {
562        ExprBuilder::new().call_extension_fn(fn_name, args)
563    }
564
565    /// Create an application `Expr` which applies the given built-in unary
566    /// operator to the given `arg`
567    pub fn unary_app(op: impl Into<UnaryOp>, arg: Expr) -> Self {
568        ExprBuilder::new().unary_app(op, arg)
569    }
570
571    /// Create an application `Expr` which applies the given built-in binary
572    /// operator to `arg1` and `arg2`
573    pub fn binary_app(op: impl Into<BinaryOp>, arg1: Expr, arg2: Expr) -> Self {
574        ExprBuilder::new().binary_app(op, arg1, arg2)
575    }
576
577    /// Create an `Expr` which gets a given attribute of a given `Entity` or record.
578    ///
579    /// `expr` must evaluate to either Entity or Record type
580    pub fn get_attr(expr: Expr, attr: SmolStr) -> Self {
581        ExprBuilder::new().get_attr(expr, attr)
582    }
583
584    /// Create an `Expr` which tests for the existence of a given
585    /// attribute on a given `Entity` or record.
586    ///
587    /// `expr` must evaluate to either Entity or Record type
588    pub fn has_attr(expr: Expr, attr: SmolStr) -> Self {
589        ExprBuilder::new().has_attr(expr, attr)
590    }
591
592    /// Create a 'like' expression.
593    ///
594    /// `expr` must evaluate to a String type
595    pub fn like(expr: Expr, pattern: Pattern) -> Self {
596        ExprBuilder::new().like(expr, pattern)
597    }
598
599    /// Create an `is` expression.
600    pub fn is_entity_type(expr: Expr, entity_type: EntityType) -> Self {
601        ExprBuilder::new().is_entity_type(expr, entity_type)
602    }
603
604    /// Check if an expression contains any symbolic unknowns
605    pub fn contains_unknown(&self) -> bool {
606        self.subexpressions()
607            .any(|e| matches!(e.expr_kind(), ExprKind::Unknown(_)))
608    }
609
610    /// Get all unknowns in an expression
611    pub fn unknowns(&self) -> impl Iterator<Item = &Unknown> {
612        self.subexpressions()
613            .filter_map(|subexpr| match subexpr.expr_kind() {
614                ExprKind::Unknown(u) => Some(u),
615                _ => None,
616            })
617    }
618
619    /// Substitute unknowns with concrete values.
620    ///
621    /// Ignores unmapped unknowns.
622    /// Ignores type annotations on unknowns.
623    pub fn substitute(&self, definitions: &HashMap<SmolStr, Value>) -> Expr {
624        match self.substitute_general::<UntypedSubstitution>(definitions) {
625            Ok(e) => e,
626            Err(empty) => match empty {},
627        }
628    }
629
630    /// Substitute unknowns with concrete values.
631    ///
632    /// Ignores unmapped unknowns.
633    /// Errors if the substituted value does not match the type annotation on the unknown.
634    pub fn substitute_typed(
635        &self,
636        definitions: &HashMap<SmolStr, Value>,
637    ) -> Result<Expr, SubstitutionError> {
638        self.substitute_general::<TypedSubstitution>(definitions)
639    }
640
641    /// Substitute unknowns with values
642    ///
643    /// Generic over the function implementing the substitution to allow for multiple error behaviors
644    fn substitute_general<T: SubstitutionFunction>(
645        &self,
646        definitions: &HashMap<SmolStr, Value>,
647    ) -> Result<Expr, T::Err> {
648        match self.expr_kind() {
649            ExprKind::Lit(_) => Ok(self.clone()),
650            ExprKind::Unknown(u @ Unknown { name, .. }) => T::substitute(u, definitions.get(name)),
651            ExprKind::Var(_) => Ok(self.clone()),
652            ExprKind::Slot(_) => Ok(self.clone()),
653            ExprKind::If {
654                test_expr,
655                then_expr,
656                else_expr,
657            } => Ok(Expr::ite(
658                test_expr.substitute_general::<T>(definitions)?,
659                then_expr.substitute_general::<T>(definitions)?,
660                else_expr.substitute_general::<T>(definitions)?,
661            )),
662            ExprKind::And { left, right } => Ok(Expr::and(
663                left.substitute_general::<T>(definitions)?,
664                right.substitute_general::<T>(definitions)?,
665            )),
666            ExprKind::Or { left, right } => Ok(Expr::or(
667                left.substitute_general::<T>(definitions)?,
668                right.substitute_general::<T>(definitions)?,
669            )),
670            ExprKind::UnaryApp { op, arg } => Ok(Expr::unary_app(
671                *op,
672                arg.substitute_general::<T>(definitions)?,
673            )),
674            ExprKind::BinaryApp { op, arg1, arg2 } => Ok(Expr::binary_app(
675                *op,
676                arg1.substitute_general::<T>(definitions)?,
677                arg2.substitute_general::<T>(definitions)?,
678            )),
679            ExprKind::ExtensionFunctionApp { fn_name, args } => {
680                let args = args
681                    .iter()
682                    .map(|e| e.substitute_general::<T>(definitions))
683                    .collect::<Result<Vec<Expr>, _>>()?;
684
685                Ok(Expr::call_extension_fn(fn_name.clone(), args))
686            }
687            ExprKind::GetAttr { expr, attr } => Ok(Expr::get_attr(
688                expr.substitute_general::<T>(definitions)?,
689                attr.clone(),
690            )),
691            ExprKind::HasAttr { expr, attr } => Ok(Expr::has_attr(
692                expr.substitute_general::<T>(definitions)?,
693                attr.clone(),
694            )),
695            ExprKind::Like { expr, pattern } => Ok(Expr::like(
696                expr.substitute_general::<T>(definitions)?,
697                pattern.clone(),
698            )),
699            ExprKind::Set(members) => {
700                let members = members
701                    .iter()
702                    .map(|e| e.substitute_general::<T>(definitions))
703                    .collect::<Result<Vec<_>, _>>()?;
704                Ok(Expr::set(members))
705            }
706            ExprKind::Record(map) => {
707                let map = map
708                    .iter()
709                    .map(|(name, e)| Ok((name.clone(), e.substitute_general::<T>(definitions)?)))
710                    .collect::<Result<BTreeMap<_, _>, _>>()?;
711                // PANIC SAFETY: cannot have a duplicate key because the input was already a BTreeMap
712                #[allow(clippy::expect_used)]
713                Ok(Expr::record(map)
714                    .expect("cannot have a duplicate key because the input was already a BTreeMap"))
715            }
716            ExprKind::Is { expr, entity_type } => Ok(Expr::is_entity_type(
717                expr.substitute_general::<T>(definitions)?,
718                entity_type.clone(),
719            )),
720        }
721    }
722}
723
724/// A trait for customizing the error behavior of substitution
725trait SubstitutionFunction {
726    /// The potential errors this substitution function can return
727    type Err;
728    /// The function for implementing the substitution.
729    ///
730    /// Takes the expression being substituted,
731    /// The substitution from the map (if present)
732    /// and the type annotation from the unknown (if present)
733    fn substitute(value: &Unknown, substitute: Option<&Value>) -> Result<Expr, Self::Err>;
734}
735
736struct TypedSubstitution {}
737
738impl SubstitutionFunction for TypedSubstitution {
739    type Err = SubstitutionError;
740
741    fn substitute(value: &Unknown, substitute: Option<&Value>) -> Result<Expr, Self::Err> {
742        match (substitute, &value.type_annotation) {
743            (None, _) => Ok(Expr::unknown(value.clone())),
744            (Some(v), None) => Ok(v.clone().into()),
745            (Some(v), Some(t)) => {
746                if v.type_of() == *t {
747                    Ok(v.clone().into())
748                } else {
749                    Err(SubstitutionError::TypeError {
750                        expected: t.clone(),
751                        actual: v.type_of(),
752                    })
753                }
754            }
755        }
756    }
757}
758
759struct UntypedSubstitution {}
760
761impl SubstitutionFunction for UntypedSubstitution {
762    type Err = std::convert::Infallible;
763
764    fn substitute(value: &Unknown, substitute: Option<&Value>) -> Result<Expr, Self::Err> {
765        Ok(substitute
766            .map(|v| v.clone().into())
767            .unwrap_or_else(|| Expr::unknown(value.clone())))
768    }
769}
770
771impl<T: Clone> std::fmt::Display for Expr<T> {
772    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
773        // To avoid code duplication between pretty-printers for AST Expr and EST Expr,
774        // we just convert to EST and use the EST pretty-printer.
775        // Note that converting AST->EST is lossless and infallible.
776        write!(f, "{}", crate::est::Expr::from(self.clone()))
777    }
778}
779
780impl<T: Clone> BoundedDisplay for Expr<T> {
781    fn fmt(&self, f: &mut impl std::fmt::Write, n: Option<usize>) -> std::fmt::Result {
782        // Like the `std::fmt::Display` impl, we convert to EST and use the EST
783        // pretty-printer. Note that converting AST->EST is lossless and infallible.
784        BoundedDisplay::fmt(&crate::est::Expr::from(self.clone()), f, n)
785    }
786}
787
788impl std::str::FromStr for Expr {
789    type Err = ParseErrors;
790
791    fn from_str(s: &str) -> Result<Expr, Self::Err> {
792        crate::parser::parse_expr(s)
793    }
794}
795
796/// Enum for errors encountered during substitution
797#[derive(Debug, Clone, Diagnostic, Error)]
798pub enum SubstitutionError {
799    /// The supplied value did not match the type annotation on the unknown.
800    #[error("expected a value of type {expected}, got a value of type {actual}")]
801    TypeError {
802        /// The expected type, ie: the type the unknown was annotated with
803        expected: Type,
804        /// The type of the provided value
805        actual: Type,
806    },
807}
808
809/// Representation of a partial-evaluation Unknown at the AST level
810#[derive(Serialize, Deserialize, Hash, Debug, Clone, PartialEq, Eq)]
811pub struct Unknown {
812    /// The name of the unknown
813    pub name: SmolStr,
814    /// The type of the values that can be substituted in for the unknown.
815    /// If `None`, we have no type annotation, and thus a value of any type can
816    /// be substituted.
817    pub type_annotation: Option<Type>,
818}
819
820impl Unknown {
821    /// Create a new untyped `Unknown`
822    pub fn new_untyped(name: impl Into<SmolStr>) -> Self {
823        Self {
824            name: name.into(),
825            type_annotation: None,
826        }
827    }
828
829    /// Create a new `Unknown` with type annotation. (Only values of the given
830    /// type can be substituted.)
831    pub fn new_with_type(name: impl Into<SmolStr>, ty: Type) -> Self {
832        Self {
833            name: name.into(),
834            type_annotation: Some(ty),
835        }
836    }
837}
838
839impl std::fmt::Display for Unknown {
840    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
841        // Like the Display impl for Expr, we delegate to the EST pretty-printer,
842        // to avoid code duplication
843        write!(f, "{}", crate::est::Expr::from(Expr::unknown(self.clone())))
844    }
845}
846
847/// Builder for constructing `Expr` objects annotated with some `data`
848/// (possibly taking default value) and optionally a `source_loc`.
849#[derive(Clone, Debug)]
850pub struct ExprBuilder<T> {
851    source_loc: Option<Loc>,
852    data: T,
853}
854
855impl<T: Default + Clone> expr_builder::ExprBuilder for ExprBuilder<T> {
856    type Expr = Expr<T>;
857
858    type Data = T;
859
860    fn loc(&self) -> Option<&Loc> {
861        self.source_loc.as_ref()
862    }
863
864    fn data(&self) -> &Self::Data {
865        &self.data
866    }
867
868    fn with_data(data: T) -> Self {
869        Self {
870            source_loc: None,
871            data,
872        }
873    }
874
875    fn with_maybe_source_loc(mut self, maybe_source_loc: Option<&Loc>) -> Self {
876        self.source_loc = maybe_source_loc.cloned();
877        self
878    }
879
880    /// Create an `Expr` that's just a single `Literal`.
881    ///
882    /// Note that you can pass this a `Literal`, an `Integer`, a `String`, etc.
883    fn val(self, v: impl Into<Literal>) -> Expr<T> {
884        self.with_expr_kind(ExprKind::Lit(v.into()))
885    }
886
887    /// Create an `Unknown` `Expr`
888    fn unknown(self, u: Unknown) -> Expr<T> {
889        self.with_expr_kind(ExprKind::Unknown(u))
890    }
891
892    /// Create an `Expr` that's just this literal `Var`
893    fn var(self, v: Var) -> Expr<T> {
894        self.with_expr_kind(ExprKind::Var(v))
895    }
896
897    /// Create an `Expr` that's just this `SlotId`
898    fn slot(self, s: SlotId) -> Expr<T> {
899        self.with_expr_kind(ExprKind::Slot(s))
900    }
901
902    /// Create a ternary (if-then-else) `Expr`.
903    ///
904    /// `test_expr` must evaluate to a Bool type
905    fn ite(self, test_expr: Expr<T>, then_expr: Expr<T>, else_expr: Expr<T>) -> Expr<T> {
906        self.with_expr_kind(ExprKind::If {
907            test_expr: Arc::new(test_expr),
908            then_expr: Arc::new(then_expr),
909            else_expr: Arc::new(else_expr),
910        })
911    }
912
913    /// Create a 'not' expression. `e` must evaluate to Bool type
914    fn not(self, e: Expr<T>) -> Expr<T> {
915        self.with_expr_kind(ExprKind::UnaryApp {
916            op: UnaryOp::Not,
917            arg: Arc::new(e),
918        })
919    }
920
921    /// Create a '==' expression
922    fn is_eq(self, e1: Expr<T>, e2: Expr<T>) -> Expr<T> {
923        self.with_expr_kind(ExprKind::BinaryApp {
924            op: BinaryOp::Eq,
925            arg1: Arc::new(e1),
926            arg2: Arc::new(e2),
927        })
928    }
929
930    /// Create an 'and' expression. Arguments must evaluate to Bool type
931    fn and(self, e1: Expr<T>, e2: Expr<T>) -> Expr<T> {
932        self.with_expr_kind(match (&e1.expr_kind, &e2.expr_kind) {
933            (ExprKind::Lit(Literal::Bool(b1)), ExprKind::Lit(Literal::Bool(b2))) => {
934                ExprKind::Lit(Literal::Bool(*b1 && *b2))
935            }
936            _ => ExprKind::And {
937                left: Arc::new(e1),
938                right: Arc::new(e2),
939            },
940        })
941    }
942
943    /// Create an 'or' expression. Arguments must evaluate to Bool type
944    fn or(self, e1: Expr<T>, e2: Expr<T>) -> Expr<T> {
945        self.with_expr_kind(match (&e1.expr_kind, &e2.expr_kind) {
946            (ExprKind::Lit(Literal::Bool(b1)), ExprKind::Lit(Literal::Bool(b2))) => {
947                ExprKind::Lit(Literal::Bool(*b1 || *b2))
948            }
949
950            _ => ExprKind::Or {
951                left: Arc::new(e1),
952                right: Arc::new(e2),
953            },
954        })
955    }
956
957    /// Create a '<' expression. Arguments must evaluate to Long type
958    fn less(self, e1: Expr<T>, e2: Expr<T>) -> Expr<T> {
959        self.with_expr_kind(ExprKind::BinaryApp {
960            op: BinaryOp::Less,
961            arg1: Arc::new(e1),
962            arg2: Arc::new(e2),
963        })
964    }
965
966    /// Create a '<=' expression. Arguments must evaluate to Long type
967    fn lesseq(self, e1: Expr<T>, e2: Expr<T>) -> Expr<T> {
968        self.with_expr_kind(ExprKind::BinaryApp {
969            op: BinaryOp::LessEq,
970            arg1: Arc::new(e1),
971            arg2: Arc::new(e2),
972        })
973    }
974
975    /// Create an 'add' expression. Arguments must evaluate to Long type
976    fn add(self, e1: Expr<T>, e2: Expr<T>) -> Expr<T> {
977        self.with_expr_kind(ExprKind::BinaryApp {
978            op: BinaryOp::Add,
979            arg1: Arc::new(e1),
980            arg2: Arc::new(e2),
981        })
982    }
983
984    /// Create a 'sub' expression. Arguments must evaluate to Long type
985    fn sub(self, e1: Expr<T>, e2: Expr<T>) -> Expr<T> {
986        self.with_expr_kind(ExprKind::BinaryApp {
987            op: BinaryOp::Sub,
988            arg1: Arc::new(e1),
989            arg2: Arc::new(e2),
990        })
991    }
992
993    /// Create a 'mul' expression. Arguments must evaluate to Long type
994    fn mul(self, e1: Expr<T>, e2: Expr<T>) -> Expr<T> {
995        self.with_expr_kind(ExprKind::BinaryApp {
996            op: BinaryOp::Mul,
997            arg1: Arc::new(e1),
998            arg2: Arc::new(e2),
999        })
1000    }
1001
1002    /// Create a 'neg' expression. `e` must evaluate to Long type.
1003    fn neg(self, e: Expr<T>) -> Expr<T> {
1004        self.with_expr_kind(ExprKind::UnaryApp {
1005            op: UnaryOp::Neg,
1006            arg: Arc::new(e),
1007        })
1008    }
1009
1010    /// Create an 'in' expression. First argument must evaluate to Entity type.
1011    /// Second argument must evaluate to either Entity type or Set type where
1012    /// all set elements have Entity type.
1013    fn is_in(self, e1: Expr<T>, e2: Expr<T>) -> Expr<T> {
1014        self.with_expr_kind(ExprKind::BinaryApp {
1015            op: BinaryOp::In,
1016            arg1: Arc::new(e1),
1017            arg2: Arc::new(e2),
1018        })
1019    }
1020
1021    /// Create a 'contains' expression.
1022    /// First argument must have Set type.
1023    fn contains(self, e1: Expr<T>, e2: Expr<T>) -> Expr<T> {
1024        self.with_expr_kind(ExprKind::BinaryApp {
1025            op: BinaryOp::Contains,
1026            arg1: Arc::new(e1),
1027            arg2: Arc::new(e2),
1028        })
1029    }
1030
1031    /// Create a 'contains_all' expression. Arguments must evaluate to Set type
1032    fn contains_all(self, e1: Expr<T>, e2: Expr<T>) -> Expr<T> {
1033        self.with_expr_kind(ExprKind::BinaryApp {
1034            op: BinaryOp::ContainsAll,
1035            arg1: Arc::new(e1),
1036            arg2: Arc::new(e2),
1037        })
1038    }
1039
1040    /// Create an 'contains_any' expression. Arguments must evaluate to Set type
1041    fn contains_any(self, e1: Expr<T>, e2: Expr<T>) -> Expr<T> {
1042        self.with_expr_kind(ExprKind::BinaryApp {
1043            op: BinaryOp::ContainsAny,
1044            arg1: Arc::new(e1),
1045            arg2: Arc::new(e2),
1046        })
1047    }
1048
1049    /// Create an 'is_empty' expression. Argument must evaluate to Set type
1050    fn is_empty(self, expr: Expr<T>) -> Expr<T> {
1051        self.with_expr_kind(ExprKind::UnaryApp {
1052            op: UnaryOp::IsEmpty,
1053            arg: Arc::new(expr),
1054        })
1055    }
1056
1057    /// Create a 'getTag' expression.
1058    /// `expr` must evaluate to Entity type, `tag` must evaluate to String type.
1059    fn get_tag(self, expr: Expr<T>, tag: Expr<T>) -> Expr<T> {
1060        self.with_expr_kind(ExprKind::BinaryApp {
1061            op: BinaryOp::GetTag,
1062            arg1: Arc::new(expr),
1063            arg2: Arc::new(tag),
1064        })
1065    }
1066
1067    /// Create a 'hasTag' expression.
1068    /// `expr` must evaluate to Entity type, `tag` must evaluate to String type.
1069    fn has_tag(self, expr: Expr<T>, tag: Expr<T>) -> Expr<T> {
1070        self.with_expr_kind(ExprKind::BinaryApp {
1071            op: BinaryOp::HasTag,
1072            arg1: Arc::new(expr),
1073            arg2: Arc::new(tag),
1074        })
1075    }
1076
1077    /// Create an `Expr` which evaluates to a Set of the given `Expr`s
1078    fn set(self, exprs: impl IntoIterator<Item = Expr<T>>) -> Expr<T> {
1079        self.with_expr_kind(ExprKind::Set(Arc::new(exprs.into_iter().collect())))
1080    }
1081
1082    /// Create an `Expr` which evaluates to a Record with the given (key, value) pairs.
1083    fn record(
1084        self,
1085        pairs: impl IntoIterator<Item = (SmolStr, Expr<T>)>,
1086    ) -> Result<Expr<T>, ExpressionConstructionError> {
1087        let mut map = BTreeMap::new();
1088        for (k, v) in pairs {
1089            match map.entry(k) {
1090                btree_map::Entry::Occupied(oentry) => {
1091                    return Err(expression_construction_errors::DuplicateKeyError {
1092                        key: oentry.key().clone(),
1093                        context: "in record literal",
1094                    }
1095                    .into());
1096                }
1097                btree_map::Entry::Vacant(ventry) => {
1098                    ventry.insert(v);
1099                }
1100            }
1101        }
1102        Ok(self.with_expr_kind(ExprKind::Record(Arc::new(map))))
1103    }
1104
1105    /// Create an `Expr` which calls the extension function with the given
1106    /// `Name` on `args`
1107    fn call_extension_fn(self, fn_name: Name, args: impl IntoIterator<Item = Expr<T>>) -> Expr<T> {
1108        self.with_expr_kind(ExprKind::ExtensionFunctionApp {
1109            fn_name,
1110            args: Arc::new(args.into_iter().collect()),
1111        })
1112    }
1113
1114    /// Create an application `Expr` which applies the given built-in unary
1115    /// operator to the given `arg`
1116    fn unary_app(self, op: impl Into<UnaryOp>, arg: Expr<T>) -> Expr<T> {
1117        self.with_expr_kind(ExprKind::UnaryApp {
1118            op: op.into(),
1119            arg: Arc::new(arg),
1120        })
1121    }
1122
1123    /// Create an application `Expr` which applies the given built-in binary
1124    /// operator to `arg1` and `arg2`
1125    fn binary_app(self, op: impl Into<BinaryOp>, arg1: Expr<T>, arg2: Expr<T>) -> Expr<T> {
1126        self.with_expr_kind(ExprKind::BinaryApp {
1127            op: op.into(),
1128            arg1: Arc::new(arg1),
1129            arg2: Arc::new(arg2),
1130        })
1131    }
1132
1133    /// Create an `Expr` which gets a given attribute of a given `Entity` or record.
1134    ///
1135    /// `expr` must evaluate to either Entity or Record type
1136    fn get_attr(self, expr: Expr<T>, attr: SmolStr) -> Expr<T> {
1137        self.with_expr_kind(ExprKind::GetAttr {
1138            expr: Arc::new(expr),
1139            attr,
1140        })
1141    }
1142
1143    /// Create an `Expr` which tests for the existence of a given
1144    /// attribute on a given `Entity` or record.
1145    ///
1146    /// `expr` must evaluate to either Entity or Record type
1147    fn has_attr(self, expr: Expr<T>, attr: SmolStr) -> Expr<T> {
1148        self.with_expr_kind(ExprKind::HasAttr {
1149            expr: Arc::new(expr),
1150            attr,
1151        })
1152    }
1153
1154    /// Create a 'like' expression.
1155    ///
1156    /// `expr` must evaluate to a String type
1157    fn like(self, expr: Expr<T>, pattern: Pattern) -> Expr<T> {
1158        self.with_expr_kind(ExprKind::Like {
1159            expr: Arc::new(expr),
1160            pattern,
1161        })
1162    }
1163
1164    /// Create an 'is' expression.
1165    fn is_entity_type(self, expr: Expr<T>, entity_type: EntityType) -> Expr<T> {
1166        self.with_expr_kind(ExprKind::Is {
1167            expr: Arc::new(expr),
1168            entity_type,
1169        })
1170    }
1171}
1172
1173impl<T> ExprBuilder<T> {
1174    /// Construct an `Expr` containing the `data` and `source_loc` in this
1175    /// `ExprBuilder` and the given `ExprKind`.
1176    pub fn with_expr_kind(self, expr_kind: ExprKind<T>) -> Expr<T> {
1177        Expr::new(expr_kind, self.source_loc, self.data)
1178    }
1179
1180    /// Create a ternary (if-then-else) `Expr`.
1181    /// Takes `Arc`s instead of owned `Expr`s.
1182    /// `test_expr` must evaluate to a Bool type
1183    pub fn ite_arc(
1184        self,
1185        test_expr: Arc<Expr<T>>,
1186        then_expr: Arc<Expr<T>>,
1187        else_expr: Arc<Expr<T>>,
1188    ) -> Expr<T> {
1189        self.with_expr_kind(ExprKind::If {
1190            test_expr,
1191            then_expr,
1192            else_expr,
1193        })
1194    }
1195
1196    /// Create an `Expr` which evaluates to a Record with the given key-value mapping.
1197    ///
1198    /// If you have an iterator of pairs, generally prefer calling `.record()`
1199    /// instead of `.collect()`-ing yourself and calling this, potentially for
1200    /// efficiency reasons but also because `.record()` will properly handle
1201    /// duplicate keys but your own `.collect()` will not (by default).
1202    pub fn record_arc(self, map: Arc<BTreeMap<SmolStr, Expr<T>>>) -> Expr<T> {
1203        self.with_expr_kind(ExprKind::Record(map))
1204    }
1205}
1206
1207impl<T: Clone + Default> ExprBuilder<T> {
1208    /// Utility used the validator to get an expression with the same source
1209    /// location as an existing expression. This is done when reconstructing the
1210    /// `Expr` with type information.
1211    pub fn with_same_source_loc<U>(self, expr: &Expr<U>) -> Self {
1212        self.with_maybe_source_loc(expr.source_loc.as_ref())
1213    }
1214}
1215
1216/// Errors when constructing an expression
1217//
1218// CAUTION: this type is publicly exported in `cedar-policy`.
1219// Don't make fields `pub`, don't make breaking changes, and use caution
1220// when adding public methods.
1221#[derive(Debug, PartialEq, Eq, Clone, Diagnostic, Error)]
1222pub enum ExpressionConstructionError {
1223    /// The same key occurred two or more times
1224    #[error(transparent)]
1225    #[diagnostic(transparent)]
1226    DuplicateKey(#[from] expression_construction_errors::DuplicateKeyError),
1227}
1228
1229/// Error subtypes for [`ExpressionConstructionError`]
1230pub mod expression_construction_errors {
1231    use miette::Diagnostic;
1232    use smol_str::SmolStr;
1233    use thiserror::Error;
1234
1235    /// The same key occurred two or more times
1236    //
1237    // CAUTION: this type is publicly exported in `cedar-policy`.
1238    // Don't make fields `pub`, don't make breaking changes, and use caution
1239    // when adding public methods.
1240    #[derive(Debug, PartialEq, Eq, Clone, Diagnostic, Error)]
1241    #[error("duplicate key `{key}` {context}")]
1242    pub struct DuplicateKeyError {
1243        /// The key which occurred two or more times
1244        pub(crate) key: SmolStr,
1245        /// Information about where the duplicate key occurred (e.g., "in record literal")
1246        pub(crate) context: &'static str,
1247    }
1248
1249    impl DuplicateKeyError {
1250        /// Get the key which occurred two or more times
1251        pub fn key(&self) -> &str {
1252            &self.key
1253        }
1254
1255        /// Make a new error with an updated `context` field
1256        pub(crate) fn with_context(self, context: &'static str) -> Self {
1257            Self { context, ..self }
1258        }
1259    }
1260}
1261
1262/// A new type wrapper around `Expr` that provides `Eq` and `Hash`
1263/// implementations that ignore any source information or other generic data
1264/// used to annotate the `Expr`.
1265#[derive(Eq, Debug, Clone)]
1266pub struct ExprShapeOnly<'a, T: Clone = ()>(Cow<'a, Expr<T>>);
1267
1268impl<'a, T: Clone> ExprShapeOnly<'a, T> {
1269    /// Construct an `ExprShapeOnly` from a borrowed `Expr`. The `Expr` is not
1270    /// modified, but any comparisons on the resulting `ExprShapeOnly` will
1271    /// ignore source information and generic data.
1272    pub fn new_from_borrowed(e: &'a Expr<T>) -> ExprShapeOnly<'a, T> {
1273        ExprShapeOnly(Cow::Borrowed(e))
1274    }
1275
1276    /// Construct an `ExprShapeOnly` from an owned `Expr`. The `Expr` is not
1277    /// modified, but any comparisons on the resulting `ExprShapeOnly` will
1278    /// ignore source information and generic data.
1279    pub fn new_from_owned(e: Expr<T>) -> ExprShapeOnly<'a, T> {
1280        ExprShapeOnly(Cow::Owned(e))
1281    }
1282}
1283
1284impl<T: Clone> PartialEq for ExprShapeOnly<'_, T> {
1285    fn eq(&self, other: &Self) -> bool {
1286        self.0.eq_shape(&other.0)
1287    }
1288}
1289
1290impl<T: Clone> Hash for ExprShapeOnly<'_, T> {
1291    fn hash<H: Hasher>(&self, state: &mut H) {
1292        self.0.hash_shape(state);
1293    }
1294}
1295
1296impl<T> Expr<T> {
1297    /// Return true if this expression (recursively) has the same expression
1298    /// kind as the argument expression. This accounts for the full recursive
1299    /// shape of the expression, but does not consider source information or any
1300    /// generic data annotated on expression. This should behave the same as the
1301    /// default implementation of `Eq` before source information and generic
1302    /// data were added.
1303    pub fn eq_shape<U>(&self, other: &Expr<U>) -> bool {
1304        use ExprKind::*;
1305        match (self.expr_kind(), other.expr_kind()) {
1306            (Lit(lit), Lit(lit1)) => lit == lit1,
1307            (Var(v), Var(v1)) => v == v1,
1308            (Slot(s), Slot(s1)) => s == s1,
1309            (
1310                Unknown(self::Unknown {
1311                    name: name1,
1312                    type_annotation: ta_1,
1313                }),
1314                Unknown(self::Unknown {
1315                    name: name2,
1316                    type_annotation: ta_2,
1317                }),
1318            ) => (name1 == name2) && (ta_1 == ta_2),
1319            (
1320                If {
1321                    test_expr,
1322                    then_expr,
1323                    else_expr,
1324                },
1325                If {
1326                    test_expr: test_expr1,
1327                    then_expr: then_expr1,
1328                    else_expr: else_expr1,
1329                },
1330            ) => {
1331                test_expr.eq_shape(test_expr1)
1332                    && then_expr.eq_shape(then_expr1)
1333                    && else_expr.eq_shape(else_expr1)
1334            }
1335            (
1336                And { left, right },
1337                And {
1338                    left: left1,
1339                    right: right1,
1340                },
1341            )
1342            | (
1343                Or { left, right },
1344                Or {
1345                    left: left1,
1346                    right: right1,
1347                },
1348            ) => left.eq_shape(left1) && right.eq_shape(right1),
1349            (UnaryApp { op, arg }, UnaryApp { op: op1, arg: arg1 }) => {
1350                op == op1 && arg.eq_shape(arg1)
1351            }
1352            (
1353                BinaryApp { op, arg1, arg2 },
1354                BinaryApp {
1355                    op: op1,
1356                    arg1: arg11,
1357                    arg2: arg21,
1358                },
1359            ) => op == op1 && arg1.eq_shape(arg11) && arg2.eq_shape(arg21),
1360            (
1361                ExtensionFunctionApp { fn_name, args },
1362                ExtensionFunctionApp {
1363                    fn_name: fn_name1,
1364                    args: args1,
1365                },
1366            ) => fn_name == fn_name1 && args.iter().zip(args1.iter()).all(|(a, a1)| a.eq_shape(a1)),
1367            (
1368                GetAttr { expr, attr },
1369                GetAttr {
1370                    expr: expr1,
1371                    attr: attr1,
1372                },
1373            )
1374            | (
1375                HasAttr { expr, attr },
1376                HasAttr {
1377                    expr: expr1,
1378                    attr: attr1,
1379                },
1380            ) => attr == attr1 && expr.eq_shape(expr1),
1381            (
1382                Like { expr, pattern },
1383                Like {
1384                    expr: expr1,
1385                    pattern: pattern1,
1386                },
1387            ) => pattern == pattern1 && expr.eq_shape(expr1),
1388            (Set(elems), Set(elems1)) => elems
1389                .iter()
1390                .zip(elems1.iter())
1391                .all(|(e, e1)| e.eq_shape(e1)),
1392            (Record(map), Record(map1)) => {
1393                map.len() == map1.len()
1394                    && map
1395                        .iter()
1396                        .zip(map1.iter()) // relying on BTreeMap producing an iterator sorted by key
1397                        .all(|((a, e), (a1, e1))| a == a1 && e.eq_shape(e1))
1398            }
1399            (
1400                Is { expr, entity_type },
1401                Is {
1402                    expr: expr1,
1403                    entity_type: entity_type1,
1404                },
1405            ) => entity_type == entity_type1 && expr.eq_shape(expr1),
1406            _ => false,
1407        }
1408    }
1409
1410    /// Implementation of hashing corresponding to equality as implemented by
1411    /// `eq_shape`. Must satisfy the usual relationship between equality and
1412    /// hashing.
1413    pub fn hash_shape<H>(&self, state: &mut H)
1414    where
1415        H: Hasher,
1416    {
1417        mem::discriminant(self).hash(state);
1418        match self.expr_kind() {
1419            ExprKind::Lit(lit) => lit.hash(state),
1420            ExprKind::Var(v) => v.hash(state),
1421            ExprKind::Slot(s) => s.hash(state),
1422            ExprKind::Unknown(u) => u.hash(state),
1423            ExprKind::If {
1424                test_expr,
1425                then_expr,
1426                else_expr,
1427            } => {
1428                test_expr.hash_shape(state);
1429                then_expr.hash_shape(state);
1430                else_expr.hash_shape(state);
1431            }
1432            ExprKind::And { left, right } => {
1433                left.hash_shape(state);
1434                right.hash_shape(state);
1435            }
1436            ExprKind::Or { left, right } => {
1437                left.hash_shape(state);
1438                right.hash_shape(state);
1439            }
1440            ExprKind::UnaryApp { op, arg } => {
1441                op.hash(state);
1442                arg.hash_shape(state);
1443            }
1444            ExprKind::BinaryApp { op, arg1, arg2 } => {
1445                op.hash(state);
1446                arg1.hash_shape(state);
1447                arg2.hash_shape(state);
1448            }
1449            ExprKind::ExtensionFunctionApp { fn_name, args } => {
1450                fn_name.hash(state);
1451                state.write_usize(args.len());
1452                args.iter().for_each(|a| {
1453                    a.hash_shape(state);
1454                });
1455            }
1456            ExprKind::GetAttr { expr, attr } => {
1457                expr.hash_shape(state);
1458                attr.hash(state);
1459            }
1460            ExprKind::HasAttr { expr, attr } => {
1461                expr.hash_shape(state);
1462                attr.hash(state);
1463            }
1464            ExprKind::Like { expr, pattern } => {
1465                expr.hash_shape(state);
1466                pattern.hash(state);
1467            }
1468            ExprKind::Set(elems) => {
1469                state.write_usize(elems.len());
1470                elems.iter().for_each(|e| {
1471                    e.hash_shape(state);
1472                })
1473            }
1474            ExprKind::Record(map) => {
1475                state.write_usize(map.len());
1476                map.iter().for_each(|(s, a)| {
1477                    s.hash(state);
1478                    a.hash_shape(state);
1479                });
1480            }
1481            ExprKind::Is { expr, entity_type } => {
1482                expr.hash_shape(state);
1483                entity_type.hash(state);
1484            }
1485        }
1486    }
1487}
1488
1489/// AST variables
1490#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, Copy)]
1491#[serde(rename_all = "camelCase")]
1492#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1493#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
1494#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
1495pub enum Var {
1496    /// the Principal of the given request
1497    Principal,
1498    /// the Action of the given request
1499    Action,
1500    /// the Resource of the given request
1501    Resource,
1502    /// the Context of the given request
1503    Context,
1504}
1505
1506#[cfg(test)]
1507mod var_generator {
1508    use super::Var;
1509    #[cfg(test)]
1510    pub fn all_vars() -> impl Iterator<Item = Var> {
1511        [Var::Principal, Var::Action, Var::Resource, Var::Context].into_iter()
1512    }
1513}
1514// by default, Coverlay does not track coverage for lines after a line
1515// containing #[cfg(test)].
1516// we use the following sentinel to "turn back on" coverage tracking for
1517// remaining lines of this file, until the next #[cfg(test)]
1518// GRCOV_BEGIN_COVERAGE
1519
1520impl From<PrincipalOrResource> for Var {
1521    fn from(v: PrincipalOrResource) -> Self {
1522        match v {
1523            PrincipalOrResource::Principal => Var::Principal,
1524            PrincipalOrResource::Resource => Var::Resource,
1525        }
1526    }
1527}
1528
1529// PANIC SAFETY Tested by `test::all_vars_are_ids`. Never panics.
1530#[allow(clippy::fallible_impl_from)]
1531impl From<Var> for Id {
1532    fn from(var: Var) -> Self {
1533        // PANIC SAFETY: `Var` is a simple enum and all vars are formatted as valid `Id`. Tested by `test::all_vars_are_ids`
1534        #[allow(clippy::unwrap_used)]
1535        format!("{var}").parse().unwrap()
1536    }
1537}
1538
1539// PANIC SAFETY Tested by `test::all_vars_are_ids`. Never panics.
1540#[allow(clippy::fallible_impl_from)]
1541impl From<Var> for UnreservedId {
1542    fn from(var: Var) -> Self {
1543        // PANIC SAFETY: `Var` is a simple enum and all vars are formatted as valid `UnreservedId`. Tested by `test::all_vars_are_ids`
1544        #[allow(clippy::unwrap_used)]
1545        Id::from(var).try_into().unwrap()
1546    }
1547}
1548
1549impl std::fmt::Display for Var {
1550    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1551        match self {
1552            Self::Principal => write!(f, "principal"),
1553            Self::Action => write!(f, "action"),
1554            Self::Resource => write!(f, "resource"),
1555            Self::Context => write!(f, "context"),
1556        }
1557    }
1558}
1559
1560#[cfg(test)]
1561mod test {
1562    use cool_asserts::assert_matches;
1563    use itertools::Itertools;
1564    use std::collections::{hash_map::DefaultHasher, HashSet};
1565
1566    use crate::expr_builder::ExprBuilder as _;
1567
1568    use super::{var_generator::all_vars, *};
1569
1570    // Tests that Var::Into never panics
1571    #[test]
1572    fn all_vars_are_ids() {
1573        for var in all_vars() {
1574            let _id: Id = var.into();
1575            let _id: UnreservedId = var.into();
1576        }
1577    }
1578
1579    #[test]
1580    fn exprs() {
1581        assert_eq!(
1582            Expr::val(33),
1583            Expr::new(ExprKind::Lit(Literal::Long(33)), None, ())
1584        );
1585        assert_eq!(
1586            Expr::val("hello"),
1587            Expr::new(ExprKind::Lit(Literal::from("hello")), None, ())
1588        );
1589        assert_eq!(
1590            Expr::val(EntityUID::with_eid("foo")),
1591            Expr::new(
1592                ExprKind::Lit(Literal::from(EntityUID::with_eid("foo"))),
1593                None,
1594                ()
1595            )
1596        );
1597        assert_eq!(
1598            Expr::var(Var::Principal),
1599            Expr::new(ExprKind::Var(Var::Principal), None, ())
1600        );
1601        assert_eq!(
1602            Expr::ite(Expr::val(true), Expr::val(88), Expr::val(-100)),
1603            Expr::new(
1604                ExprKind::If {
1605                    test_expr: Arc::new(Expr::new(ExprKind::Lit(Literal::Bool(true)), None, ())),
1606                    then_expr: Arc::new(Expr::new(ExprKind::Lit(Literal::Long(88)), None, ())),
1607                    else_expr: Arc::new(Expr::new(ExprKind::Lit(Literal::Long(-100)), None, ())),
1608                },
1609                None,
1610                ()
1611            )
1612        );
1613        assert_eq!(
1614            Expr::not(Expr::val(false)),
1615            Expr::new(
1616                ExprKind::UnaryApp {
1617                    op: UnaryOp::Not,
1618                    arg: Arc::new(Expr::new(ExprKind::Lit(Literal::Bool(false)), None, ())),
1619                },
1620                None,
1621                ()
1622            )
1623        );
1624        assert_eq!(
1625            Expr::get_attr(Expr::val(EntityUID::with_eid("foo")), "some_attr".into()),
1626            Expr::new(
1627                ExprKind::GetAttr {
1628                    expr: Arc::new(Expr::new(
1629                        ExprKind::Lit(Literal::from(EntityUID::with_eid("foo"))),
1630                        None,
1631                        ()
1632                    )),
1633                    attr: "some_attr".into()
1634                },
1635                None,
1636                ()
1637            )
1638        );
1639        assert_eq!(
1640            Expr::has_attr(Expr::val(EntityUID::with_eid("foo")), "some_attr".into()),
1641            Expr::new(
1642                ExprKind::HasAttr {
1643                    expr: Arc::new(Expr::new(
1644                        ExprKind::Lit(Literal::from(EntityUID::with_eid("foo"))),
1645                        None,
1646                        ()
1647                    )),
1648                    attr: "some_attr".into()
1649                },
1650                None,
1651                ()
1652            )
1653        );
1654        assert_eq!(
1655            Expr::is_entity_type(
1656                Expr::val(EntityUID::with_eid("foo")),
1657                "Type".parse().unwrap()
1658            ),
1659            Expr::new(
1660                ExprKind::Is {
1661                    expr: Arc::new(Expr::new(
1662                        ExprKind::Lit(Literal::from(EntityUID::with_eid("foo"))),
1663                        None,
1664                        ()
1665                    )),
1666                    entity_type: "Type".parse().unwrap()
1667                },
1668                None,
1669                ()
1670            ),
1671        );
1672    }
1673
1674    #[test]
1675    fn like_display() {
1676        // `\0` escaped form is `\0`.
1677        let e = Expr::like(Expr::val("a"), Pattern::from(vec![PatternElem::Char('\0')]));
1678        assert_eq!(format!("{e}"), r#""a" like "\0""#);
1679        // `\`'s escaped form is `\\`
1680        let e = Expr::like(
1681            Expr::val("a"),
1682            Pattern::from(vec![PatternElem::Char('\\'), PatternElem::Char('0')]),
1683        );
1684        assert_eq!(format!("{e}"), r#""a" like "\\0""#);
1685        // `\`'s escaped form is `\\`
1686        let e = Expr::like(
1687            Expr::val("a"),
1688            Pattern::from(vec![PatternElem::Char('\\'), PatternElem::Wildcard]),
1689        );
1690        assert_eq!(format!("{e}"), r#""a" like "\\*""#);
1691        // literal star's escaped from is `\*`
1692        let e = Expr::like(
1693            Expr::val("a"),
1694            Pattern::from(vec![PatternElem::Char('\\'), PatternElem::Char('*')]),
1695        );
1696        assert_eq!(format!("{e}"), r#""a" like "\\\*""#);
1697    }
1698
1699    #[test]
1700    fn has_display() {
1701        // `\0` escaped form is `\0`.
1702        let e = Expr::has_attr(Expr::val("a"), "\0".into());
1703        assert_eq!(format!("{e}"), r#""a" has "\0""#);
1704        // `\`'s escaped form is `\\`
1705        let e = Expr::has_attr(Expr::val("a"), r"\".into());
1706        assert_eq!(format!("{e}"), r#""a" has "\\""#);
1707    }
1708
1709    #[test]
1710    fn slot_display() {
1711        let e = Expr::slot(SlotId::principal());
1712        assert_eq!(format!("{e}"), "?principal");
1713        let e = Expr::slot(SlotId::resource());
1714        assert_eq!(format!("{e}"), "?resource");
1715        let e = Expr::val(EntityUID::with_eid("eid"));
1716        assert_eq!(format!("{e}"), "test_entity_type::\"eid\"");
1717    }
1718
1719    #[test]
1720    fn simple_slots() {
1721        let e = Expr::slot(SlotId::principal());
1722        let p = SlotId::principal();
1723        let r = SlotId::resource();
1724        let set: HashSet<SlotId> = HashSet::from_iter([p]);
1725        assert_eq!(set, e.slots().map(|slot| slot.id).collect::<HashSet<_>>());
1726        let e = Expr::or(
1727            Expr::slot(SlotId::principal()),
1728            Expr::ite(
1729                Expr::val(true),
1730                Expr::slot(SlotId::resource()),
1731                Expr::val(false),
1732            ),
1733        );
1734        let set: HashSet<SlotId> = HashSet::from_iter([p, r]);
1735        assert_eq!(set, e.slots().map(|slot| slot.id).collect::<HashSet<_>>());
1736    }
1737
1738    #[test]
1739    fn unknowns() {
1740        let e = Expr::ite(
1741            Expr::not(Expr::unknown(Unknown::new_untyped("a"))),
1742            Expr::and(Expr::unknown(Unknown::new_untyped("b")), Expr::val(3)),
1743            Expr::unknown(Unknown::new_untyped("c")),
1744        );
1745        let unknowns = e.unknowns().collect_vec();
1746        assert_eq!(unknowns.len(), 3);
1747        assert!(unknowns.contains(&&Unknown::new_untyped("a")));
1748        assert!(unknowns.contains(&&Unknown::new_untyped("b")));
1749        assert!(unknowns.contains(&&Unknown::new_untyped("c")));
1750    }
1751
1752    #[test]
1753    fn is_unknown() {
1754        let e = Expr::ite(
1755            Expr::not(Expr::unknown(Unknown::new_untyped("a"))),
1756            Expr::and(Expr::unknown(Unknown::new_untyped("b")), Expr::val(3)),
1757            Expr::unknown(Unknown::new_untyped("c")),
1758        );
1759        assert!(e.contains_unknown());
1760        let e = Expr::ite(
1761            Expr::not(Expr::val(true)),
1762            Expr::and(Expr::val(1), Expr::val(3)),
1763            Expr::val(1),
1764        );
1765        assert!(!e.contains_unknown());
1766    }
1767
1768    #[test]
1769    fn expr_with_data() {
1770        let e = ExprBuilder::with_data("data").val(1);
1771        assert_eq!(e.into_data(), "data");
1772    }
1773
1774    #[test]
1775    fn expr_shape_only_eq() {
1776        let temp = ExprBuilder::with_data(1).val(1);
1777        let exprs = &[
1778            (ExprBuilder::with_data(1).val(33), Expr::val(33)),
1779            (ExprBuilder::with_data(1).val(true), Expr::val(true)),
1780            (
1781                ExprBuilder::with_data(1).var(Var::Principal),
1782                Expr::var(Var::Principal),
1783            ),
1784            (
1785                ExprBuilder::with_data(1).slot(SlotId::principal()),
1786                Expr::slot(SlotId::principal()),
1787            ),
1788            (
1789                ExprBuilder::with_data(1).ite(temp.clone(), temp.clone(), temp.clone()),
1790                Expr::ite(Expr::val(1), Expr::val(1), Expr::val(1)),
1791            ),
1792            (
1793                ExprBuilder::with_data(1).not(temp.clone()),
1794                Expr::not(Expr::val(1)),
1795            ),
1796            (
1797                ExprBuilder::with_data(1).is_eq(temp.clone(), temp.clone()),
1798                Expr::is_eq(Expr::val(1), Expr::val(1)),
1799            ),
1800            (
1801                ExprBuilder::with_data(1).and(temp.clone(), temp.clone()),
1802                Expr::and(Expr::val(1), Expr::val(1)),
1803            ),
1804            (
1805                ExprBuilder::with_data(1).or(temp.clone(), temp.clone()),
1806                Expr::or(Expr::val(1), Expr::val(1)),
1807            ),
1808            (
1809                ExprBuilder::with_data(1).less(temp.clone(), temp.clone()),
1810                Expr::less(Expr::val(1), Expr::val(1)),
1811            ),
1812            (
1813                ExprBuilder::with_data(1).lesseq(temp.clone(), temp.clone()),
1814                Expr::lesseq(Expr::val(1), Expr::val(1)),
1815            ),
1816            (
1817                ExprBuilder::with_data(1).greater(temp.clone(), temp.clone()),
1818                Expr::greater(Expr::val(1), Expr::val(1)),
1819            ),
1820            (
1821                ExprBuilder::with_data(1).greatereq(temp.clone(), temp.clone()),
1822                Expr::greatereq(Expr::val(1), Expr::val(1)),
1823            ),
1824            (
1825                ExprBuilder::with_data(1).add(temp.clone(), temp.clone()),
1826                Expr::add(Expr::val(1), Expr::val(1)),
1827            ),
1828            (
1829                ExprBuilder::with_data(1).sub(temp.clone(), temp.clone()),
1830                Expr::sub(Expr::val(1), Expr::val(1)),
1831            ),
1832            (
1833                ExprBuilder::with_data(1).mul(temp.clone(), temp.clone()),
1834                Expr::mul(Expr::val(1), Expr::val(1)),
1835            ),
1836            (
1837                ExprBuilder::with_data(1).neg(temp.clone()),
1838                Expr::neg(Expr::val(1)),
1839            ),
1840            (
1841                ExprBuilder::with_data(1).is_in(temp.clone(), temp.clone()),
1842                Expr::is_in(Expr::val(1), Expr::val(1)),
1843            ),
1844            (
1845                ExprBuilder::with_data(1).contains(temp.clone(), temp.clone()),
1846                Expr::contains(Expr::val(1), Expr::val(1)),
1847            ),
1848            (
1849                ExprBuilder::with_data(1).contains_all(temp.clone(), temp.clone()),
1850                Expr::contains_all(Expr::val(1), Expr::val(1)),
1851            ),
1852            (
1853                ExprBuilder::with_data(1).contains_any(temp.clone(), temp.clone()),
1854                Expr::contains_any(Expr::val(1), Expr::val(1)),
1855            ),
1856            (
1857                ExprBuilder::with_data(1).is_empty(temp.clone()),
1858                Expr::is_empty(Expr::val(1)),
1859            ),
1860            (
1861                ExprBuilder::with_data(1).set([temp.clone()]),
1862                Expr::set([Expr::val(1)]),
1863            ),
1864            (
1865                ExprBuilder::with_data(1)
1866                    .record([("foo".into(), temp.clone())])
1867                    .unwrap(),
1868                Expr::record([("foo".into(), Expr::val(1))]).unwrap(),
1869            ),
1870            (
1871                ExprBuilder::with_data(1)
1872                    .call_extension_fn("foo".parse().unwrap(), vec![temp.clone()]),
1873                Expr::call_extension_fn("foo".parse().unwrap(), vec![Expr::val(1)]),
1874            ),
1875            (
1876                ExprBuilder::with_data(1).get_attr(temp.clone(), "foo".into()),
1877                Expr::get_attr(Expr::val(1), "foo".into()),
1878            ),
1879            (
1880                ExprBuilder::with_data(1).has_attr(temp.clone(), "foo".into()),
1881                Expr::has_attr(Expr::val(1), "foo".into()),
1882            ),
1883            (
1884                ExprBuilder::with_data(1)
1885                    .like(temp.clone(), Pattern::from(vec![PatternElem::Wildcard])),
1886                Expr::like(Expr::val(1), Pattern::from(vec![PatternElem::Wildcard])),
1887            ),
1888            (
1889                ExprBuilder::with_data(1).is_entity_type(temp, "T".parse().unwrap()),
1890                Expr::is_entity_type(Expr::val(1), "T".parse().unwrap()),
1891            ),
1892        ];
1893
1894        for (e0, e1) in exprs {
1895            assert!(e0.eq_shape(e0));
1896            assert!(e1.eq_shape(e1));
1897            assert!(e0.eq_shape(e1));
1898            assert!(e1.eq_shape(e0));
1899
1900            let mut hasher0 = DefaultHasher::new();
1901            e0.hash_shape(&mut hasher0);
1902            let hash0 = hasher0.finish();
1903
1904            let mut hasher1 = DefaultHasher::new();
1905            e1.hash_shape(&mut hasher1);
1906            let hash1 = hasher1.finish();
1907
1908            assert_eq!(hash0, hash1);
1909        }
1910    }
1911
1912    #[test]
1913    fn expr_shape_only_not_eq() {
1914        let expr1 = ExprBuilder::with_data(1).val(1);
1915        let expr2 = ExprBuilder::with_data(1).val(2);
1916        assert_ne!(
1917            ExprShapeOnly::new_from_borrowed(&expr1),
1918            ExprShapeOnly::new_from_borrowed(&expr2)
1919        );
1920    }
1921
1922    #[test]
1923    fn untyped_subst_present() {
1924        let u = Unknown {
1925            name: "foo".into(),
1926            type_annotation: None,
1927        };
1928        let r = UntypedSubstitution::substitute(&u, Some(&Value::new(1, None)));
1929        match r {
1930            Ok(e) => assert_eq!(e, Expr::val(1)),
1931            Err(empty) => match empty {},
1932        }
1933    }
1934
1935    #[test]
1936    fn untyped_subst_present_correct_type() {
1937        let u = Unknown {
1938            name: "foo".into(),
1939            type_annotation: Some(Type::Long),
1940        };
1941        let r = UntypedSubstitution::substitute(&u, Some(&Value::new(1, None)));
1942        match r {
1943            Ok(e) => assert_eq!(e, Expr::val(1)),
1944            Err(empty) => match empty {},
1945        }
1946    }
1947
1948    #[test]
1949    fn untyped_subst_present_wrong_type() {
1950        let u = Unknown {
1951            name: "foo".into(),
1952            type_annotation: Some(Type::Bool),
1953        };
1954        let r = UntypedSubstitution::substitute(&u, Some(&Value::new(1, None)));
1955        match r {
1956            Ok(e) => assert_eq!(e, Expr::val(1)),
1957            Err(empty) => match empty {},
1958        }
1959    }
1960
1961    #[test]
1962    fn untyped_subst_not_present() {
1963        let u = Unknown {
1964            name: "foo".into(),
1965            type_annotation: Some(Type::Bool),
1966        };
1967        let r = UntypedSubstitution::substitute(&u, None);
1968        match r {
1969            Ok(n) => assert_eq!(n, Expr::unknown(u)),
1970            Err(empty) => match empty {},
1971        }
1972    }
1973
1974    #[test]
1975    fn typed_subst_present() {
1976        let u = Unknown {
1977            name: "foo".into(),
1978            type_annotation: None,
1979        };
1980        let e = TypedSubstitution::substitute(&u, Some(&Value::new(1, None))).unwrap();
1981        assert_eq!(e, Expr::val(1));
1982    }
1983
1984    #[test]
1985    fn typed_subst_present_correct_type() {
1986        let u = Unknown {
1987            name: "foo".into(),
1988            type_annotation: Some(Type::Long),
1989        };
1990        let e = TypedSubstitution::substitute(&u, Some(&Value::new(1, None))).unwrap();
1991        assert_eq!(e, Expr::val(1));
1992    }
1993
1994    #[test]
1995    fn typed_subst_present_wrong_type() {
1996        let u = Unknown {
1997            name: "foo".into(),
1998            type_annotation: Some(Type::Bool),
1999        };
2000        let r = TypedSubstitution::substitute(&u, Some(&Value::new(1, None))).unwrap_err();
2001        assert_matches!(
2002            r,
2003            SubstitutionError::TypeError {
2004                expected: Type::Bool,
2005                actual: Type::Long,
2006            }
2007        );
2008    }
2009
2010    #[test]
2011    fn typed_subst_not_present() {
2012        let u = Unknown {
2013            name: "foo".into(),
2014            type_annotation: None,
2015        };
2016        let r = TypedSubstitution::substitute(&u, None).unwrap();
2017        assert_eq!(r, Expr::unknown(u));
2018    }
2019}