diff options
author | Aspen Smith <root@gws.fyi> | 2024-02-01T21·48-0500 |
---|---|---|
committer | aspen <root@gws.fyi> | 2024-02-08T19·59+0000 |
commit | 780b47193a19ec34d467776b142d115bd0029dff (patch) | |
tree | a7dbbb2e43a113a7078dd8df7209037f87ad460c /tvix/eval/builtin-macros | |
parent | 4e040e8bc491bcee930ee7e59d6e68ef87c35bb6 (diff) |
refactor(tvix/eval): Generalize propagation of catchable values r/7482
Rather than explicitly checking for Value::Catchable in all builtins, make the #[builtin] proc macro insert this for all strict arguments by default, with support for a #[catch] attribute on the argument to disable this behavior. That attribute hasn't actually been *used* anywhere here, primarily because the tests pass without it, even for those builtins which weren't previously checking for Value::Catchable - if some time passes without this being used I might get rid of support for it entirely. There's also a `try_value` macro in builtins directly for the places where builtins were eg forcing something, then explicitly propagating a catchable value. Change-Id: Ie22037b9d3e305e3bdb682d105fe467bd90d53e9 Reviewed-on: https://cl.tvl.fyi/c/depot/+/10732 Tested-by: BuildkiteCI Reviewed-by: raitobezarius <tvl@lahfa.xyz>
Diffstat (limited to 'tvix/eval/builtin-macros')
-rw-r--r-- | tvix/eval/builtin-macros/src/lib.rs | 37 |
1 files changed, 31 insertions, 6 deletions
diff --git a/tvix/eval/builtin-macros/src/lib.rs b/tvix/eval/builtin-macros/src/lib.rs index de73b4576a0c..5cc9807f54fe 100644 --- a/tvix/eval/builtin-macros/src/lib.rs +++ b/tvix/eval/builtin-macros/src/lib.rs @@ -22,6 +22,10 @@ struct BuiltinArgument { /// function is called. strict: bool, + /// Propagate catchable values as values to the function, rather than short-circuit returning + /// them if encountered + catch: bool, + /// Span at which the argument was defined. span: Span, } @@ -205,6 +209,7 @@ pub fn builtins(args: TokenStream, item: TokenStream) -> TokenStream { .map(|arg| { let span = arg.span(); let mut strict = true; + let mut catch = false; let (name, ty) = match arg { FnArg::Receiver(_) => { return Err(quote_spanned!(span => { @@ -219,6 +224,9 @@ pub fn builtins(args: TokenStream, item: TokenStream) -> TokenStream { if id == "lazy" { strict = false; false + } else if id == "catch" { + catch = true; + false } else { true } @@ -233,8 +241,15 @@ pub fn builtins(args: TokenStream, item: TokenStream) -> TokenStream { } }; + if catch && !strict { + return Err(quote_spanned!(span => { + compile_error!("Cannot mix both lazy and catch on the same argument") + })); + } + Ok(BuiltinArgument { strict, + catch, span, name, ty, @@ -267,12 +282,22 @@ pub fn builtins(args: TokenStream, item: TokenStream) -> TokenStream { let ident = &arg.name; if arg.strict { - f.block = Box::new(parse_quote_spanned! {arg.span=> { - let #ident: #ty = tvix_eval::generators::request_force(&co, values.pop() - .expect("Tvix bug: builtin called with incorrect number of arguments")).await; - - #block - }}); + if arg.catch { + f.block = Box::new(parse_quote_spanned! {arg.span=> { + let #ident: #ty = tvix_eval::generators::request_force(&co, values.pop() + .expect("Tvix bug: builtin called with incorrect number of arguments")).await; + #block + }}); + } else { + f.block = Box::new(parse_quote_spanned! {arg.span=> { + let #ident: #ty = tvix_eval::generators::request_force(&co, values.pop() + .expect("Tvix bug: builtin called with incorrect number of arguments")).await; + if #ident.is_catchable() { + return Ok(#ident); + } + #block + }}); + } } else { f.block = Box::new(parse_quote_spanned! {arg.span=> { let #ident: #ty = values.pop() |