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