Call a value that holds a function
`(self.map)(o)` is how winnow's combinators invoke the closure they were built with, and rustnim accepted only a named function in call position. Nim calls a proc-typed value with the same syntax, so all this needed was the callee's type -- and a refusal that says what it found rather than what it wanted, for anything that is not one. tests/cases/061. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
64cb049 parent: 670d6a7 modified
src/lower.rs +19 -1 | @@ -6098,7 +6098,25 @@ impl Lowerer { | ||
| 6098 | 6098 | |
| 6099 | 6099 | fn call(&mut self, c: &syn::ExprCall, expect: Option<&Nim>) -> Result<Val, String> { |
| 6100 | 6100 | let Expr::Path(p) = &*c.func else { |
| 6101 | - return Err("only calls to named functions are supported".into()); | |
| 6101 | + // `(self.map)(o)` -- calling something that holds a proc. Nim | |
| 6102 | + // calls a proc-typed value with the same syntax, so this needs | |
| 6103 | + // only the callee's type to confirm that is what it is. | |
| 6104 | + let f = self.expr(&c.func)?; | |
| 6105 | + let Some(Nim::Proc(ptys, ret)) = f.ty.clone() else { | |
| 6106 | + return Err(format!( | |
| 6107 | + "`{}` is called here but is not a function; only a named \ | |
| 6108 | + function or a value of proc type can be", | |
| 6109 | + snippet("e::quote!(#{ &c.func }).to_string()), | |
| 6110 | + )); | |
| 6111 | + }; | |
| 6112 | + let mut codes = Vec::new(); | |
| 6113 | + for (i, a) in c.args.iter().enumerate() { | |
| 6114 | + codes.push(self.expr_at(a, ptys.get(i))?.code); | |
| 6115 | + } | |
| 6116 | + return Ok(Val::new( | |
| 6117 | + format!("{}({})", f.code, codes.join(", ")), | |
| 6118 | + Some((*ret).clone()), | |
| 6119 | + )); | |
| 6102 | 6120 | }; |
| 6103 | 6121 | let name = path_name(&p.path); |
| 6104 | 6122 | |
| @@ -6098,7 +6098,25 @@ impl Lowerer { | |||
| 6098 | 6098 | ||
| 6099 | fn call(&mut self, c: &syn::ExprCall, expect: Option<&Nim>) -> Result<Val, String> { | 6099 | fn call(&mut self, c: &syn::ExprCall, expect: Option<&Nim>) -> Result<Val, String> { |
| 6100 | let Expr::Path(p) = &*c.func else { | 6100 | let Expr::Path(p) = &*c.func else { |
| 6101 | - return Err("only calls to named functions are supported".into()); | 6101 | + // `(self.map)(o)` -- calling something that holds a proc. Nim |
| 6102 | + // calls a proc-typed value with the same syntax, so this needs | ||
| 6103 | + // only the callee's type to confirm that is what it is. | ||
| 6104 | + let f = self.expr(&c.func)?; | ||
| 6105 | + let Some(Nim::Proc(ptys, ret)) = f.ty.clone() else { | ||
| 6106 | + return Err(format!( | ||
| 6107 | + "`{}` is called here but is not a function; only a named \ | ||
| 6108 | + function or a value of proc type can be", | ||
| 6109 | + snippet("e::quote!(#{ &c.func }).to_string()), | ||
| 6110 | + )); | ||
| 6111 | + }; | ||
| 6112 | + let mut codes = Vec::new(); | ||
| 6113 | + for (i, a) in c.args.iter().enumerate() { | ||
| 6114 | + codes.push(self.expr_at(a, ptys.get(i))?.code); | ||
| 6115 | + } | ||
| 6116 | + return Ok(Val::new( | ||
| 6117 | + format!("{}({})", f.code, codes.join(", ")), | ||
| 6118 | + Some((*ret).clone()), | ||
| 6119 | + )); | ||
| 6102 | }; | 6120 | }; |
| 6103 | let name = path_name(&p.path); | 6121 | let name = path_name(&p.path); |
| 6104 | 6122 | ||
added
tests/cases/061-call-proc-value.rs +27 -0 | new file mode 100644 | ||
| @@ -0,0 +1,27 @@ | ||
| 1 | +// Calling something that holds a function rather than a named function. Nim | |
| 2 | +// calls a proc-typed value with the same syntax, so what this needs is the | |
| 3 | +// callee's type. | |
| 4 | +struct Mapper { | |
| 5 | + f: fn(u32) -> u32, | |
| 6 | +} | |
| 7 | + | |
| 8 | +fn double(x: u32) -> u32 { | |
| 9 | + x * 2 | |
| 10 | +} | |
| 11 | + | |
| 12 | +fn plus3(x: u32) -> u32 { | |
| 13 | + x + 3 | |
| 14 | +} | |
| 15 | + | |
| 16 | +fn apply(m: &Mapper, v: u32) -> u32 { | |
| 17 | + (m.f)(v) | |
| 18 | +} | |
| 19 | + | |
| 20 | +fn main() { | |
| 21 | + let a = Mapper { f: double }; | |
| 22 | + let b = Mapper { f: plus3 }; | |
| 23 | + println!("{} {}", apply(&a, 10), apply(&b, 10)); | |
| 24 | + | |
| 25 | + let g: fn(u32) -> u32 = double; | |
| 26 | + println!("{}", (g)(21)); | |
| 27 | +} | |
| new file mode 100644 | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | +// Calling something that holds a function rather than a named function. Nim | ||
| 2 | +// calls a proc-typed value with the same syntax, so what this needs is the | ||
| 3 | +// callee's type. | ||
| 4 | +struct Mapper { | ||
| 5 | + f: fn(u32) -> u32, | ||
| 6 | +} | ||
| 7 | + | ||
| 8 | +fn double(x: u32) -> u32 { | ||
| 9 | + x * 2 | ||
| 10 | +} | ||
| 11 | + | ||
| 12 | +fn plus3(x: u32) -> u32 { | ||
| 13 | + x + 3 | ||
| 14 | +} | ||
| 15 | + | ||
| 16 | +fn apply(m: &Mapper, v: u32) -> u32 { | ||
| 17 | + (m.f)(v) | ||
| 18 | +} | ||
| 19 | + | ||
| 20 | +fn main() { | ||
| 21 | + let a = Mapper { f: double }; | ||
| 22 | + let b = Mapper { f: plus3 }; | ||
| 23 | + println!("{} {}", apply(&a, 10), apply(&b, 10)); | ||
| 24 | + | ||
| 25 | + let g: fn(u32) -> u32 = double; | ||
| 26 | + println!("{}", (g)(21)); | ||
| 27 | +} | ||