Fix IR for try (#13811)

# Description
Fixes a bug in the IR for `try` to match that of the regular evaluator
(continuing from #13515):
```nushell
# without IR:
try { ^false } catch { 'caught' } # == 'caught'

# with IR:
try { ^false } catch { 'caught' } # error, non-zero exit code
```

In this PR, both now evaluate to `caught`. For the implementation, I had
to add another instruction, and feel free to suggest better
alternatives. In the future, it might be possible to get rid of this
extra instruction.

# User-Facing Changes
Bug fix, `try { ^false } catch { 'caught' }` now works in IR.
This commit is contained in:
Ian Manske
2024-09-09 19:44:04 -07:00
committed by GitHub
parent 6600b3edfb
commit 493850b1bf
7 changed files with 36 additions and 5 deletions

View File

@ -202,6 +202,7 @@ impl BlockBuilder {
Instruction::Span { src_dst } => allocate(&[*src_dst], &[*src_dst]),
Instruction::Drop { src } => allocate(&[*src], &[]),
Instruction::Drain { src } => allocate(&[*src], &[]),
Instruction::WriteToOutDests { src } => allocate(&[*src], &[]),
Instruction::LoadVariable { dst, var_id: _ } => allocate(&[], &[*dst]),
Instruction::StoreVariable { var_id: _, src } => allocate(&[*src], &[]),
Instruction::DropVariable { var_id: _ } => Ok(()),

View File

@ -362,6 +362,7 @@ pub(crate) fn compile_try(
//
// on-error-into ERR, %io_reg // or without
// %io_reg <- <...block...> <- %io_reg
// write-to-out-dests %io_reg
// pop-error-handler
// jump END
// ERR: clone %err_reg, %io_reg
@ -374,6 +375,7 @@ pub(crate) fn compile_try(
// %closure_reg <- <catch_expr>
// on-error-into ERR, %io_reg
// %io_reg <- <...block...> <- %io_reg
// write-to-out-dests %io_reg
// pop-error-handler
// jump END
// ERR: clone %err_reg, %io_reg
@ -461,7 +463,17 @@ pub(crate) fn compile_try(
io_reg,
)?;
// Successful case: pop the error handler
// Successful case:
// - write to the current output destinations
// - pop the error handler
if let Some(mode) = redirect_modes.out {
builder.push(mode.map(|mode| Instruction::RedirectOut { mode }))?;
}
if let Some(mode) = redirect_modes.err {
builder.push(mode.map(|mode| Instruction::RedirectErr { mode }))?;
}
builder.push(Instruction::WriteToOutDests { src: io_reg }.into_spanned(call.head))?;
builder.push(Instruction::PopErrorHandler.into_spanned(call.head))?;
// Jump over the failure case

View File

@ -317,6 +317,17 @@ fn eval_instruction<D: DebugContext>(
let data = ctx.take_reg(*src);
drain(ctx, data)
}
Instruction::WriteToOutDests { src } => {
let data = ctx.take_reg(*src);
let res = {
let stack = &mut ctx
.stack
.push_redirection(ctx.redirect_out.clone(), ctx.redirect_err.clone());
data.write_to_out_dests(ctx.engine_state, stack)?
};
ctx.put_reg(*src, res);
Ok(Continue)
}
Instruction::LoadVariable { dst, var_id } => {
let value = get_var(ctx, *var_id, *span)?;
ctx.put_reg(*dst, value.into_pipeline_data());