diff --git a/crates/typst/src/eval/call.rs b/crates/typst/src/eval/call.rs index 9e4a128f9..a4b057773 100644 --- a/crates/typst/src/eval/call.rs +++ b/crates/typst/src/eval/call.rs @@ -1,5 +1,5 @@ use comemo::{Prehashed, Tracked, TrackedMut}; -use ecow::EcoVec; +use ecow::{eco_format, EcoVec}; use crate::diag::{bail, error, At, HintedStrResult, SourceResult, Trace, Tracepoint}; use crate::engine::Engine; @@ -99,13 +99,27 @@ impl Eval for ast::FuncCall<'_> { field.as_str() ); - if let Value::Dict(dict) = target { - if matches!(dict.get(&field), Ok(Value::Func(_))) { - error.hint( - "to call the function stored in the dictionary, \ - surround the field access with parentheses", - ); + let mut field_hint = || { + if target.field(&field).is_ok() { + error.hint(eco_format!( + "did you mean to access the field `{}`?", + field.as_str() + )); } + }; + + match target { + Value::Dict(ref dict) => { + if matches!(dict.get(&field), Ok(Value::Func(_))) { + error.hint( + "to call the function stored in the dictionary, \ + surround the field access with parentheses", + ); + } else { + field_hint(); + } + } + _ => field_hint(), } bail!(error); diff --git a/tests/typ/compiler/dict.typ b/tests/typ/compiler/dict.typ index 138aa7d42..e66d8099e 100644 --- a/tests/typ/compiler/dict.typ +++ b/tests/typ/compiler/dict.typ @@ -119,6 +119,7 @@ ) // Error: 8-15 type dictionary has no method `nonfunc` + // Hint: 8-15 did you mean to access the field `nonfunc`? dict.nonfunc() } diff --git a/tests/typ/compiler/methods.typ b/tests/typ/compiler/methods.typ index 692f9ab36..f3ec44347 100644 --- a/tests/typ/compiler/methods.typ +++ b/tests/typ/compiler/methods.typ @@ -35,6 +35,12 @@ #let numbers = () #numbers.fun() +--- +// Error: 2:4-2:10 type content has no method `stroke` +// Hint: 2:4-2:10 did you mean to access the field `stroke`? +#let l = line(stroke: red) +#l.stroke() + --- // Error: 2:2-2:43 cannot mutate a temporary value #let numbers = (1, 2, 3)