From 573e6812c8c1ff776170d3993edada05b8144f10 Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Mon, 2 Dec 2024 15:30:59 -0800 Subject: [PATCH 01/10] added source locations to some errors Signed-off-by: Shaobo He --- cedar-policy-core/src/ast/name.rs | 3 +- cedar-policy-core/src/ast/policy.rs | 6 ++++ cedar-policy-core/src/parser.rs | 2 +- cedar-policy-core/src/parser/err.rs | 35 ++++++++++++++++++--- cedar-policy-core/src/parser/text_to_cst.rs | 4 +-- cedar-policy-core/src/test_utils.rs | 18 +++++------ 6 files changed, 49 insertions(+), 19 deletions(-) diff --git a/cedar-policy-core/src/ast/name.rs b/cedar-policy-core/src/ast/name.rs index 9eb46084a..90165499c 100644 --- a/cedar-policy-core/src/ast/name.rs +++ b/cedar-policy-core/src/ast/name.rs @@ -394,11 +394,12 @@ impl std::fmt::Display for ValidSlotId { } /// [`SlotId`] plus a source location -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct Slot { /// [`SlotId`] pub id: SlotId, /// Source location, if available + #[serde(skip)] pub loc: Option, } diff --git a/cedar-policy-core/src/ast/policy.rs b/cedar-policy-core/src/ast/policy.rs index 384e5d7cf..3d3f21408 100644 --- a/cedar-policy-core/src/ast/policy.rs +++ b/cedar-policy-core/src/ast/policy.rs @@ -1758,6 +1758,12 @@ impl Diagnostic for UnexpectedSlotError { }), } } + + fn source_code(&self) -> Option<&dyn miette::SourceCode> { + match self { + Self::FoundSlot(Slot { loc, .. }) => loc.as_ref().map(|l| l as &dyn miette::SourceCode), + } + } } impl From for EntityReference { diff --git a/cedar-policy-core/src/parser.rs b/cedar-policy-core/src/parser.rs index c8ed91e0e..ba038bca3 100644 --- a/cedar-policy-core/src/parser.rs +++ b/cedar-policy-core/src/parser.rs @@ -300,7 +300,7 @@ pub(crate) mod test_utils { msg: &ExpectedErrorMessage<'_>, ) { assert!( - errs.iter().any(|e| msg.matches(Some(src), e)), + errs.iter().any(|e| msg.matches(e)), "for the following input:\n{src}\nexpected some error to match the following:\n{msg}\nbut actual errors were:\n{:?}", // the Debug representation of `miette::Report` is the pretty one, for some reason miette::Report::new(errs.clone()), ); diff --git a/cedar-policy-core/src/parser/err.rs b/cedar-policy-core/src/parser/err.rs index 8e8254b9a..ad535215d 100644 --- a/cedar-policy-core/src/parser/err.rs +++ b/cedar-policy-core/src/parser/err.rs @@ -18,6 +18,7 @@ use std::collections::{BTreeSet, HashMap, HashSet}; use std::fmt::{self, Display, Write}; use std::iter; use std::ops::{Deref, DerefMut}; +use std::sync::Arc; use either::Either; use lalrpop_util as lalr; @@ -472,14 +473,32 @@ pub mod parse_errors { use super::*; /// Details about a `ExpectedStaticPolicy` error. - #[derive(Debug, Clone, Diagnostic, Error, PartialEq, Eq)] + #[derive(Debug, Clone, Error, PartialEq, Eq)] #[error("expected a static policy, got a template containing the slot {}", slot.id)] - #[diagnostic(help("try removing the template slot(s) from this policy"))] pub struct ExpectedStaticPolicy { /// Slot that was found (which is not valid in a static policy) pub(crate) slot: ast::Slot, } + impl Diagnostic for ExpectedStaticPolicy { + fn help<'a>(&'a self) -> Option> { + Some(Box::new( + "try removing the template slot(s) from this policy", + )) + } + + fn labels(&self) -> Option + '_>> { + self.slot.loc.as_ref().map(|loc| { + let label = miette::LabeledSpan::underline(loc.span); + Box::new(std::iter::once(label)) as Box> + }) + } + + fn source_code(&self) -> Option<&dyn miette::SourceCode> { + self.slot.loc.as_ref().map(|l| l as &dyn miette::SourceCode) + } + } + impl From for ExpectedStaticPolicy { fn from(err: ast::UnexpectedSlotError) -> Self { match err { @@ -573,6 +592,7 @@ pub mod parse_errors { #[derive(Clone, Debug, Error, PartialEq, Eq)] pub struct ToCSTError { err: OwnedRawParseError, + src: Arc, } impl ToCSTError { @@ -592,14 +612,15 @@ impl ToCSTError { } } - pub(crate) fn from_raw_parse_err(err: RawParseError<'_>) -> Self { + pub(crate) fn from_raw_parse_err(err: RawParseError<'_>, src: Arc) -> Self { Self { err: err.map_token(|token| token.to_string()), + src, } } - pub(crate) fn from_raw_err_recovery(recovery: RawErrorRecovery<'_>) -> Self { - Self::from_raw_parse_err(recovery.error) + pub(crate) fn from_raw_err_recovery(recovery: RawErrorRecovery<'_>, src: Arc) -> Self { + Self::from_raw_parse_err(recovery.error, src) } } @@ -622,6 +643,10 @@ impl Display for ToCSTError { } impl Diagnostic for ToCSTError { + fn source_code(&self) -> Option<&dyn miette::SourceCode> { + Some(&self.src as &dyn miette::SourceCode) + } + fn labels(&self) -> Option + '_>> { let primary_source_span = self.primary_source_span(); let labeled_span = match &self.err { diff --git a/cedar-policy-core/src/parser/text_to_cst.rs b/cedar-policy-core/src/parser/text_to_cst.rs index e95964100..aaf7cce16 100644 --- a/cedar-policy-core/src/parser/text_to_cst.rs +++ b/cedar-policy-core/src/parser/text_to_cst.rs @@ -52,13 +52,13 @@ fn parse_collect_errors<'a, P, T>( let errors = errs .into_iter() - .map(err::ToCSTError::from_raw_err_recovery) + .map(|rc| err::ToCSTError::from_raw_err_recovery(rc, Arc::from(text))) .map(Into::into); let parsed = match result { Ok(parsed) => parsed, Err(e) => { return Err(err::ParseErrors::new( - err::ToCSTError::from_raw_parse_err(e).into(), + err::ToCSTError::from_raw_parse_err(e, Arc::from(text)).into(), errors, )); } diff --git a/cedar-policy-core/src/test_utils.rs b/cedar-policy-core/src/test_utils.rs index 615868564..247ef7b69 100644 --- a/cedar-policy-core/src/test_utils.rs +++ b/cedar-policy-core/src/test_utils.rs @@ -161,11 +161,11 @@ impl<'a> ExpectedErrorMessage<'a> { /// `src` is the full source text (which the miette labels index into). /// It can be omitted only in the case where we expect no underlines. /// Panics if this invariant is violated. - pub fn matches(&self, src: Option<&'a str>, error: &impl miette::Diagnostic) -> bool { + pub fn matches(&self, error: &impl miette::Diagnostic) -> bool { self.matches_error(error) && self.matches_help(error) && self.matches_source(error) - && self.matches_underlines(src, error) + && self.matches_underlines(error) } /// Internal helper: whether the main error message matches @@ -285,15 +285,16 @@ impl<'a> ExpectedErrorMessage<'a> { /// `src` is the full source text (which the miette labels index into). /// It can be omitted only in the case where we expect no underlines. /// Panics if this invariant is violated. - fn matches_underlines(&self, src: Option<&'a str>, err: &impl miette::Diagnostic) -> bool { + fn matches_underlines(&self, err: &impl miette::Diagnostic) -> bool { let expected_num_labels = self.underlines.len(); let actual_num_labels = err.labels().map(|iter| iter.count()).unwrap_or(0); if expected_num_labels != actual_num_labels { return false; } if expected_num_labels != 0 { - let src = - src.expect("src can be `None` only in the case where we expect no underlines"); + let src = err + .source_code() + .expect("src can be `None` only in the case where we expect no underlines"); for (expected, actual) in self .underlines .iter() @@ -302,11 +303,8 @@ impl<'a> ExpectedErrorMessage<'a> { let (expected_snippet, expected_label) = expected; let actual_snippet = { let span = actual.inner(); - if span.offset() < src.len() { - &src[span.offset()..span.offset() + span.len()] - } else { - "" - } + std::str::from_utf8(src.read_span(span, 0, 0).expect("should read span").data()) + .expect("should be utf8 encoded") }; let actual_label = actual.label(); if expected_snippet != &actual_snippet { From 11e5bbb589b27faf5148d750cd5ec1e70178a0b8 Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Mon, 2 Dec 2024 20:21:54 -0800 Subject: [PATCH 02/10] cedar schema parse errors Signed-off-by: Shaobo He --- .../src/cedar_schema/err.rs | 24 ++++++++++++------- .../src/cedar_schema/parser.rs | 7 ++++-- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/cedar-policy-validator/src/cedar_schema/err.rs b/cedar-policy-validator/src/cedar_schema/err.rs index a385abc0b..2a10039ab 100644 --- a/cedar-policy-validator/src/cedar_schema/err.rs +++ b/cedar-policy-validator/src/cedar_schema/err.rs @@ -18,6 +18,7 @@ use std::{ collections::{HashMap, HashSet}, fmt::Display, iter::{Chain, Once}, + sync::Arc, vec, }; @@ -102,26 +103,27 @@ lazy_static! { pub struct ParseError { /// Error generated by lalrpop err: OwnedRawParseError, + /// Source code + src: Arc, } -impl From> for ParseError { - fn from(err: RawParseError<'_>) -> Self { +impl ParseError { + pub(crate) fn from_raw_parse_error(err: RawParseError<'_>, src: Arc) -> Self { Self { err: err.map_token(|token| token.to_string()), + src, } } -} -impl From> for ParseError { - fn from(recovery: RawErrorRecovery<'_>) -> Self { - recovery.error.into() + pub(crate) fn from_raw_error_recovery(recovery: RawErrorRecovery<'_>, src: Arc) -> Self { + Self::from_raw_parse_error(recovery.error, src) } } impl ParseError { /// Extract a primary source span locating the error. pub fn primary_source_span(&self) -> SourceSpan { - let Self { err } = self; + let Self { err, .. } = self; match err { OwnedRawParseError::InvalidToken { location } => SourceSpan::from(*location), OwnedRawParseError::UnrecognizedEof { location, .. } => SourceSpan::from(*location), @@ -139,7 +141,7 @@ impl ParseError { impl Display for ParseError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let Self { err } = self; + let Self { err, .. } = self; match err { OwnedRawParseError::InvalidToken { .. } => write!(f, "invalid token"), OwnedRawParseError::UnrecognizedEof { .. } => write!(f, "unexpected end of input"), @@ -161,9 +163,13 @@ impl Display for ParseError { impl std::error::Error for ParseError {} impl Diagnostic for ParseError { + fn source_code(&self) -> Option<&dyn miette::SourceCode> { + Some(&self.src as &dyn miette::SourceCode) + } + fn labels(&self) -> Option + '_>> { let primary_source_span = self.primary_source_span(); - let Self { err } = self; + let Self { err, .. } = self; let labeled_span = match err { OwnedRawParseError::InvalidToken { .. } => LabeledSpan::underline(primary_source_span), OwnedRawParseError::UnrecognizedEof { expected, .. } => LabeledSpan::new_with_span( diff --git a/cedar-policy-validator/src/cedar_schema/parser.rs b/cedar-policy-validator/src/cedar_schema/parser.rs index b999eb90b..a4397ecd4 100644 --- a/cedar-policy-validator/src/cedar_schema/parser.rs +++ b/cedar-policy-validator/src/cedar_schema/parser.rs @@ -62,12 +62,15 @@ fn parse_collect_errors<'a, P, T>( let errors = errs .into_iter() - .map(Into::into) + .map(|rc| ParseError::from_raw_error_recovery(rc, Arc::from(text))) .collect::>(); let parsed = match result { Ok(parsed) => parsed, Err(e) => { - return Err(ParseErrors::new(e.into(), errors)); + return Err(ParseErrors::new( + ParseError::from_raw_parse_error(e, Arc::from(text)), + errors, + )); } }; match ParseErrors::from_iter(errors) { From ba05696deeb805514f1f9bf5d939c9e7979fa191 Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Tue, 3 Dec 2024 11:29:15 -0800 Subject: [PATCH 03/10] updated changelog Signed-off-by: Shaobo He --- cedar-policy/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cedar-policy/CHANGELOG.md b/cedar-policy/CHANGELOG.md index 6faee2ab9..ff9ef26ec 100644 --- a/cedar-policy/CHANGELOG.md +++ b/cedar-policy/CHANGELOG.md @@ -25,6 +25,10 @@ Cedar Language Version: TBD - Stopped emitting warnings for identifiers containing certain printable ASCII characters (e.g., `/` and `:`) (#1336, resolving #621) +### Fixed + +- Attach source code to certain errors so that `miette::Report`s derived from these errors are self-contained (#1351, resolving #977 and #1335) + ## [4.2.2] - 2024-11-11 Cedar Language version: 4.1 From 55f4bdf1148e1dc431ffca4b251feb88aa1d1a96 Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Tue, 3 Dec 2024 13:19:46 -0800 Subject: [PATCH 04/10] probably too much for fixing a source location? Signed-off-by: Shaobo He --- Cargo.lock | 79 ++++++++++++------- cedar-policy-core/Cargo.toml | 1 + cedar-policy-core/src/ast/policy.rs | 64 +++++++++------ .../src/est/scope_constraints.rs | 20 ++--- .../src/parser/cst_to_ast/to_ref_or_refs.rs | 14 ++-- cedar-policy-validator/src/rbac.rs | 22 +++--- cedar-policy/src/api.rs | 16 ++-- cedar-policy/src/ffi/utils.rs | 4 +- 8 files changed, 131 insertions(+), 89 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1b220a5c4..29e7650c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -355,6 +355,7 @@ dependencies = [ "arbitrary", "chrono", "cool_asserts", + "derivative", "either", "itertools 0.13.0", "lalrpop", @@ -591,7 +592,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -750,7 +751,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn", + "syn 2.0.90", ] [[package]] @@ -761,7 +762,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -774,6 +775,17 @@ dependencies = [ "serde", ] +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "derive_arbitrary" version = "1.4.1" @@ -782,7 +794,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -825,7 +837,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -963,7 +975,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -1248,7 +1260,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -1492,7 +1504,7 @@ dependencies = [ "quote", "regex-syntax", "rustc_version", - "syn", + "syn 2.0.90", ] [[package]] @@ -1539,7 +1551,7 @@ checksum = "23c9b935fbe1d6cbd1dac857b54a688145e2d93f48db36010514d0f612d0ad67" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -1797,7 +1809,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" dependencies = [ "proc-macro2", - "syn", + "syn 2.0.90", ] [[package]] @@ -1865,7 +1877,7 @@ dependencies = [ "prost", "prost-types", "regex", - "syn", + "syn 2.0.90", "tempfile", ] @@ -1879,7 +1891,7 @@ dependencies = [ "itertools 0.13.0", "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -2000,7 +2012,7 @@ checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -2064,7 +2076,7 @@ dependencies = [ "regex", "relative-path", "rustc_version", - "syn", + "syn 2.0.90", "unicode-ident", ] @@ -2193,7 +2205,7 @@ checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -2204,7 +2216,7 @@ checksum = "e578a843d40b4189a4d66bba51d7684f57da5bd7c304c64e14bd63efbef49509" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -2256,7 +2268,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -2385,6 +2397,17 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.90" @@ -2404,7 +2427,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -2482,7 +2505,7 @@ checksum = "b607164372e89797d78b8e23a6d67d5d1038c1c65efd52e1389ef8b77caba2a6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -2493,7 +2516,7 @@ checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -2624,7 +2647,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn", + "syn 2.0.90", ] [[package]] @@ -2782,7 +2805,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.90", "wasm-bindgen-shared", ] @@ -2817,7 +2840,7 @@ checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2851,7 +2874,7 @@ checksum = "222ebde6ea87fbfa6bdd2e9f1fd8a91d60aee5db68792632176c4e16a74fc7d8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -3005,7 +3028,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", "synstructure", ] @@ -3027,7 +3050,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -3047,7 +3070,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", "synstructure", ] @@ -3070,5 +3093,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] diff --git a/cedar-policy-core/Cargo.toml b/cedar-policy-core/Cargo.toml index 92be2b8af..1f5dd89b5 100644 --- a/cedar-policy-core/Cargo.toml +++ b/cedar-policy-core/Cargo.toml @@ -42,6 +42,7 @@ chrono = { version = "0.4.38", optional = true, default-features = false} # protobuf dependency prost = { version = "0.13", optional = true } +derivative = "2.2.0" [features] # by default, enable all Cedar extensions diff --git a/cedar-policy-core/src/ast/policy.rs b/cedar-policy-core/src/ast/policy.rs index 3d3f21408..bfc5c3d90 100644 --- a/cedar-policy-core/src/ast/policy.rs +++ b/cedar-policy-core/src/ast/policy.rs @@ -16,6 +16,7 @@ use crate::ast::*; use crate::parser::Loc; +use derivative::Derivative; use itertools::Itertools; use miette::Diagnostic; use nonempty::{nonempty, NonEmpty}; @@ -1495,10 +1496,10 @@ impl PrincipalConstraint { /// Fill in the Slot, if any, with the given EUID pub fn with_filled_slot(self, euid: Arc) -> Self { match self.constraint { - PrincipalOrResourceConstraint::Eq(EntityReference::Slot) => Self { + PrincipalOrResourceConstraint::Eq(EntityReference::Slot(_)) => Self { constraint: PrincipalOrResourceConstraint::Eq(EntityReference::EUID(euid)), }, - PrincipalOrResourceConstraint::In(EntityReference::Slot) => Self { + PrincipalOrResourceConstraint::In(EntityReference::Slot(_)) => Self { constraint: PrincipalOrResourceConstraint::In(EntityReference::EUID(euid)), }, _ => self, @@ -1626,10 +1627,10 @@ impl ResourceConstraint { /// Fill in the Slot, if any, with the given EUID pub fn with_filled_slot(self, euid: Arc) -> Self { match self.constraint { - PrincipalOrResourceConstraint::Eq(EntityReference::Slot) => Self { + PrincipalOrResourceConstraint::Eq(EntityReference::Slot(_)) => Self { constraint: PrincipalOrResourceConstraint::Eq(EntityReference::EUID(euid)), }, - PrincipalOrResourceConstraint::In(EntityReference::Slot) => Self { + PrincipalOrResourceConstraint::In(EntityReference::Slot(_)) => Self { constraint: PrincipalOrResourceConstraint::In(EntityReference::EUID(euid)), }, _ => self, @@ -1672,12 +1673,22 @@ impl From<&ResourceConstraint> for proto::ResourceConstraint { } /// A reference to an EntityUID that may be a Slot -#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, PartialOrd, Ord, Debug)] +#[derive(Derivative, Serialize, Deserialize, Clone, Debug, Eq)] +#[derivative(Hash, PartialEq, PartialOrd, Ord)] +#[derivative(PartialOrd = "feature_allow_slow_enum")] +#[derivative(Ord = "feature_allow_slow_enum")] pub enum EntityReference { /// Reference to a literal EUID EUID(Arc), /// Template Slot - Slot, + Slot( + #[serde(skip)] + #[derivative(PartialEq = "ignore")] + #[derivative(PartialOrd = "ignore")] + #[derivative(Ord = "ignore")] + #[derivative(Hash = "ignore")] + Option, + ), } impl EntityReference { @@ -1694,7 +1705,10 @@ impl EntityReference { pub fn into_expr(&self, slot: SlotId) -> Expr { match self { EntityReference::EUID(euid) => Expr::val(euid.clone()), - EntityReference::Slot => Expr::slot(slot), + EntityReference::Slot(loc) => loc + .as_ref() + .map(|loc| ExprBuilder::new().with_source_loc(loc.clone()).slot(slot)) + .unwrap_or(Expr::slot(slot)), } } } @@ -1713,7 +1727,7 @@ impl From<&proto::EntityReference> for EntityReference { match proto::entity_reference::Ty::try_from(ty.to_owned()) .expect("decode should succeed") { - proto::entity_reference::Ty::Slot => EntityReference::Slot, + proto::entity_reference::Ty::Slot => EntityReference::Slot(None), } } proto::entity_reference::Data::Euid(euid) => { @@ -1732,7 +1746,7 @@ impl From<&EntityReference> for proto::EntityReference { euid.as_ref(), ))), }, - EntityReference::Slot => Self { + EntityReference::Slot(_) => Self { data: Some(proto::entity_reference::Data::Ty( proto::entity_reference::Ty::Slot.into(), )), @@ -1831,12 +1845,12 @@ impl PrincipalOrResourceConstraint { /// Constrained to equal a slot pub fn is_eq_slot() -> Self { - PrincipalOrResourceConstraint::Eq(EntityReference::Slot) + PrincipalOrResourceConstraint::Eq(EntityReference::Slot(None)) } /// Constrained to be in a slot pub fn is_in_slot() -> Self { - PrincipalOrResourceConstraint::In(EntityReference::Slot) + PrincipalOrResourceConstraint::In(EntityReference::Slot(None)) } /// Hierarchical constraint. @@ -1846,7 +1860,7 @@ impl PrincipalOrResourceConstraint { /// Type constraint additionally constrained to be in a slot. pub fn is_entity_type_in_slot(entity_type: Arc) -> Self { - PrincipalOrResourceConstraint::IsIn(entity_type, EntityReference::Slot) + PrincipalOrResourceConstraint::IsIn(entity_type, EntityReference::Slot(None)) } /// Type constraint with a hierarchical constraint. @@ -1907,11 +1921,11 @@ impl PrincipalOrResourceConstraint { match self { PrincipalOrResourceConstraint::Any => None, PrincipalOrResourceConstraint::In(EntityReference::EUID(euid)) => Some(euid), - PrincipalOrResourceConstraint::In(EntityReference::Slot) => None, + PrincipalOrResourceConstraint::In(EntityReference::Slot(_)) => None, PrincipalOrResourceConstraint::Eq(EntityReference::EUID(euid)) => Some(euid), - PrincipalOrResourceConstraint::Eq(EntityReference::Slot) => None, + PrincipalOrResourceConstraint::Eq(EntityReference::Slot(_)) => None, PrincipalOrResourceConstraint::IsIn(_, EntityReference::EUID(euid)) => Some(euid), - PrincipalOrResourceConstraint::IsIn(_, EntityReference::Slot) => None, + PrincipalOrResourceConstraint::IsIn(_, EntityReference::Slot(_)) => None, PrincipalOrResourceConstraint::Is(_) => None, } } @@ -2321,9 +2335,9 @@ pub(crate) mod test_generators { let v = vec![ PrincipalOrResourceConstraint::any(), PrincipalOrResourceConstraint::is_eq(euid.clone()), - PrincipalOrResourceConstraint::Eq(EntityReference::Slot), + PrincipalOrResourceConstraint::Eq(EntityReference::Slot(None)), PrincipalOrResourceConstraint::is_in(euid), - PrincipalOrResourceConstraint::In(EntityReference::Slot), + PrincipalOrResourceConstraint::In(EntityReference::Slot(None)), ]; v.into_iter() @@ -2607,7 +2621,7 @@ mod test { Some(&e) ); assert_eq!( - PrincipalOrResourceConstraint::In(EntityReference::Slot).get_euid(), + PrincipalOrResourceConstraint::In(EntityReference::Slot(None)).get_euid(), None ); assert_eq!( @@ -2615,7 +2629,7 @@ mod test { Some(&e) ); assert_eq!( - PrincipalOrResourceConstraint::Eq(EntityReference::Slot).get_euid(), + PrincipalOrResourceConstraint::Eq(EntityReference::Slot(None)).get_euid(), None ); assert_eq!( @@ -2633,7 +2647,7 @@ mod test { assert_eq!( PrincipalOrResourceConstraint::IsIn( Arc::new("T".parse().unwrap()), - EntityReference::Slot + EntityReference::Slot(None) ) .get_euid(), None @@ -2694,7 +2708,7 @@ mod test { #[test] fn euid_into_expr() { - let e = EntityReference::Slot; + let e = EntityReference::Slot(None); assert_eq!( e.into_expr(SlotId::principal()), Expr::slot(SlotId::principal()) @@ -2708,7 +2722,7 @@ mod test { #[test] fn por_constraint_display() { - let t = PrincipalOrResourceConstraint::Eq(EntityReference::Slot); + let t = PrincipalOrResourceConstraint::Eq(EntityReference::Slot(None)); let s = t.display(PrincipalOrResource::Principal); assert_eq!(s, "principal == ?principal"); let t = PrincipalOrResourceConstraint::Eq(EntityReference::euid(Arc::new( @@ -2726,7 +2740,7 @@ mod test { "expected a static policy, got a template containing the slot ?principal" ) .help("try removing the template slot(s) from this policy") - .exactly_one_underline("permit(principal == ?principal, action, resource);") + .exactly_one_underline("?principal") .build() ); }); @@ -2781,8 +2795,8 @@ mod test { EntityReference::from(&proto::EntityReference::from(&er1)) ); assert_eq!( - EntityReference::Slot, - EntityReference::from(&proto::EntityReference::from(&EntityReference::Slot)) + EntityReference::Slot(None), + EntityReference::from(&proto::EntityReference::from(&EntityReference::Slot(None))) ); let read_euid: Arc = Arc::new(EntityUID::with_eid("read")); diff --git a/cedar-policy-core/src/est/scope_constraints.rs b/cedar-policy-core/src/est/scope_constraints.rs index 4a42355f9..f62409aef 100644 --- a/cedar-policy-core/src/est/scope_constraints.rs +++ b/cedar-policy-core/src/est/scope_constraints.rs @@ -600,7 +600,7 @@ impl From for PrincipalConstraint { entity: EntityUidJson::ImplicitEntityEscape((&*e).into()), }) } - ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::Slot) => { + ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::Slot(_)) => { PrincipalConstraint::Eq(EqConstraint::Slot { slot: ast::SlotId::principal(), }) @@ -610,7 +610,7 @@ impl From for PrincipalConstraint { entity: EntityUidJson::ImplicitEntityEscape((&*e).into()), }) } - ast::PrincipalOrResourceConstraint::In(ast::EntityReference::Slot) => { + ast::PrincipalOrResourceConstraint::In(ast::EntityReference::Slot(_)) => { PrincipalConstraint::In(PrincipalOrResourceInConstraint::Slot { slot: ast::SlotId::principal(), }) @@ -622,7 +622,7 @@ impl From for PrincipalConstraint { ast::EntityReference::EUID(e) => PrincipalOrResourceInConstraint::Entity { entity: EntityUidJson::ImplicitEntityEscape((&*e).into()), }, - ast::EntityReference::Slot => PrincipalOrResourceInConstraint::Slot { + ast::EntityReference::Slot(_) => PrincipalOrResourceInConstraint::Slot { slot: ast::SlotId::principal(), }, }), @@ -647,7 +647,7 @@ impl From for ResourceConstraint { entity: EntityUidJson::ImplicitEntityEscape((&*e).into()), }) } - ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::Slot) => { + ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::Slot(_)) => { ResourceConstraint::Eq(EqConstraint::Slot { slot: ast::SlotId::resource(), }) @@ -657,7 +657,7 @@ impl From for ResourceConstraint { entity: EntityUidJson::ImplicitEntityEscape((&*e).into()), }) } - ast::PrincipalOrResourceConstraint::In(ast::EntityReference::Slot) => { + ast::PrincipalOrResourceConstraint::In(ast::EntityReference::Slot(_)) => { ResourceConstraint::In(PrincipalOrResourceInConstraint::Slot { slot: ast::SlotId::resource(), }) @@ -669,7 +669,7 @@ impl From for ResourceConstraint { ast::EntityReference::EUID(e) => PrincipalOrResourceInConstraint::Entity { entity: EntityUidJson::ImplicitEntityEscape((&*e).into()), }, - ast::EntityReference::Slot => PrincipalOrResourceInConstraint::Slot { + ast::EntityReference::Slot(_) => PrincipalOrResourceInConstraint::Slot { slot: ast::SlotId::resource(), }, }), @@ -700,7 +700,7 @@ impl TryFrom for ast::PrincipalOrResourceConstraint { PrincipalConstraint::Eq(EqConstraint::Slot { slot }) => { if slot == ast::SlotId::principal() { Ok(ast::PrincipalOrResourceConstraint::Eq( - ast::EntityReference::Slot, + ast::EntityReference::Slot(None), )) } else { Err(Self::Error::InvalidSlotName) @@ -714,7 +714,7 @@ impl TryFrom for ast::PrincipalOrResourceConstraint { PrincipalConstraint::In(PrincipalOrResourceInConstraint::Slot { slot }) => { if slot == ast::SlotId::principal() { Ok(ast::PrincipalOrResourceConstraint::In( - ast::EntityReference::Slot, + ast::EntityReference::Slot(None), )) } else { Err(Self::Error::InvalidSlotName) @@ -765,7 +765,7 @@ impl TryFrom for ast::PrincipalOrResourceConstraint { ResourceConstraint::Eq(EqConstraint::Slot { slot }) => { if slot == ast::SlotId::resource() { Ok(ast::PrincipalOrResourceConstraint::Eq( - ast::EntityReference::Slot, + ast::EntityReference::Slot(None), )) } else { Err(Self::Error::InvalidSlotName) @@ -779,7 +779,7 @@ impl TryFrom for ast::PrincipalOrResourceConstraint { ResourceConstraint::In(PrincipalOrResourceInConstraint::Slot { slot }) => { if slot == ast::SlotId::resource() { Ok(ast::PrincipalOrResourceConstraint::In( - ast::EntityReference::Slot, + ast::EntityReference::Slot(None), )) } else { Err(Self::Error::InvalidSlotName) diff --git a/cedar-policy-core/src/parser/cst_to_ast/to_ref_or_refs.rs b/cedar-policy-core/src/parser/cst_to_ast/to_ref_or_refs.rs index 9f52be652..0dc036859 100644 --- a/cedar-policy-core/src/parser/cst_to_ast/to_ref_or_refs.rs +++ b/cedar-policy-core/src/parser/cst_to_ast/to_ref_or_refs.rs @@ -33,7 +33,7 @@ use crate::{ /// in the policy scope. trait RefKind: Sized { fn err_str() -> &'static str; - fn create_single_ref(e: EntityUID, loc: &Loc) -> Result; + fn create_single_ref(e: EntityUID) -> Result; fn create_multiple_refs(loc: &Loc) -> Result) -> Self>; fn create_slot(loc: &Loc) -> Result; } @@ -45,7 +45,7 @@ impl RefKind for SingleEntity { "an entity uid" } - fn create_single_ref(e: EntityUID, _loc: &Loc) -> Result { + fn create_single_ref(e: EntityUID) -> Result { Ok(SingleEntity(e)) } @@ -77,11 +77,11 @@ impl RefKind for EntityReference { "an entity uid or matching template slot" } - fn create_slot(_loc: &Loc) -> Result { - Ok(EntityReference::Slot) + fn create_slot(loc: &Loc) -> Result { + Ok(EntityReference::Slot(Some(loc.clone()))) } - fn create_single_ref(e: EntityUID, _loc: &Loc) -> Result { + fn create_single_ref(e: EntityUID) -> Result { Ok(EntityReference::euid(Arc::new(e))) } @@ -122,7 +122,7 @@ impl RefKind for OneOrMultipleRefs { .into()) } - fn create_single_ref(e: EntityUID, _loc: &Loc) -> Result { + fn create_single_ref(e: EntityUID) -> Result { Ok(OneOrMultipleRefs::Single(e)) } @@ -211,7 +211,7 @@ impl Node> { )) .into()) } - cst::Primary::Ref(x) => T::create_single_ref(x.to_ref()?, &self.loc), + cst::Primary::Ref(x) => T::create_single_ref(x.to_ref()?), cst::Primary::Name(name) => { let found = match name.as_inner() { Some(name) => format!("name `{name}`"), diff --git a/cedar-policy-validator/src/rbac.rs b/cedar-policy-validator/src/rbac.rs index ea97569fe..b27ad86f5 100644 --- a/cedar-policy-validator/src/rbac.rs +++ b/cedar-policy-validator/src/rbac.rs @@ -361,19 +361,21 @@ impl Validator { PrincipalOrResourceConstraint::In(EntityReference::EUID(euid)) => { Box::new(self.schema.get_entity_types_in(euid.as_ref()).into_iter()) } - PrincipalOrResourceConstraint::Eq(EntityReference::Slot) - | PrincipalOrResourceConstraint::In(EntityReference::Slot) => { + PrincipalOrResourceConstraint::Eq(EntityReference::Slot(_)) + | PrincipalOrResourceConstraint::In(EntityReference::Slot(_)) => { Box::new(self.schema.known_entity_types()) } PrincipalOrResourceConstraint::Is(entity_type) - | PrincipalOrResourceConstraint::IsIn(entity_type, EntityReference::Slot) => Box::new( - if self.schema.is_known_entity_type(entity_type) { - Some(entity_type.as_ref()) - } else { - None - } - .into_iter(), - ), + | PrincipalOrResourceConstraint::IsIn(entity_type, EntityReference::Slot(_)) => { + Box::new( + if self.schema.is_known_entity_type(entity_type) { + Some(entity_type.as_ref()) + } else { + None + } + .into_iter(), + ) + } PrincipalOrResourceConstraint::IsIn(entity_type, EntityReference::EUID(in_entity)) => { Box::new( self.schema diff --git a/cedar-policy/src/api.rs b/cedar-policy/src/api.rs index 56a286b49..c83ea6766 100644 --- a/cedar-policy/src/api.rs +++ b/cedar-policy/src/api.rs @@ -2599,13 +2599,13 @@ impl Template { ast::PrincipalOrResourceConstraint::In(eref) => { TemplatePrincipalConstraint::In(match eref { ast::EntityReference::EUID(e) => Some(e.as_ref().clone().into()), - ast::EntityReference::Slot => None, + ast::EntityReference::Slot(_) => None, }) } ast::PrincipalOrResourceConstraint::Eq(eref) => { TemplatePrincipalConstraint::Eq(match eref { ast::EntityReference::EUID(e) => Some(e.as_ref().clone().into()), - ast::EntityReference::Slot => None, + ast::EntityReference::Slot(_) => None, }) } ast::PrincipalOrResourceConstraint::Is(entity_type) => { @@ -2616,7 +2616,7 @@ impl Template { entity_type.as_ref().clone().into(), match eref { ast::EntityReference::EUID(e) => Some(e.as_ref().clone().into()), - ast::EntityReference::Slot => None, + ast::EntityReference::Slot(_) => None, }, ) } @@ -2642,13 +2642,13 @@ impl Template { ast::PrincipalOrResourceConstraint::In(eref) => { TemplateResourceConstraint::In(match eref { ast::EntityReference::EUID(e) => Some(e.as_ref().clone().into()), - ast::EntityReference::Slot => None, + ast::EntityReference::Slot(_) => None, }) } ast::PrincipalOrResourceConstraint::Eq(eref) => { TemplateResourceConstraint::Eq(match eref { ast::EntityReference::EUID(e) => Some(e.as_ref().clone().into()), - ast::EntityReference::Slot => None, + ast::EntityReference::Slot(_) => None, }) } ast::PrincipalOrResourceConstraint::Is(entity_type) => { @@ -2659,7 +2659,7 @@ impl Template { entity_type.as_ref().clone().into(), match eref { ast::EntityReference::EUID(e) => Some(e.as_ref().clone().into()), - ast::EntityReference::Slot => None, + ast::EntityReference::Slot(_) => None, }, ) } @@ -3002,7 +3002,9 @@ impl Policy { ast::EntityReference::EUID(euid) => EntityUid::ref_cast(euid), // PANIC SAFETY: This `unwrap` here is safe due the invariant (values total map) on policies. #[allow(clippy::unwrap_used)] - ast::EntityReference::Slot => EntityUid::ref_cast(self.ast.env().get(&slot).unwrap()), + ast::EntityReference::Slot(_) => { + EntityUid::ref_cast(self.ast.env().get(&slot).unwrap()) + } } } diff --git a/cedar-policy/src/ffi/utils.rs b/cedar-policy/src/ffi/utils.rs index 9cb417a79..966f81e1d 100644 --- a/cedar-policy/src/ffi/utils.rs +++ b/cedar-policy/src/ffi/utils.rs @@ -735,7 +735,7 @@ mod test { &err, &ExpectedErrorMessageBuilder::error("failed to parse policy from string") .source("expected a static policy, got a template containing the slot ?principal") - .exactly_one_underline(src) + .exactly_one_underline("?principal") .help("try removing the template slot(s) from this policy") .build(), ); @@ -907,7 +907,7 @@ mod test { "failed to parse policy with id `policy0` from string", ) .source("expected a static policy, got a template containing the slot ?principal") - .exactly_one_underline("permit(principal == ?principal, action, resource);") + .exactly_one_underline("?principal") .help("try removing the template slot(s) from this policy") .build(), ); From e0fec080e92976fe2d039b20a0f1b52a7dbd90b7 Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Tue, 3 Dec 2024 13:36:09 -0800 Subject: [PATCH 05/10] changed to `educe` Signed-off-by: Shaobo He --- Cargo.lock | 112 +++++++++++++++------------- cedar-policy-core/Cargo.toml | 2 +- cedar-policy-core/src/ast/policy.rs | 15 ++-- 3 files changed, 68 insertions(+), 61 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 29e7650c3..689afe439 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -355,7 +355,7 @@ dependencies = [ "arbitrary", "chrono", "cool_asserts", - "derivative", + "educe", "either", "itertools 0.13.0", "lalrpop", @@ -592,7 +592,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -751,7 +751,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.90", + "syn", ] [[package]] @@ -762,7 +762,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -775,17 +775,6 @@ dependencies = [ "serde", ] -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "derive_arbitrary" version = "1.4.1" @@ -794,7 +783,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -837,7 +826,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -846,6 +835,18 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "either" version = "1.13.0" @@ -867,6 +868,26 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +[[package]] +name = "enum-ordinalize" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -975,7 +996,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -1260,7 +1281,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -1504,7 +1525,7 @@ dependencies = [ "quote", "regex-syntax", "rustc_version", - "syn 2.0.90", + "syn", ] [[package]] @@ -1551,7 +1572,7 @@ checksum = "23c9b935fbe1d6cbd1dac857b54a688145e2d93f48db36010514d0f612d0ad67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -1809,7 +1830,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" dependencies = [ "proc-macro2", - "syn 2.0.90", + "syn", ] [[package]] @@ -1877,7 +1898,7 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.90", + "syn", "tempfile", ] @@ -1891,7 +1912,7 @@ dependencies = [ "itertools 0.13.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -2012,7 +2033,7 @@ checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -2076,7 +2097,7 @@ dependencies = [ "regex", "relative-path", "rustc_version", - "syn 2.0.90", + "syn", "unicode-ident", ] @@ -2205,7 +2226,7 @@ checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -2216,7 +2237,7 @@ checksum = "e578a843d40b4189a4d66bba51d7684f57da5bd7c304c64e14bd63efbef49509" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -2268,7 +2289,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -2397,17 +2418,6 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.90" @@ -2427,7 +2437,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -2505,7 +2515,7 @@ checksum = "b607164372e89797d78b8e23a6d67d5d1038c1c65efd52e1389ef8b77caba2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -2516,7 +2526,7 @@ checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -2647,7 +2657,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.90", + "syn", ] [[package]] @@ -2805,7 +2815,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.90", + "syn", "wasm-bindgen-shared", ] @@ -2840,7 +2850,7 @@ checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2874,7 +2884,7 @@ checksum = "222ebde6ea87fbfa6bdd2e9f1fd8a91d60aee5db68792632176c4e16a74fc7d8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -3028,7 +3038,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", "synstructure", ] @@ -3050,7 +3060,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -3070,7 +3080,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", "synstructure", ] @@ -3093,5 +3103,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] diff --git a/cedar-policy-core/Cargo.toml b/cedar-policy-core/Cargo.toml index 1f5dd89b5..bb69f3387 100644 --- a/cedar-policy-core/Cargo.toml +++ b/cedar-policy-core/Cargo.toml @@ -42,7 +42,7 @@ chrono = { version = "0.4.38", optional = true, default-features = false} # protobuf dependency prost = { version = "0.13", optional = true } -derivative = "2.2.0" +educe = "0.6.0" [features] # by default, enable all Cedar extensions diff --git a/cedar-policy-core/src/ast/policy.rs b/cedar-policy-core/src/ast/policy.rs index bfc5c3d90..ac5d1e6cc 100644 --- a/cedar-policy-core/src/ast/policy.rs +++ b/cedar-policy-core/src/ast/policy.rs @@ -16,7 +16,7 @@ use crate::ast::*; use crate::parser::Loc; -use derivative::Derivative; +use educe::Educe; use itertools::Itertools; use miette::Diagnostic; use nonempty::{nonempty, NonEmpty}; @@ -1673,20 +1673,17 @@ impl From<&ResourceConstraint> for proto::ResourceConstraint { } /// A reference to an EntityUID that may be a Slot -#[derive(Derivative, Serialize, Deserialize, Clone, Debug, Eq)] -#[derivative(Hash, PartialEq, PartialOrd, Ord)] -#[derivative(PartialOrd = "feature_allow_slow_enum")] -#[derivative(Ord = "feature_allow_slow_enum")] +#[derive(Educe, Serialize, Deserialize, Clone, Debug, Eq)] +#[educe(Hash, PartialEq, PartialOrd, Ord)] pub enum EntityReference { /// Reference to a literal EUID EUID(Arc), /// Template Slot Slot( #[serde(skip)] - #[derivative(PartialEq = "ignore")] - #[derivative(PartialOrd = "ignore")] - #[derivative(Ord = "ignore")] - #[derivative(Hash = "ignore")] + #[educe(PartialEq(ignore))] + #[educe(PartialOrd(ignore))] + #[educe(Hash(ignore))] Option, ), } From 0bbe8d6824b10516e84a30ac0c9d88e922d4adaa Mon Sep 17 00:00:00 2001 From: shaobo-he-aws <130499339+shaobo-he-aws@users.noreply.github.com> Date: Tue, 3 Dec 2024 13:45:51 -0800 Subject: [PATCH 06/10] Apply suggestions from code review Co-authored-by: Craig Disselkoen --- cedar-policy-core/src/test_utils.rs | 2 +- cedar-policy-validator/src/cedar_schema/err.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/cedar-policy-core/src/test_utils.rs b/cedar-policy-core/src/test_utils.rs index 247ef7b69..cfeb50560 100644 --- a/cedar-policy-core/src/test_utils.rs +++ b/cedar-policy-core/src/test_utils.rs @@ -294,7 +294,7 @@ impl<'a> ExpectedErrorMessage<'a> { if expected_num_labels != 0 { let src = err .source_code() - .expect("src can be `None` only in the case where we expect no underlines"); + .expect("err.source_code() should be `Some` if we are expecting underlines"); for (expected, actual) in self .underlines .iter() diff --git a/cedar-policy-validator/src/cedar_schema/err.rs b/cedar-policy-validator/src/cedar_schema/err.rs index 2a10039ab..232529cbb 100644 --- a/cedar-policy-validator/src/cedar_schema/err.rs +++ b/cedar-policy-validator/src/cedar_schema/err.rs @@ -123,8 +123,7 @@ impl ParseError { impl ParseError { /// Extract a primary source span locating the error. pub fn primary_source_span(&self) -> SourceSpan { - let Self { err, .. } = self; - match err { + match &self.err { OwnedRawParseError::InvalidToken { location } => SourceSpan::from(*location), OwnedRawParseError::UnrecognizedEof { location, .. } => SourceSpan::from(*location), OwnedRawParseError::UnrecognizedToken { From 825f41f9a9116dd11719f419dd082bae5654bdb7 Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Tue, 3 Dec 2024 13:52:33 -0800 Subject: [PATCH 07/10] review feedback Signed-off-by: Shaobo He --- cedar-policy-core/src/ast/name.rs | 3 +-- cedar-policy-core/src/test_utils.rs | 4 ---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/cedar-policy-core/src/ast/name.rs b/cedar-policy-core/src/ast/name.rs index 90165499c..9eb46084a 100644 --- a/cedar-policy-core/src/ast/name.rs +++ b/cedar-policy-core/src/ast/name.rs @@ -394,12 +394,11 @@ impl std::fmt::Display for ValidSlotId { } /// [`SlotId`] plus a source location -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone)] pub struct Slot { /// [`SlotId`] pub id: SlotId, /// Source location, if available - #[serde(skip)] pub loc: Option, } diff --git a/cedar-policy-core/src/test_utils.rs b/cedar-policy-core/src/test_utils.rs index cfeb50560..f5d0d7bb5 100644 --- a/cedar-policy-core/src/test_utils.rs +++ b/cedar-policy-core/src/test_utils.rs @@ -157,10 +157,6 @@ impl<'a> ExpectedErrorMessage<'a> { /// Return a boolean indicating whether a given error matches this expected message. /// (If you want to assert that it matches, use [`expect_err()`] instead, /// for much better assertion-failure messages.) - /// - /// `src` is the full source text (which the miette labels index into). - /// It can be omitted only in the case where we expect no underlines. - /// Panics if this invariant is violated. pub fn matches(&self, error: &impl miette::Diagnostic) -> bool { self.matches_error(error) && self.matches_help(error) From a171b9159b0508ea95877a5252141c96e1b756ee Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Tue, 3 Dec 2024 15:21:53 -0800 Subject: [PATCH 08/10] macros Signed-off-by: Shaobo He --- cedar-policy-core/src/error_macros.rs | 6 +++--- cedar-policy-core/src/parser/err.rs | 11 +---------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/cedar-policy-core/src/error_macros.rs b/cedar-policy-core/src/error_macros.rs index 77f5fd444..d9d26a689 100644 --- a/cedar-policy-core/src/error_macros.rs +++ b/cedar-policy-core/src/error_macros.rs @@ -37,15 +37,15 @@ macro_rules! impl_diagnostic_from_source_loc_field { /// of a field of type `Option` #[macro_export] macro_rules! impl_diagnostic_from_source_loc_opt_field { - ( $i:ident ) => { + ( $($id:ident).+ ) => { fn source_code(&self) -> Option<&dyn miette::SourceCode> { - self.$i + self.$($id).+ .as_ref() .map(|loc| &loc.src as &dyn miette::SourceCode) } fn labels(&self) -> Option + '_>> { - self.$i + self.$($id).+ .as_ref() .map(|loc| Box::new(std::iter::once(miette::LabeledSpan::underline(loc.span))) as _) } diff --git a/cedar-policy-core/src/parser/err.rs b/cedar-policy-core/src/parser/err.rs index ad535215d..238da3408 100644 --- a/cedar-policy-core/src/parser/err.rs +++ b/cedar-policy-core/src/parser/err.rs @@ -487,16 +487,7 @@ pub mod parse_errors { )) } - fn labels(&self) -> Option + '_>> { - self.slot.loc.as_ref().map(|loc| { - let label = miette::LabeledSpan::underline(loc.span); - Box::new(std::iter::once(label)) as Box> - }) - } - - fn source_code(&self) -> Option<&dyn miette::SourceCode> { - self.slot.loc.as_ref().map(|l| l as &dyn miette::SourceCode) - } + impl_diagnostic_from_source_loc_opt_field!(slot.loc); } impl From for ExpectedStaticPolicy { From a6e66c75e56fa91f233751643fdb105206362356 Mon Sep 17 00:00:00 2001 From: shaobo-he-aws <130499339+shaobo-he-aws@users.noreply.github.com> Date: Thu, 5 Dec 2024 10:20:28 -0800 Subject: [PATCH 09/10] Update cedar-policy-core/src/ast/policy.rs Co-authored-by: Craig Disselkoen --- cedar-policy-core/src/ast/policy.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cedar-policy-core/src/ast/policy.rs b/cedar-policy-core/src/ast/policy.rs index ac5d1e6cc..23233fe99 100644 --- a/cedar-policy-core/src/ast/policy.rs +++ b/cedar-policy-core/src/ast/policy.rs @@ -1702,10 +1702,7 @@ impl EntityReference { pub fn into_expr(&self, slot: SlotId) -> Expr { match self { EntityReference::EUID(euid) => Expr::val(euid.clone()), - EntityReference::Slot(loc) => loc - .as_ref() - .map(|loc| ExprBuilder::new().with_source_loc(loc.clone()).slot(slot)) - .unwrap_or(Expr::slot(slot)), + EntityReference::Slot(loc) => Expr::slot(slot).with_maybe_source_loc(loc.cloned()), } } } From f93e6b7dbabdaf80317785e23391492de285b32b Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Thu, 5 Dec 2024 10:31:27 -0800 Subject: [PATCH 10/10] fixes Signed-off-by: Shaobo He --- cedar-policy-core/Cargo.toml | 2 +- cedar-policy-core/src/ast/policy.rs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cedar-policy-core/Cargo.toml b/cedar-policy-core/Cargo.toml index bb69f3387..9c0fa7ba7 100644 --- a/cedar-policy-core/Cargo.toml +++ b/cedar-policy-core/Cargo.toml @@ -28,6 +28,7 @@ stacker = "0.1.15" arbitrary = { version = "1", features = ["derive"], optional = true } miette = { version = "7.4.0", features = ["serde"] } nonempty = "0.10.0" +educe = "0.6.0" # decimal extension requires regex regex = { version = "1.8", features = ["unicode"], optional = true } @@ -42,7 +43,6 @@ chrono = { version = "0.4.38", optional = true, default-features = false} # protobuf dependency prost = { version = "0.13", optional = true } -educe = "0.6.0" [features] # by default, enable all Cedar extensions diff --git a/cedar-policy-core/src/ast/policy.rs b/cedar-policy-core/src/ast/policy.rs index 23233fe99..d6fbac830 100644 --- a/cedar-policy-core/src/ast/policy.rs +++ b/cedar-policy-core/src/ast/policy.rs @@ -1702,7 +1702,9 @@ impl EntityReference { pub fn into_expr(&self, slot: SlotId) -> Expr { match self { EntityReference::EUID(euid) => Expr::val(euid.clone()), - EntityReference::Slot(loc) => Expr::slot(slot).with_maybe_source_loc(loc.cloned()), + EntityReference::Slot(loc) => { + Expr::slot(slot).with_maybe_source_loc(loc.as_ref().cloned()) + } } } }