Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
3149180
slots in the condition of template
alanwang67 Jul 29, 2025
4934e51
fixed + added testcases
alanwang67 Jul 29, 2025
e3a96b5
improved comments
alanwang67 Jul 29, 2025
b0e6683
fmt
alanwang67 Jul 29, 2025
41804ab
added has_slot for est & refactored
alanwang67 Jul 30, 2025
4a7e2f5
added missing match arm
alanwang67 Jul 30, 2025
d2967de
added linking with slots in the condition for the EST data structure
alanwang67 Jul 30, 2025
a0436e7
first step
alanwang67 Jul 30, 2025
85e8dd5
adding a new field to Policy
alanwang67 Jul 31, 2025
0b23d86
removed repeated line
alanwang67 Jul 31, 2025
3f40da2
updates to naming
alanwang67 Aug 1, 2025
e35cac5
more naming changes
alanwang67 Aug 1, 2025
48ad73c
changes
alanwang67 Aug 1, 2025
8e725ec
use only one field for values of slots
alanwang67 Aug 7, 2025
5913651
updates to use restricted expr as type for slots for EST format
alanwang67 Aug 8, 2025
d83ee15
Revert "changes"
alanwang67 Aug 8, 2025
92f3c36
Revert "Revert "changes""
alanwang67 Aug 8, 2025
4b4ed2a
Revert "updates to use restricted expr as type for slots for EST format"
alanwang67 Aug 8, 2025
905db6c
Revert "Revert "updates to use restricted expr as type for slots for …
alanwang67 Aug 8, 2025
15c1804
Revert "Revert "Revert "changes"""
alanwang67 Aug 8, 2025
613d171
Revert "Revert "changes""
alanwang67 Aug 8, 2025
bb0b339
Revert "updates to use restricted expr as type for slots for EST format"
alanwang67 Aug 8, 2025
bd272da
Revert "use only one field for values of slots"
alanwang67 Aug 8, 2025
c86dd88
validate incorrect entity types in generalized slots + removed confus…
alanwang67 Aug 8, 2025
a28f3e8
provided better comments clarifying invariants
alanwang67 Aug 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cedar-language-server/src/schema/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ pub(crate) fn fold_schema(schema_info: &SchemaInfo) -> Option<Vec<FoldingRange>>
.filter_map(|et| et.loc.as_loc_ref());
let action_locs = validator.action_ids().filter_map(|a| a.loc());
let common_types = validator
.common_types()
.common_types_extended()
.filter_map(|ct| ct.type_loc.as_loc_ref());

// Combine all locations and create folding ranges
Expand Down
2 changes: 1 addition & 1 deletion cedar-language-server/src/schema/symbols.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ pub(crate) fn schema_symbols(schema_info: &SchemaInfo) -> Option<Vec<DocumentSym

