Repository: typst/typst
File: crates/typst/src/foundations/cast.rs (Rust)

Code before:
            CastInfo::Union(_) => {}
        });

        let mut msg = String::from("expected ");
        if parts.is_empty() {
            msg.push_str(" nothing");
        }

        msg.push_str(&repr::separated_list(&parts, "or"));

        if !matching_type {
            msg.push_str(", found ");
            write!(msg, "{}", found.ty()).unwrap();
        }

        let mut msg = HintedString::new(msg.into());

        if let Value::Int(i) = found {
            if !matching_type && parts.iter().any(|p| p == "length") {
                msg.hint(eco_format!("a length needs a unit - did you mean {i}pt?"));
            }
        }
        if let Value::Str(s) = found {
            if !matching_type && parts.iter().any(|p| p == "label") {
                if is_valid_in_label_literal(s) {
                    msg.hint(eco_format!("use `<{s}>` to create a label or the label function to convert a string to a label"));
                } else {
                    msg.hint("use the label function to convert a string to a label");
                }
            }
        }

        msg
    }

    /// Walk all contained non-union infos.
    pub fn walk<F>(&self, mut f: F)
    where
        F: FnMut(&Self),
    {
        fn inner<F>(info: &CastInfo, f: &mut F)
        where
            F: FnMut(&CastInfo),
        {
            if let CastInfo::Union(infos) = info {
                for child in infos {
                    inner(child, f);
                }
            } else {
                f(info);
            }

Review comment (suggestion):
Maybe we can improve this message a bit? I would suggest "use `<{s}>` or `#label("{s}")` to create a label".

(I'm open to further suggestions)

Code after:

        let mut msg = String::from("expected ");
        if parts.is_empty() {
            msg.push_str(" nothing");
        }

        msg.push_str(&repr::separated_list(&parts, "or"));

        if !matching_type {
            msg.push_str(", found ");
            write!(msg, "{}", found.ty()).unwrap();
        }

        let mut msg: HintedString = msg.into();

        if let Value::Int(i) = found {
            if !matching_type && parts.iter().any(|p| p == "length") {
                msg.hint(eco_format!("a length needs a unit - did you mean {i}pt?"));
            }
        } else if let Value::Str(s) = found {
            if !matching_type && parts.iter().any(|p| p == "label") {
                if typst_syntax::is_valid_label_literal_id(s) {
                    msg.hint(eco_format!(
                        "use `<{s}>` or `label({})` to create a label",
                        s.repr()
                    ));
                } else {
                    msg.hint(eco_format!("use `label({})` to create a label", s.repr()));
                }
            }
        }

        msg
    }

    /// Walk all contained non-union infos.
    pub fn walk<F>(&self, mut f: F)
    where
        F: FnMut(&Self),
    {
        fn inner<F>(info: &CastInfo, f: &mut F)
        where
            F: FnMut(&CastInfo),
        {
            if let CastInfo::Union(infos) = info {
                for child in infos {
                    inner(child, f);
                }
            } else {
                f(info);
            }