feat: debug thunk location

This commit is contained in:
2026-01-24 16:44:28 +08:00
parent 62ec37f3ad
commit 3d315cd050
5 changed files with 42 additions and 23 deletions

View File

@@ -40,6 +40,7 @@ pub(crate) trait CodegenContext {
fn get_current_dir(&self) -> &Path; fn get_current_dir(&self) -> &Path;
fn get_store_dir(&self) -> &str; fn get_store_dir(&self) -> &str;
fn get_current_source_id(&self) -> usize; fn get_current_source_id(&self) -> usize;
fn get_current_source(&self) -> crate::error::Source;
} }
trait EscapeQuote { trait EscapeQuote {
@@ -117,9 +118,19 @@ impl<Ctx: CodegenContext> Compile<Ctx> for Ir {
Ir::Arg(x) => format!("arg{}", x.inner.0), Ir::Arg(x) => format!("arg{}", x.inner.0),
Ir::Let(x) => x.compile(ctx), Ir::Let(x) => x.compile(ctx),
Ir::Select(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); 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, .. }) => { &Ir::ExprRef(ExprRef { inner: expr_id, .. }) => {
format!("expr{}", expr_id.0) format!("expr{}", expr_id.0)

View File

@@ -230,6 +230,9 @@ impl CodegenContext for Ctx {
.checked_sub(1) .checked_sub(1)
.expect("current_source not set") .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 { fn get_store_dir(&self) -> &str {
self.store.as_store().get_store_dir() self.store.as_store().get_store_dir()
} }
@@ -322,8 +325,8 @@ impl DowngradeContext for DowngradeCtx<'_> {
ExprId(self.ctx.irs.len() + self.irs.len() - 1) ExprId(self.ctx.irs.len() + self.irs.len() - 1)
} }
fn maybe_thunk(&mut self, id: ExprId) -> ExprId { fn get_ir(&self, id: ExprId) -> &Ir {
let ir = if id.0 < self.ctx.irs.len() { if id.0 < self.ctx.irs.len() {
self.ctx.irs.get(id.0).expect("unreachable") self.ctx.irs.get(id.0).expect("unreachable")
} else { } else {
self.irs self.irs
@@ -331,7 +334,11 @@ impl DowngradeContext for DowngradeCtx<'_> {
.expect("ExprId out of bounds") .expect("ExprId out of bounds")
.as_ref() .as_ref()
.expect("maybe_thunk called on an extracted expr") .expect("maybe_thunk called on an extracted expr")
}; }
}
fn maybe_thunk(&mut self, id: ExprId) -> ExprId {
let ir = self.get_ir(id);
match ir { match ir {
Ir::Builtin(_) Ir::Builtin(_)
| Ir::Builtins(_) | 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(); let local_id = id.0 - self.ctx.irs.len();
self.irs self.irs
.get_mut(local_id) .get_mut(local_id)
@@ -458,7 +465,7 @@ impl DowngradeContext for DowngradeCtx<'_> {
.expect("extract_expr called on an already extracted expr") .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 local_id = id.0 - self.ctx.irs.len();
let _ = self let _ = self
.irs .irs

View File

@@ -35,11 +35,7 @@ impl TryFrom<&str> for Source {
impl From<Source> for NamedSource<Arc<str>> { impl From<Source> for NamedSource<Arc<str>> {
fn from(value: Source) -> Self { fn from(value: Source) -> Self {
let name = match value.ty { let name = value.get_name();
SourceType::Eval(_) => "«eval»".into(),
SourceType::Repl(_) => "«repl»".into(),
SourceType::File(path) => path.as_os_str().to_string_lossy().to_string(),
};
NamedSource::new(name, value.src.clone()) NamedSource::new(name, value.src.clone())
} }
} }
@@ -75,6 +71,14 @@ impl Source {
.expect("source file must have a parent dir"), .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)] #[derive(Error, Debug, Diagnostic)]

View File

@@ -28,8 +28,9 @@ pub trait DowngradeContext {
fn get_sym(&self, id: SymId) -> &str; fn get_sym(&self, id: SymId) -> &str;
fn lookup(&mut self, sym: SymId, span: TextRange) -> Result<ExprId>; fn lookup(&mut self, sym: SymId, span: TextRange) -> Result<ExprId>;
fn extract_expr(&mut self, id: ExprId) -> Ir; fn get_ir(&self, id: ExprId) -> &Ir;
fn replace_expr(&mut self, id: ExprId, expr: 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<Item = ExprId> + Clone + use<Self>; fn reserve_slots(&mut self, slots: usize) -> impl Iterator<Item = ExprId> + Clone + use<Self>;
fn get_current_source(&self) -> Source; fn get_current_source(&self) -> Source;
@@ -124,7 +125,7 @@ impl AttrSet {
// If the next attribute is a static string. // If the next attribute is a static string.
if let Some(&id) = self.stcs.get(&ident) { if let Some(&id) = self.stcs.get(&ident) {
// If a sub-attrset already exists, recurse into it. // 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 let result = ir
.as_mut() .as_mut()
.try_unwrap_attr_set() .try_unwrap_attr_set()
@@ -139,7 +140,7 @@ impl AttrSet {
) )
}) })
.and_then(|attrs| attrs._insert(path, name, value, ctx)); .and_then(|attrs| attrs._insert(path, name, value, ctx));
ctx.replace_expr(id, ir); ctx.replace_ir(id, ir);
result?; result?;
} else { } else {
// Create a new sub-attrset because this path doesn't exist yet. // Create a new sub-attrset because this path doesn't exist yet.

View File

@@ -405,21 +405,17 @@ where
for (sym, slot) in binding_keys.iter().copied().zip(slots.iter()) { for (sym, slot) in binding_keys.iter().copied().zip(slots.iter()) {
if let Some(&expr) = bindings.get(&sym) { if let Some(&expr) = bindings.get(&sym) {
ctx.replace_expr( ctx.replace_ir(
*slot, *slot,
Thunk { Thunk {
inner: expr, inner: expr,
// span: ctx.get_span(expr), span: ctx.get_ir(expr).span(),
// FIXME: span
span: synthetic_span(),
} }
.to_ir(), .to_ir(),
); );
} else { } else {
return Err(Error::downgrade_error( return Err(Error::internal(
format!("binding '{}' not found", format_symbol(ctx.get_sym(sym))), format!("binding '{}' not found", format_symbol(ctx.get_sym(sym))),
ctx.get_current_source(),
synthetic_span(),
)); ));
} }
} }