Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 5 additions & 6 deletions vortex-array/src/arrays/scalar_fn/vtable/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ use crate::legacy_session;
use crate::scalar_fn::TypedScalarFnInstance;
use crate::scalar_fn::VecExecutionArgs;
use crate::scalar_fn::fns::literal::Literal;
use crate::scalar_fn::fns::root::Root;
use crate::validity::Validity;

/// Execute an expression tree recursively.
Expand All @@ -32,10 +31,10 @@ fn execute_expr(
row_count: usize,
ctx: &mut ExecutionCtx,
) -> VortexResult<ArrayRef> {
// Handle Root expression - this should not happen in validity expressions
if expr.is::<Root>() {
vortex_bail!("Root expression cannot be executed in validity context");
}
// Only Expression::Scalar is executable
let Some(scalar_fn) = expr.as_scalar() else {
vortex_bail!("Only Expression::Scalar is executable");
};

// Handle Literal expression - create a constant array
if expr.is::<Literal>() {
Expand All @@ -52,7 +51,7 @@ fn execute_expr(

let args = VecExecutionArgs::new(inputs, row_count);

Ok(expr.scalar_fn().execute(&args, ctx)?.into_array())
Ok(scalar_fn.execute(&args, ctx)?.into_array())
}

impl ValidityVTable<ScalarFn> for ScalarFn {
Expand Down
6 changes: 5 additions & 1 deletion vortex-array/src/expr/analysis/fallible.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ use crate::expr::label_tree;
pub fn label_is_fallible(expr: &Expression) -> BooleanLabels<'_> {
label_tree(
expr,
|expr| expr.signature().is_fallible(),
|expr| match expr {
Expression::Scalar { scalar_fn, .. } => scalar_fn.signature().is_fallible(),
// The scope itself cannot fail.
Expression::Root => false,
},
|acc, &child| acc | child,
)
}
Expand Down
14 changes: 7 additions & 7 deletions vortex-array/src/expr/analysis/immediate_access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use crate::expr::BoundExpression;
use crate::expr::Expression;
use crate::expr::analysis::AnnotationFn;
use crate::scalar_fn::fns::get_item::GetItem;
use crate::scalar_fn::fns::root::Root;
use crate::scalar_fn::fns::select::Select;

/// Returns the "free fields" for this expression node.
Expand All @@ -26,9 +25,10 @@ use crate::scalar_fn::fns::select::Select;
///
/// # Annotation Rules
///
/// - **[`Select`]**: Returns the included field names if the child is [`Root`].
/// - **[`GetItem`] on [`Root`]**: Returns `[field_name]` if the child is [`Root`].
/// - **[`Root`]**: Returns all field names from `scope` (conservative over-approximation).
/// - **[`Select`]**: Returns the included field names if the child is [`Expression::Root`].
/// - **[`GetItem`] on the root**: Returns `[field_name]` if the child is [`Expression::Root`].
/// - **[`Expression::Root`]**: Returns all field names from `scope` (conservative
/// over-approximation).
/// - **Everything else**: Returns empty (annotations aggregate from children automatically).
///
/// # Example
Expand All @@ -42,18 +42,18 @@ pub fn make_free_field_annotator(
) -> impl AnnotationFn<Expression, Annotation = FieldName> {
move |expr: &Expression| {
if let Some(selection) = expr.as_opt::<Select>() {
if expr.child(0).is::<Root>() {
if expr.child(0).is_root() {
return selection
.normalize_to_included_fields(scope.names())
.vortex_expect("Select fields must be valid for scope")
.into_iter()
.collect();
}
} else if let Some(field_name) = expr.as_opt::<GetItem>() {
if expr.child(0).is::<Root>() {
if expr.child(0).is_root() {
return vec![field_name.clone()];
}
} else if expr.is::<Root>() {
} else if expr.is_root() {
return scope.names().iter().cloned().collect();
}

Expand Down
6 changes: 5 additions & 1 deletion vortex-array/src/expr/analysis/strict.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ use crate::expr::Expression;
pub fn label_strict(expr: &Expression) -> BooleanLabels<'_> {
label_tree(
expr,
|expr| expr.signature().is_strict(),
|expr| match expr {
Expression::Scalar { scalar_fn, .. } => scalar_fn.signature().is_strict(),
// Vacuously strict.
Expression::Root => true,
},
|acc, &child| acc & child,
)
}
Expand Down
8 changes: 5 additions & 3 deletions vortex-array/src/expr/bound_expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ use crate::expr::Expression;
use crate::expr::display::DisplayTreeExpr;
use crate::expr::scope::Scope;
use crate::scalar_fn::ScalarFnRef;
use crate::scalar_fn::fns::root::Root;

/// An [`Expression`] that has been type-checked against a [`Scope`].
///
Expand Down Expand Up @@ -247,7 +246,7 @@ impl Expression {

/// Bind this expression against an explicit [`Scope`].
pub fn bind_scope(&self, scope: &Scope) -> VortexResult<BoundExpression> {
if self.is::<Root>() {
if self.is_root() {
return Ok(BoundExpression::new_root(scope.root().clone()));
}

Expand All @@ -256,7 +255,10 @@ impl Expression {
.iter()
.map(|child| child.bind_scope(scope))
.try_collect()?;
BoundExpression::try_new(self.scalar_fn().clone(), children)
let scalar_fn = self
.as_scalar()
.vortex_expect("root was handled above, so this is a scalar node");
BoundExpression::try_new(scalar_fn.clone(), children)
}
}

Expand Down
18 changes: 13 additions & 5 deletions vortex-array/src/expr/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use std::fmt::Formatter;
use crate::expr::BoundExpression;
use crate::expr::BoundKind;
use crate::expr::Expression;
use crate::expr::root;
use crate::scalar_fn::ChildName;

pub enum DisplayFormat {
Expand Down Expand Up @@ -56,17 +55,26 @@ trait DisplayTreeNode: Sized {
fn fmt_tree_node(&self, f: &mut Formatter<'_>) -> fmt::Result;
}

/// Tree-display label for the scope root.
const ROOT_DISPLAY: &str = "vortex.root()";

impl DisplayTreeNode for Expression {
fn tree_children(&self) -> &[Self] {
Expression::children(self).as_slice()
Expression::children(self)
}

fn tree_child_name(&self, index: usize) -> ChildName {
self.scalar_fn().signature().child_name(index)
match self {
Expression::Scalar { scalar_fn, .. } => scalar_fn.signature().child_name(index),
Expression::Root => unreachable!("the scope root has no children"),
}
}

fn fmt_tree_node(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(self.scalar_fn(), f)
match self {
Expression::Scalar { scalar_fn, .. } => Display::fmt(scalar_fn, f),
Expression::Root => write!(f, "{ROOT_DISPLAY}"),
}
}
}

Expand All @@ -85,7 +93,7 @@ impl DisplayTreeNode for BoundExpression {
fn fmt_tree_node(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self.kind() {
BoundKind::Scalar { scalar_fn, .. } => Display::fmt(scalar_fn, f),
BoundKind::Root => Display::fmt(root().scalar_fn(), f),
BoundKind::Root => write!(f, "{ROOT_DISPLAY}"),
}
}
}
Expand Down
Loading
Loading