diff --git a/crates/polars-error/src/lib.rs b/crates/polars-error/src/lib.rs index b67e4702a9c0..57ee5da352b5 100644 --- a/crates/polars-error/src/lib.rs +++ b/crates/polars-error/src/lib.rs @@ -230,7 +230,7 @@ impl PolarsError { StructFieldNotFound(msg) => StructFieldNotFound(func(msg).into()), SQLInterface(msg) => SQLInterface(func(msg).into()), SQLSyntax(msg) => SQLSyntax(func(msg).into()), - _ => unreachable!(), + Context { error, .. } => error.wrap_msg(func), } } diff --git a/crates/polars-plan/src/plans/conversion/dsl_to_ir.rs b/crates/polars-plan/src/plans/conversion/dsl_to_ir.rs index 3f17e83eefb5..62fd0673d496 100644 --- a/crates/polars-plan/src/plans/conversion/dsl_to_ir.rs +++ b/crates/polars-plan/src/plans/conversion/dsl_to_ir.rs @@ -28,23 +28,12 @@ fn empty_df() -> IR { } } -macro_rules! failed_input { - ($($t:tt)*) => { - failed_input_args!(stringify!($($t)*)) - } -} -macro_rules! failed_input_args { - ($name:expr) => { - format!("'{}' input failed to resolve", $name).into() - }; -} - macro_rules! failed_here { ($($t:tt)*) => { - format!("'{}' failed", stringify!($($t)*)).into() + format!("'{}'", stringify!($($t)*)).into() } } -pub(super) use {failed_here, failed_input, failed_input_args}; +pub(super) use failed_here; pub fn to_alp( lp: DslPlan, @@ -65,7 +54,29 @@ pub fn to_alp( opt_flags, }; - to_alp_impl(lp, &mut ctxt) + match to_alp_impl(lp, &mut ctxt) { + Ok(out) => Ok(out), + Err(err) => { + if let Some(ir_until_then) = lp_arena.last_node() { + let node_name = if let PolarsError::Context { msg, .. } = &err { + msg + } else { + "THIS_NODE" + }; + let plan = IRPlan::new( + ir_until_then, + std::mem::take(lp_arena), + std::mem::take(expr_arena), + ); + let location = format!("{}", plan.display()); + Err(err.wrap_msg(|msg| { + format!("{msg}\n\nResolved plan until failure:\n\n{location}\n\t---> FAILED HERE RESOLVING {node_name} <---") + })) + } else { + Err(err) + } + }, + } } pub(super) struct DslConversionContext<'a> { @@ -284,7 +295,7 @@ pub fn to_alp_impl(lp: DslPlan, ctxt: &mut DslConversionContext) -> PolarsResult .into_iter() .map(|lp| to_alp_impl(lp, ctxt)) .collect::>>() - .map_err(|e| e.context(failed_input!(vertical concat)))?; + .map_err(|e| e.context(failed_here!(vertical concat)))?; if args.diagonal { inputs = @@ -293,7 +304,7 @@ pub fn to_alp_impl(lp: DslPlan, ctxt: &mut DslConversionContext) -> PolarsResult if args.to_supertypes { convert_utils::convert_st_union(&mut inputs, ctxt.lp_arena, ctxt.expr_arena) - .map_err(|e| e.context(failed_input!(vertical concat)))?; + .map_err(|e| e.context(failed_here!(vertical concat)))?; } let options = args.into(); IR::Union { inputs, options } @@ -303,7 +314,7 @@ pub fn to_alp_impl(lp: DslPlan, ctxt: &mut DslConversionContext) -> PolarsResult .into_iter() .map(|lp| to_alp_impl(lp, ctxt)) .collect::>>() - .map_err(|e| e.context(failed_input!(horizontal concat)))?; + .map_err(|e| e.context(failed_here!(horizontal concat)))?; let schema = convert_utils::h_concat_schema(&inputs, ctxt.lp_arena)?; @@ -315,7 +326,7 @@ pub fn to_alp_impl(lp: DslPlan, ctxt: &mut DslConversionContext) -> PolarsResult }, DslPlan::Filter { input, predicate } => { let mut input = - to_alp_impl(owned(input), ctxt).map_err(|e| e.context(failed_input!(filter)))?; + to_alp_impl(owned(input), ctxt).map_err(|e| e.context(failed_here!(filter)))?; let predicate = expand_filter(predicate, input, ctxt.lp_arena, ctxt.opt_flags) .map_err(|e| e.context(failed_here!(filter)))?; @@ -365,7 +376,7 @@ pub fn to_alp_impl(lp: DslPlan, ctxt: &mut DslConversionContext) -> PolarsResult }, DslPlan::Slice { input, offset, len } => { let input = - to_alp_impl(owned(input), ctxt).map_err(|e| e.context(failed_input!(slice)))?; + to_alp_impl(owned(input), ctxt).map_err(|e| e.context(failed_here!(slice)))?; IR::Slice { input, offset, len } }, DslPlan::DataFrameScan { df, schema } => IR::DataFrameScan { @@ -380,7 +391,7 @@ pub fn to_alp_impl(lp: DslPlan, ctxt: &mut DslConversionContext) -> PolarsResult options, } => { let input = - to_alp_impl(owned(input), ctxt).map_err(|e| e.context(failed_input!(select)))?; + to_alp_impl(owned(input), ctxt).map_err(|e| e.context(failed_here!(select)))?; let schema = ctxt.lp_arena.get(input).schema(ctxt.lp_arena); let (exprs, schema) = prepare_projection(expr, &schema, ctxt.opt_flags) .map_err(|e| e.context(failed_here!(select)))?; @@ -430,7 +441,7 @@ pub fn to_alp_impl(lp: DslPlan, ctxt: &mut DslConversionContext) -> PolarsResult ); let input = - to_alp_impl(owned(input), ctxt).map_err(|e| e.context(failed_input!(sort)))?; + to_alp_impl(owned(input), ctxt).map_err(|e| e.context(failed_here!(sort)))?; let mut expanded_cols = Vec::new(); let mut nulls_last = Vec::new(); @@ -477,7 +488,7 @@ pub fn to_alp_impl(lp: DslPlan, ctxt: &mut DslConversionContext) -> PolarsResult }, DslPlan::Cache { input, id } => { let input = - to_alp_impl(owned(input), ctxt).map_err(|e| e.context(failed_input!(cache)))?; + to_alp_impl(owned(input), ctxt).map_err(|e| e.context(failed_here!(cache)))?; IR::Cache { input, id, @@ -493,7 +504,7 @@ pub fn to_alp_impl(lp: DslPlan, ctxt: &mut DslConversionContext) -> PolarsResult options, } => { let input = - to_alp_impl(owned(input), ctxt).map_err(|e| e.context(failed_input!(group_by)))?; + to_alp_impl(owned(input), ctxt).map_err(|e| e.context(failed_here!(group_by)))?; let (keys, aggs, schema) = resolve_group_by( input, @@ -555,7 +566,7 @@ pub fn to_alp_impl(lp: DslPlan, ctxt: &mut DslConversionContext) -> PolarsResult options, } => { let input = to_alp_impl(owned(input), ctxt) - .map_err(|e| e.context(failed_input!(with_columns)))?; + .map_err(|e| e.context(failed_here!(with_columns)))?; let (exprs, schema) = resolve_with_columns(exprs, input, ctxt.lp_arena, ctxt.expr_arena, ctxt.opt_flags) .map_err(|e| e.context(failed_here!(with_columns)))?; @@ -572,7 +583,7 @@ pub fn to_alp_impl(lp: DslPlan, ctxt: &mut DslConversionContext) -> PolarsResult }, DslPlan::Distinct { input, options } => { let input = - to_alp_impl(owned(input), ctxt).map_err(|e| e.context(failed_input!(unique)))?; + to_alp_impl(owned(input), ctxt).map_err(|e| e.context(failed_here!(unique)))?; let input_schema = ctxt.lp_arena.get(input).schema(ctxt.lp_arena); let subset = options @@ -589,9 +600,8 @@ pub fn to_alp_impl(lp: DslPlan, ctxt: &mut DslConversionContext) -> PolarsResult IR::Distinct { input, options } }, DslPlan::MapFunction { input, function } => { - let input = to_alp_impl(owned(input), ctxt).map_err(|e| { - e.context(failed_input_args!(format!("{}", function).to_lowercase())) - })?; + let input = to_alp_impl(owned(input), ctxt) + .map_err(|e| e.context(failed_here!(format!("{}", function).to_lowercase())))?; let input_schema = ctxt.lp_arena.get(input).schema(ctxt.lp_arena); match function { @@ -755,7 +765,7 @@ pub fn to_alp_impl(lp: DslPlan, ctxt: &mut DslConversionContext) -> PolarsResult }, DslPlan::ExtContext { input, contexts } => { let input = to_alp_impl(owned(input), ctxt) - .map_err(|e| e.context(failed_input!(with_context)))?; + .map_err(|e| e.context(failed_here!(with_context)))?; let contexts = contexts .into_iter() .map(|lp| to_alp_impl(lp, ctxt)) @@ -780,7 +790,7 @@ pub fn to_alp_impl(lp: DslPlan, ctxt: &mut DslConversionContext) -> PolarsResult }, DslPlan::Sink { input, payload } => { let input = - to_alp_impl(owned(input), ctxt).map_err(|e| e.context(failed_input!(sink)))?; + to_alp_impl(owned(input), ctxt).map_err(|e| e.context(failed_here!(sink)))?; IR::Sink { input, payload } }, DslPlan::IR { node, dsl, version } => { diff --git a/crates/polars-plan/src/plans/conversion/join.rs b/crates/polars-plan/src/plans/conversion/join.rs index 954714f13b26..b1577da41a33 100644 --- a/crates/polars-plan/src/plans/conversion/join.rs +++ b/crates/polars-plan/src/plans/conversion/join.rs @@ -75,10 +75,10 @@ pub fn resolve_join( } let input_left = input_left.map_right(Ok).right_or_else(|input| { - to_alp_impl(owned(input), ctxt).map_err(|e| e.context(failed_input!(join left))) + to_alp_impl(owned(input), ctxt).map_err(|e| e.context(failed_here!(join left))) })?; let input_right = input_right.map_right(Ok).right_or_else(|input| { - to_alp_impl(owned(input), ctxt).map_err(|e| e.context(failed_input!(join right))) + to_alp_impl(owned(input), ctxt).map_err(|e| e.context(failed_here!(join right))) })?; let schema_left = ctxt.lp_arena.get(input_left).schema(ctxt.lp_arena); @@ -153,9 +153,9 @@ fn resolve_join_where( ) -> PolarsResult { check_join_keys(&predicates)?; let input_left = to_alp_impl(Arc::unwrap_or_clone(input_left), ctxt) - .map_err(|e| e.context(failed_input!(join left)))?; + .map_err(|e| e.context(failed_here!(join left)))?; let input_right = to_alp_impl(Arc::unwrap_or_clone(input_right), ctxt) - .map_err(|e| e.context(failed_input!(join left)))?; + .map_err(|e| e.context(failed_here!(join left)))?; let schema_left = ctxt.lp_arena.get(input_left).schema(ctxt.lp_arena); let schema_right = ctxt diff --git a/crates/polars-utils/src/arena.rs b/crates/polars-utils/src/arena.rs index d5748725c4d1..c8b5823d695e 100644 --- a/crates/polars-utils/src/arena.rs +++ b/crates/polars-utils/src/arena.rs @@ -66,6 +66,14 @@ impl Arena { self.items.pop() } + pub fn last_node(&mut self) -> Option { + if self.is_empty() { + None + } else { + Some(Node(self.items.len() - 1)) + } + } + pub fn len(&self) -> usize { self.items.len() }