// Create common type symbols
let common_type_symbols: Vec<DocumentSymbol> = validator
.common_types()
.common_types_extended()
.filter_map(|ct| {
ct.name_loc
.as_ref()
Expand Down
2 changes: 2 additions & 0 deletions cedar-policy-core/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,7 @@ mod expr_iterator;
pub use expr_iterator::*;
mod annotation;
pub use annotation::*;
mod generalized_slots_annotation;
pub use generalized_slots_annotation::*;
mod expr_visitor;
pub use expr_visitor::*;
4 changes: 2 additions & 2 deletions cedar-policy-core/src/ast/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ impl<T> Expr<T> {
self.subexpressions()
.filter_map(|exp| match &exp.expr_kind {
ExprKind::Slot(slotid) => Some(Slot {
id: *slotid,
id: slotid.clone(),
loc: exp.source_loc().into_maybe_loc(),
}),
_ => None,
Expand Down Expand Up @@ -1842,7 +1842,7 @@ mod test {
let e = Expr::slot(SlotId::principal());
let p = SlotId::principal();
let r = SlotId::resource();
let set: HashSet<SlotId> = HashSet::from_iter([p]);
let set: HashSet<SlotId> = HashSet::from_iter([p.clone()]);
assert_eq!(set, e.slots().map(|slot| slot.id).collect::<HashSet<_>>());
let e = Expr::or(
Expr::slot(SlotId::principal()),
Expand Down
2 changes: 1 addition & 1 deletion cedar-policy-core/src/ast/expr_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ pub trait ExprVisitor {
match expr.expr_kind() {
ExprKind::Lit(lit) => self.visit_literal(lit, loc),
ExprKind::Var(var) => self.visit_var(*var, loc),
ExprKind::Slot(slot) => self.visit_slot(*slot, loc),
ExprKind::Slot(slot) => self.visit_slot(slot.clone(), loc),
ExprKind::Unknown(unknown) => self.visit_unknown(unknown, loc),
ExprKind::If {
test_expr,
Expand Down
122 changes: 122 additions & 0 deletions cedar-policy-core/src/ast/generalized_slots_annotation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright Cedar Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

use std::collections::BTreeMap;

use crate::ast::SlotId;
use crate::extensions::Extensions;
use crate::validator::{
json_schema::Type as JSONSchemaType, types::Type as ValidatorType, RawName, SchemaError,
ValidatorSchema,
};
use serde::{Deserialize, Serialize};

/// Struct storing the pairs of SlotId's and their corresponding type
#[derive(Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Hash, Serialize, Deserialize)]
pub struct GeneralizedSlotsAnnotation(BTreeMap<SlotId, JSONSchemaType<RawName>>);

impl GeneralizedSlotsAnnotation {
/// Create a new empty `GeneralizedSlotsAnnotation` (with no slots)
pub fn new() -> Self {
Self(BTreeMap::new())
}

/// Get the type of the slot by key
pub fn get(&self, key: &SlotId) -> Option<&JSONSchemaType<RawName>> {
self.0.get(key)
}

/// Iterate over all pairs of slots and their types
pub fn iter(&self) -> impl Iterator<Item = (&SlotId, &JSONSchemaType<RawName>)> {
self.0.iter()
}

/// Tell if it's empty
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}

/// Converts the types of generalized slots annotation to
/// use validator types so that they can be used by the typechecker
pub fn into_validator_generalized_slots_annotation(
self,
schema: &ValidatorSchema,
) -> Result<ValidatorGeneralizedSlotsAnnotation, SchemaError> {
let validator_generalized_slots_annotation: Result<BTreeMap<_, _>, SchemaError> = self
.0
.into_iter()
.map(|(k, ty)| -> Result<_, SchemaError> {
Ok((
k,
schema.json_schema_type_to_validator_type(ty, Extensions::all_available())?,
))
})
.collect();
Ok(validator_generalized_slots_annotation?.into())
}
}

impl Default for GeneralizedSlotsAnnotation {
fn default() -> Self {
Self::new()
}
}

impl FromIterator<(SlotId, JSONSchemaType<RawName>)> for GeneralizedSlotsAnnotation {
fn from_iter<T: IntoIterator<Item = (SlotId, JSONSchemaType<RawName>)>>(iter: T) -> Self {
Self(BTreeMap::from_iter(iter))
}
}

impl From<BTreeMap<SlotId, JSONSchemaType<RawName>>> for GeneralizedSlotsAnnotation {
fn from(value: BTreeMap<SlotId, JSONSchemaType<RawName>>) -> Self {
Self(value)
}
}

/// Struct storing the pairs of SlotId's and their corresponding validator types
#[derive(Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Hash)]
pub struct ValidatorGeneralizedSlotsAnnotation(BTreeMap<SlotId, ValidatorType>);

impl FromIterator<(SlotId, ValidatorType)> for ValidatorGeneralizedSlotsAnnotation {
fn from_iter<T: IntoIterator<Item = (SlotId, ValidatorType)>>(iter: T) -> Self {
Self(BTreeMap::from_iter(iter))
}
}

impl From<BTreeMap<SlotId, ValidatorType>> for ValidatorGeneralizedSlotsAnnotation {
fn from(value: BTreeMap<SlotId, ValidatorType>) -> Self {
Self(value)
}
}

impl Default for ValidatorGeneralizedSlotsAnnotation {
fn default() -> Self {
Self::new()
}
}

impl ValidatorGeneralizedSlotsAnnotation {
/// Create a new empty `ValidatorGeneralizedSlotsAnnotation` (with no slots)
pub fn new() -> Self {
Self(BTreeMap::new())
}

/// Get the validator type of the slot by key
pub fn get(&self, slot: &SlotId) -> Option<&ValidatorType> {
self.0.get(slot)
}
}
18 changes: 15 additions & 3 deletions cedar-policy-core/src/ast/name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ impl<'de> Deserialize<'de> for InternalName {
/// Clone is O(1).
// This simply wraps a separate enum -- currently [`ValidSlotId`] -- in case we
// want to generalize later
#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct SlotId(pub(crate) ValidSlotId);

Expand All @@ -298,6 +298,11 @@ impl SlotId {
Self(ValidSlotId::Resource)
}

/// Create a `generalized slot`
pub fn generalized_slot(id: Id) -> Self {
Self(ValidSlotId::GeneralizedSlot(id))
}

/// Check if a slot represents a principal
pub fn is_principal(&self) -> bool {
matches!(self, Self(ValidSlotId::Principal))
Expand All @@ -307,6 +312,11 @@ impl SlotId {
pub fn is_resource(&self) -> bool {
matches!(self, Self(ValidSlotId::Resource))
}

/// Check if a slot represents a generalized slot
pub fn is_generalized_slot(&self) -> bool {
matches!(self, Self(ValidSlotId::GeneralizedSlot(_)))
}
}

impl From<PrincipalOrResource> for SlotId {
Expand All @@ -324,20 +334,22 @@ impl std::fmt::Display for SlotId {
}
}

/// Two possible variants for Slots
#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
/// Three possible variants for Slots
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub(crate) enum ValidSlotId {
#[serde(rename = "?principal")]
Principal,
#[serde(rename = "?resource")]
Resource,
GeneralizedSlot(Id), // Slots for generalized templates, for more info see [RFC 98](https://github.com/cedar-policy/rfcs/pull/98).
}

impl std::fmt::Display for ValidSlotId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
ValidSlotId::Principal => "principal",
ValidSlotId::Resource => "resource",
ValidSlotId::GeneralizedSlot(id) => id.as_ref(),
};
write!(f, "?{s}")
}
Expand Down
Loading
Loading