fix: maybe_thunk

This commit is contained in:
2026-01-24 01:58:04 +08:00
parent 2f5f84c6c1
commit e58ebbe408
4 changed files with 40 additions and 56 deletions

View File

@@ -11,7 +11,7 @@ use crate::codegen::{CodegenContext, compile};
use crate::error::{Error, Result, Source}; use crate::error::{Error, Result, Source};
use crate::ir::{ use crate::ir::{
Arg, ArgId, Bool, Builtin, Downgrade as _, DowngradeContext, ExprId, ExprRef, Ir, Null, SymId, Arg, ArgId, Bool, Builtin, Downgrade as _, DowngradeContext, ExprId, ExprRef, Ir, Null, SymId,
ToIr as _, synthetic_span, Thunk, ToIr as _, synthetic_span,
}; };
use crate::runtime::{Runtime, RuntimeContext}; use crate::runtime::{Runtime, RuntimeContext};
use crate::store::{StoreBackend, StoreConfig}; use crate::store::{StoreBackend, StoreConfig};
@@ -351,6 +351,34 @@ 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 {
let ir = if id.0 < self.ctx.irs.len() {
self.ctx.irs.get(id.0).expect("unreachable")
} else {
self.irs
.get(id.0 - self.ctx.irs.len())
.expect("ExprId out of bounds")
.as_ref()
.expect("maybe_thunk called on an extracted expr")
};
match ir {
Ir::Builtin(_)
| Ir::Builtins(_)
| Ir::Int(_)
| Ir::Float(_)
| Ir::Bool(_)
| Ir::Null(_)
| Ir::Str(_) => id,
_ => self.new_expr(
Thunk {
inner: id,
span: ir.span(),
}
.to_ir(),
),
}
}
fn new_sym(&mut self, sym: String) -> SymId { fn new_sym(&mut self, sym: String) -> SymId {
self.ctx.symbols.get_or_intern(sym) self.ctx.symbols.get_or_intern(sym)
} }

View File

