Skip to main content

sim_shape/
diagnostics.rs

1//! Diagnostic constructors shared by shape implementations.
2
3use sim_kernel::{Diagnostic, Expr, HintMetadata, Symbol};
4
5/// Builds a diagnostic for an expected-shape mismatch.
6pub fn expected_shape_diagnostic(
7    expected: impl Into<String>,
8    actual: impl Into<String>,
9) -> Diagnostic {
10    let expected = expected.into();
11    let actual = actual.into();
12    let message = format!("expected {expected}, found {actual}");
13    let hint = HintMetadata::new(
14        Symbol::qualified("shape-hint", "expected"),
15        "shape mismatch",
16    )
17    .with_detail(message.clone())
18    .with_tag(Symbol::qualified("shape", "expected"))
19    .with_tag(Symbol::qualified("shape", "actual"))
20    .with_argument(Symbol::new("value"));
21    hint.attach_to(Diagnostic::error(message).with_code(Symbol::qualified("shape", "expected")))
22}
23
24/// Builds a diagnostic for a binding failure inside a capture or destructuring shape.
25pub fn binding_failure_diagnostic(
26    binding: &Symbol,
27    expected: impl Into<String>,
28    actual: impl Into<String>,
29) -> Diagnostic {
30    let expected = expected.into();
31    let actual = actual.into();
32    let message = format!("binding {binding} expected {expected}, found {actual}");
33    let hint = HintMetadata::new(
34        Symbol::qualified("shape-hint", "binding"),
35        "binding mismatch",
36    )
37    .with_detail(message.clone())
38    .with_tag(Symbol::qualified("shape", "binding"))
39    .with_argument(binding.clone());
40    hint.attach_to(Diagnostic::error(message).with_code(Symbol::qualified("shape", "binding")))
41}
42
43/// Builds a diagnostic for a callable shape argument mismatch.
44pub fn callable_mismatch_diagnostic(
45    callable: &Symbol,
46    expected: impl Into<String>,
47    actual: impl Into<String>,
48) -> Diagnostic {
49    let expected = expected.into();
50    let actual = actual.into();
51    let message = format!("callable {callable} expected {expected}, found {actual}");
52    let hint = HintMetadata::new(
53        Symbol::qualified("shape-hint", "callable-mismatch"),
54        "callable mismatch",
55    )
56    .with_detail(message.clone())
57    .with_tag(Symbol::qualified("shape", "callable"))
58    .with_argument(callable.clone());
59    hint.attach_to(
60        Diagnostic::error(message).with_code(Symbol::qualified("shape", "callable-mismatch")),
61    )
62}
63
64/// Builds a diagnostic for overload selection failures or ambiguity.
65pub fn overload_selection_diagnostic(function: &Symbol, reason: impl Into<String>) -> Diagnostic {
66    let reason = reason.into();
67    let message = format!("overload selection for {function}: {reason}");
68    let hint = HintMetadata::new(
69        Symbol::qualified("shape-hint", "overload-selection"),
70        "overload selection",
71    )
72    .with_detail(message.clone())
73    .with_tag(Symbol::qualified("shape", "overload"))
74    .with_argument(function.clone());
75    hint.attach_to(
76        Diagnostic::error(message).with_code(Symbol::qualified("shape", "overload-selection")),
77    )
78}
79
80/// Returns a compact label for the actual expression kind.
81pub(crate) fn expr_actual_label(expr: &Expr) -> String {
82    match expr {
83        Expr::Nil => "nil expression",
84        Expr::Bool(_) => "bool expression",
85        Expr::Number(_) => "number expression",
86        Expr::Symbol(_) | Expr::Local(_) => "symbol expression",
87        Expr::String(_) => "string expression",
88        Expr::Bytes(_) => "bytes expression",
89        Expr::List(_) => "list expression",
90        Expr::Vector(_) => "vector expression",
91        Expr::Map(_) => "map expression",
92        Expr::Set(_) => "set expression",
93        Expr::Call { .. } => "call expression",
94        Expr::Infix { .. } => "infix expression",
95        Expr::Prefix { .. } => "prefix expression",
96        Expr::Postfix { .. } => "postfix expression",
97        Expr::Block(_) => "block expression",
98        Expr::Quote { .. } => "quote expression",
99        Expr::Annotated { .. } => "annotated expression",
100        Expr::Extension { .. } => "extension expression",
101    }
102    .to_owned()
103}