Repository: typst/typst
File: crates/typst/src/eval/call.rs (Rust)

Code before:
                            field_hint();
                        }
                    }
                    _ => field_hint(),
                }

                bail!(error);
            }
        } else {
            (callee.eval(vm)?, args.eval(vm)?.spanned(span))
        };

        // If the callee is a callable symbol, call its handler.
        let callee = match callee {
            Value::Symbol(sym) => {
                if let Some(handler) = sym.func() {
                    Value::Func(handler)
                } else {
                    Value::Symbol(sym)
                }
            }
            callee => callee,
        };

        // For non-functions in math, we wrap the arguments in parentheses.
        if in_math && !matches!(callee, Value::Func(_)) {
            let mut body = Content::empty();
            for (i, arg) in args.all::<Content>()?.into_iter().enumerate() {
                if i > 0 {
                    body += TextElem::packed(',');
                }
                body += arg;
            }
            if trailing_comma {
                body += TextElem::packed(',');
            }
            return Ok(Value::Content(
                callee.display().spanned(callee_span)
                    + LrElem::new(TextElem::packed('(') + body + TextElem::packed(')'))
                        .pack(),
            ));
        }

        let callee = callee.cast::<Func>().at(callee_span)?;
        let point = || Tracepoint::Call(callee.name().map(Into::into));
        let f = || {
            callee
                .call(&mut vm.engine, vm.context, args)
                .trace(vm.world(), point, span)
        };


Review comment (suggestion):
We could try doing the `let callee = callee.cast::<Func>().at(callee_span);` above here, but not yet early return if it's `Err(_)`, instead first checking the non-function in math case.

Then, we could add `Symbol -> Func` to the cast implementation of `Func` in `foundations/value.rs` (like `Type` has). and get rid of the symbol special case above.

Not 100% whether it'll work, but worth a try.

Code after:
                            field_hint();
                        }
                    }
                    _ => field_hint(),
                }

                bail!(error);
            }
        } else {
            (callee.eval(vm)?, args.eval(vm)?.spanned(span))
        };

        let func_result = callee.clone().cast::<Func>().at(callee_span);
        if in_math && func_result.is_err() {
            // For non-functions in math, we wrap the arguments in parentheses.
            let mut body = Content::empty();
            for (i, arg) in args.all::<Content>()?.into_iter().enumerate() {
                if i > 0 {
                    body += TextElem::packed(',');
                }
                body += arg;
            }
            if trailing_comma {
                body += TextElem::packed(',');
            }
            return Ok(Value::Content(
                callee.display().spanned(callee_span)
                    + LrElem::new(TextElem::packed('(') + body + TextElem::packed(')'))
                        .pack(),
            ));
        }

        let func = func_result?;
        let point = || Tracepoint::Call(func.name().map(Into::into));
        let f = || {
            func.call(&mut vm.engine, vm.context, args)
                .trace(vm.world(), point, span)
        };

        // Stacker is broken on WASM.
        #[cfg(target_arch = "wasm32")]
        return f();

        #[cfg(not(target_arch = "wasm32"))]
        stacker::maybe_grow(32 * 1024, 2 * 1024 * 1024, f)
    }
}

impl Eval for ast::Args<'_> {
    type Output = Args;