@@ -22,6 +22,7 @@ pub trait DowngradeContext {
fn new_expr(&mut self, expr: Ir) -> ExprId; fn new_expr(&mut self, expr: Ir) -> ExprId;
fn new_arg(&mut self, span: TextRange) -> ExprId; fn new_arg(&mut self, span: TextRange) -> ExprId;
fn maybe_thunk(&mut self, id: ExprId) -> ExprId;
fn new_sym(&mut self, sym: String) -> SymId; fn new_sym(&mut self, sym: String) -> SymId;
fn get_sym(&self, id: SymId) -> &str; fn get_sym(&self, id: SymId) -> &str;

View File

@@ -121,7 +121,8 @@ impl<Ctx: DowngradeContext> Downgrade<Ctx> for ast::Str {
.map(|part| match part { .map(|part| match part {
ast::InterpolPart::Literal(lit) => Ok(ctx.new_expr(Str { val: lit, span }.to_ir())), ast::InterpolPart::Literal(lit) => Ok(ctx.new_expr(Str { val: lit, span }.to_ir())),
ast::InterpolPart::Interpolation(interpol) => { ast::InterpolPart::Interpolation(interpol) => {
interpol.expr().unwrap().downgrade(ctx) let inner = interpol.expr().unwrap().downgrade(ctx)?;
Ok(ctx.new_expr(Thunk { inner, span }.to_ir()))
} }
}) })
.collect::<Result<Vec<_>>>()?; .collect::<Result<Vec<_>>>()?;
@@ -210,7 +211,10 @@ impl<Ctx: DowngradeContext> Downgrade<Ctx> for ast::List {
fn downgrade(self, ctx: &mut Ctx) -> Result<ExprId> { fn downgrade(self, ctx: &mut Ctx) -> Result<ExprId> {
let items = self let items = self
.items() .items()
.map(|item| maybe_thunk(item, ctx)) .map(|item| {
let id = item.downgrade(ctx)?;
Ok(ctx.maybe_thunk(id))
})
.collect::<Result<_>>()?; .collect::<Result<_>>()?;
let span = self.syntax().text_range(); let span = self.syntax().text_range();
Ok(ctx.new_expr(List { items, span }.to_ir())) Ok(ctx.new_expr(List { items, span }.to_ir()))
@@ -439,7 +443,8 @@ impl<Ctx: DowngradeContext> Downgrade<Ctx> for ast::Lambda {
impl<Ctx: DowngradeContext> Downgrade<Ctx> for ast::Apply { impl<Ctx: DowngradeContext> Downgrade<Ctx> for ast::Apply {
fn downgrade(self, ctx: &mut Ctx) -> Result<ExprId> { fn downgrade(self, ctx: &mut Ctx) -> Result<ExprId> {
let func = self.lambda().unwrap().downgrade(ctx)?; let func = self.lambda().unwrap().downgrade(ctx)?;
let arg = maybe_thunk(self.argument().unwrap(), ctx)?; let arg = self.argument().unwrap().downgrade(ctx)?;
let arg = ctx.maybe_thunk(arg);
let span = self.syntax().text_range(); let span = self.syntax().text_range();
Ok(ctx.new_expr(Call { func, arg, span }.to_ir())) Ok(ctx.new_expr(Call { func, arg, span }.to_ir()))
} }

View File

@@ -13,57 +13,6 @@ use crate::value::format_symbol;
use super::*; use super::*;
pub fn maybe_thunk(mut expr: ast::Expr, ctx: &mut impl DowngradeContext) -> Result<ExprId> {
use ast::Expr::*;
let expr = loop {
expr = match expr {
Paren(paren) => paren.expr().unwrap(),
Root(root) => root.expr().unwrap(),
expr => break expr,
}
};
match expr {
Error(error) => {
let span = error.syntax().text_range();
return Err(self::Error::downgrade_error(error.to_string())
.with_span(span)
.with_source(ctx.get_current_source()));
}
Ident(ident) => return ident.downgrade(ctx),
Literal(lit) => return lit.downgrade(ctx),
Str(str) => return str.downgrade(ctx),
Path(path) => return path.downgrade(ctx),
_ => (),
}
let id = match expr {
Apply(apply) => apply.downgrade(ctx),
Assert(assert) => assert.downgrade(ctx),
IfElse(ifelse) => ifelse.downgrade(ctx),
Select(select) => select.downgrade(ctx),
Lambda(lambda) => lambda.downgrade(ctx),
LegacyLet(let_) => let_.downgrade(ctx),
LetIn(letin) => letin.downgrade(ctx),
List(list) => list.downgrade(ctx),
BinOp(op) => op.downgrade(ctx),
AttrSet(attrs) => attrs.downgrade(ctx),
UnaryOp(op) => op.downgrade(ctx),
With(with) => with.downgrade(ctx),
HasAttr(has) => has.downgrade(ctx),
_ => unreachable!(),
}?;
Ok(ctx.new_expr(
Thunk {
inner: id,
// span: ctx.get_span(id),
// FIXME: span
span: synthetic_span(),
}
.to_ir(),
))
}
/// Downgrades the entries of an attribute set. /// Downgrades the entries of an attribute set.
/// This handles `inherit` and `attrpath = value;` entries. /// This handles `inherit` and `attrpath = value;` entries.
pub fn downgrade_attrs( pub fn downgrade_attrs(
@@ -231,7 +180,8 @@ pub fn downgrade_attrpathvalue(
ctx: &mut impl DowngradeContext, ctx: &mut impl DowngradeContext,
) -> Result<()> { ) -> Result<()> {
let path = downgrade_attrpath(value.attrpath().unwrap(), ctx)?; let path = downgrade_attrpath(value.attrpath().unwrap(), ctx)?;
let value = maybe_thunk(value.value().unwrap(), ctx)?; let value = value.value().unwrap().downgrade(ctx)?;
let value = ctx.maybe_thunk(value);
attrs.insert(path, value, ctx) attrs.insert(path, value, ctx)
} }