From 3d315cd0507ba8b7cbb29b5f7bbc06e1912f6885 Mon Sep 17 00:00:00 2001 From: imxyy_soope_ Date: Sat, 24 Jan 2026 16:44:28 +0800 Subject: [PATCH] feat: debug thunk location --- nix-js/src/codegen.rs | 15 +++++++++++++-- nix-js/src/context.rs | 17 ++++++++++++----- nix-js/src/error.rs | 14 +++++++++----- nix-js/src/ir.rs | 9 +++++---- nix-js/src/ir/utils.rs | 10 +++------- 5 files changed, 42 insertions(+), 23 deletions(-) diff --git a/nix-js/src/codegen.rs b/nix-js/src/codegen.rs index b0bb598..fe79f27 100644 --- a/nix-js/src/codegen.rs +++ b/nix-js/src/codegen.rs @@ -40,6 +40,7 @@ pub(crate) trait CodegenContext { fn get_current_dir(&self) -> &Path; fn get_store_dir(&self) -> &str; fn get_current_source_id(&self) -> usize; + fn get_current_source(&self) -> crate::error::Source; } trait EscapeQuote { @@ -117,9 +118,19 @@ impl Compile for Ir { Ir::Arg(x) => format!("arg{}", x.inner.0), Ir::Let(x) => x.compile(ctx), Ir::Select(x) => x.compile(ctx), - &Ir::Thunk(Thunk { inner: expr_id, .. }) => { + &Ir::Thunk(Thunk { + inner: expr_id, + span, + }) => { let inner = ctx.get_ir(expr_id).compile(ctx); - format!("Nix.createThunk(()=>({}),\"expr{}\")", inner, expr_id.0) + format!( + "Nix.createThunk(()=>({}),\"expr{} {}:{}:{}\")", + inner, + expr_id.0, + ctx.get_current_source().get_name(), + usize::from(span.start()), + usize::from(span.end()) + ) } &Ir::ExprRef(ExprRef { inner: expr_id, .. }) => { format!("expr{}", expr_id.0) diff --git a/nix-js/src/context.rs b/nix-js/src/context.rs index 93b2341..a285ec8 100644 --- a/nix-js/src/context.rs +++ b/nix-js/src/context.rs @@ -230,6 +230,9 @@ impl CodegenContext for Ctx { .checked_sub(1) .expect("current_source not set") } + fn get_current_source(&self) -> crate::error::Source { + self.sources.last().expect("current_source not set").clone() + } fn get_store_dir(&self) -> &str { self.store.as_store().get_store_dir() } @@ -322,8 +325,8 @@ impl DowngradeContext for DowngradeCtx<'_> { ExprId(self.ctx.irs.len() + self.irs.len() - 1) } - fn maybe_thunk(&mut self, id: ExprId) -> ExprId { - let ir = if id.0 < self.ctx.irs.len() { + fn get_ir(&self, id: ExprId) -> &Ir { + if id.0 < self.ctx.irs.len() { self.ctx.irs.get(id.0).expect("unreachable") } else { self.irs @@ -331,7 +334,11 @@ impl DowngradeContext for DowngradeCtx<'_> { .expect("ExprId out of bounds") .as_ref() .expect("maybe_thunk called on an extracted expr") - }; + } + } + + fn maybe_thunk(&mut self, id: ExprId) -> ExprId { + let ir = self.get_ir(id); match ir { Ir::Builtin(_) | Ir::Builtins(_) @@ -449,7 +456,7 @@ impl DowngradeContext for DowngradeCtx<'_> { }) } - fn extract_expr(&mut self, id: ExprId) -> Ir { + fn extract_ir(&mut self, id: ExprId) -> Ir { let local_id = id.0 - self.ctx.irs.len(); self.irs .get_mut(local_id) @@ -458,7 +465,7 @@ impl DowngradeContext for DowngradeCtx<'_> { .expect("extract_expr called on an already extracted expr") } - fn replace_expr(&mut self, id: ExprId, expr: Ir) { + fn replace_ir(&mut self, id: ExprId, expr: Ir) { let local_id = id.0 - self.ctx.irs.len(); let _ = self .irs diff --git a/nix-js/src/error.rs b/nix-js/src/error.rs index 9ffb048..bde6e49 100644 --- a/nix-js/src/error.rs +++ b/nix-js/src/error.rs @@ -35,11 +35,7 @@ impl TryFrom<&str> for Source { impl From for NamedSource> { fn from(value: Source) -> Self { - let name = match value.ty { - SourceType::Eval(_) => "«eval»".into(), - SourceType::Repl(_) => "«repl»".into(), - SourceType::File(path) => path.as_os_str().to_string_lossy().to_string(), - }; + let name = value.get_name(); NamedSource::new(name, value.src.clone()) } } @@ -75,6 +71,14 @@ impl Source { .expect("source file must have a parent dir"), } } + + pub fn get_name(&self) -> String { + match &self.ty { + SourceType::Eval(_) => "«eval»".into(), + SourceType::Repl(_) => "«repl»".into(), + SourceType::File(path) => path.as_os_str().to_string_lossy().to_string(), + } + } } #[derive(Error, Debug, Diagnostic)] diff --git a/nix-js/src/ir.rs b/nix-js/src/ir.rs index 37edead..73d23d6 100644 --- a/nix-js/src/ir.rs +++ b/nix-js/src/ir.rs @@ -28,8 +28,9 @@ pub trait DowngradeContext { fn get_sym(&self, id: SymId) -> &str; fn lookup(&mut self, sym: SymId, span: TextRange) -> Result; - fn extract_expr(&mut self, id: ExprId) -> Ir; - fn replace_expr(&mut self, id: ExprId, expr: Ir); + fn get_ir(&self, id: ExprId) -> &Ir; + fn extract_ir(&mut self, id: ExprId) -> Ir; + fn replace_ir(&mut self, id: ExprId, expr: Ir); fn reserve_slots(&mut self, slots: usize) -> impl Iterator + Clone + use; fn get_current_source(&self) -> Source; @@ -124,7 +125,7 @@ impl AttrSet { // If the next attribute is a static string. if let Some(&id) = self.stcs.get(&ident) { // If a sub-attrset already exists, recurse into it. - let mut ir = ctx.extract_expr(id); + let mut ir = ctx.extract_ir(id); let result = ir .as_mut() .try_unwrap_attr_set() @@ -139,7 +140,7 @@ impl AttrSet { ) }) .and_then(|attrs| attrs._insert(path, name, value, ctx)); - ctx.replace_expr(id, ir); + ctx.replace_ir(id, ir); result?; } else { // Create a new sub-attrset because this path doesn't exist yet. diff --git a/nix-js/src/ir/utils.rs b/nix-js/src/ir/utils.rs index 4f8f1ed..6ed4749 100644 --- a/nix-js/src/ir/utils.rs +++ b/nix-js/src/ir/utils.rs @@ -405,21 +405,17 @@ where for (sym, slot) in binding_keys.iter().copied().zip(slots.iter()) { if let Some(&expr) = bindings.get(&sym) { - ctx.replace_expr( + ctx.replace_ir( *slot, Thunk { inner: expr, - // span: ctx.get_span(expr), - // FIXME: span - span: synthetic_span(), + span: ctx.get_ir(expr).span(), } .to_ir(), ); } else { - return Err(Error::downgrade_error( + return Err(Error::internal( format!("binding '{}' not found", format_symbol(ctx.get_sym(sym))), - ctx.get_current_source(), - synthetic_span(), )); } }