Skip to content

Commit 4e2b2d5

Browse files
Simplified strict typechecking (cedar-policy#282)
Implements cedar-policy/rfcs#19
1 parent 09b99a3 commit 4e2b2d5

9 files changed

Lines changed: 631 additions & 828 deletions

File tree

cedar-policy-validator/src/type_error.rs

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
use std::{collections::BTreeSet, fmt::Display};
2020

2121
use cedar_policy_core::{
22-
ast::{CallStyle, EntityUID, Expr, ExprKind, Var},
22+
ast::{CallStyle, EntityUID, Expr, ExprKind, Name, Var},
2323
parser::SourceInfo,
2424
};
2525

@@ -96,19 +96,6 @@ impl TypeError {
9696
}
9797
}
9898

99-
pub(crate) fn types_must_match<T>(
100-
on_expr: Expr<T>,
101-
types: impl IntoIterator<Item = Type>,
102-
) -> Self {
103-
Self {
104-
on_expr: None,
105-
source_location: on_expr.into_source_info(),
106-
kind: TypeErrorKind::TypesMustMatch(TypesMustMatch {
107-
types: types.into_iter().collect::<BTreeSet<_>>(),
108-
}),
109-
}
110-
}
111-
11299
pub(crate) fn unsafe_attribute_access(
113100
on_expr: Expr,
114101
attribute_access: AttributeAccess,
@@ -196,6 +183,18 @@ impl TypeError {
196183
kind: TypeErrorKind::NonLitExtConstructor,
197184
}
198185
}
186+
187+
pub(crate) fn hierarchy_not_respected<T>(
188+
on_expr: Expr<T>,
189+
in_lhs: Option<Name>,
190+
in_rhs: Option<Name>,
191+
) -> Self {
192+
Self {
193+
on_expr: None,
194+
source_location: on_expr.into_source_info(),
195+
kind: TypeErrorKind::HierarchyNotRespected(HierarchyNotRespected { in_lhs, in_rhs }),
196+
}
197+
}
199198
}
200199

201200
impl Display for TypeError {
@@ -264,12 +263,19 @@ pub enum TypeErrorKind {
264263
/// Error returned by custom extension function argument validation
265264
#[error("Error during extension function argument validation: {}", .0.msg)]
266265
FunctionArgumentValidationError(FunctionArgumentValidationError),
267-
#[error("Types of operands in this expression are not equal: [{}]", .0.types.iter().join(","))]
268-
TypesMustMatch(TypesMustMatch),
269266
#[error("empty set literals are forbidden in policies")]
270267
EmptySetForbidden,
271268
#[error("extension constructors may not be called with non-literal expressions")]
272269
NonLitExtConstructor,
270+
/// To pass strict validation a policy cannot contain an `in` expression
271+
/// where the entity type on the left might not be able to be a member of
272+
/// the entity type on the right.
273+
#[error("operands to `in` do not respect the entity hierarchy{}",
274+
match (&.0.in_lhs, &.0.in_rhs) {
275+
(Some(in_lhs), Some(in_rhs)) => format!(". `{}` is not a descendant of `{}`", in_lhs, in_rhs),
276+
_ => "".to_string(),
277+
})]
278+
HierarchyNotRespected(HierarchyNotRespected),
273279
}
274280

275281
/// Structure containing details about an unexpected type error.
@@ -282,12 +288,6 @@ pub struct UnexpectedType {
282288
/// Structure containing details about an incompatible type error.
283289
#[derive(Debug, Hash, Eq, PartialEq)]
284290
pub struct IncompatibleTypes {
285-
types: BTreeSet<Type>,
286-
}
287-
288-
/// Structure containing details about types must match error.
289-
#[derive(Debug, Hash, Eq, PartialEq)]
290-
pub struct TypesMustMatch {
291291
pub(crate) types: BTreeSet<Type>,
292292
}
293293

@@ -339,6 +339,13 @@ pub struct FunctionArgumentValidationError {
339339
msg: String,
340340
}
341341

342+
/// Structure containing details about a hierarchy not respected error
343+
#[derive(Debug, Hash, Eq, PartialEq)]
344+
pub struct HierarchyNotRespected {
345+
in_lhs: Option<Name>,
346+
in_rhs: Option<Name>,
347+
}
348+
342349
/// Contains more detailed information about an attribute access when it occurs
343350
/// on an entity type expression or on the `context` variable. Track a `Vec` of
344351
/// attributes rather than a single attribute so that on `principal.foo.bar` can

0 commit comments

Comments
 (0)