solscript_typeck/
error.rs

1//! Type checking error types
2
3use miette::{Diagnostic, SourceSpan};
4use thiserror::Error;
5
6use crate::types::Type;
7
8/// A type checking error
9#[derive(Error, Debug, Diagnostic)]
10pub enum TypeError {
11    #[error("Type mismatch: expected `{expected}`, found `{found}`")]
12    #[diagnostic(
13        code(solscript::typeck::mismatch),
14        help("ensure the value type matches the expected type")
15    )]
16    TypeMismatch {
17        expected: String,
18        found: String,
19        #[label("expected `{expected}`, found `{found}`")]
20        span: SourceSpan,
21        #[source_code]
22        src: String,
23    },
24
25    #[error("Undefined variable: `{name}`")]
26    #[diagnostic(
27        code(solscript::typeck::undefined_var),
28        help("check spelling, or declare the variable before use")
29    )]
30    UndefinedVariable {
31        name: String,
32        #[label("not found in this scope")]
33        span: SourceSpan,
34        #[source_code]
35        src: String,
36    },
37
38    #[error("Undefined type: `{name}`")]
39    #[diagnostic(
40        code(solscript::typeck::undefined_type),
41        help("check spelling, or define the type (struct/enum/contract)")
42    )]
43    UndefinedType {
44        name: String,
45        #[label("unknown type")]
46        span: SourceSpan,
47        #[source_code]
48        src: String,
49    },
50
51    #[error("Undefined function: `{name}`")]
52    #[diagnostic(
53        code(solscript::typeck::undefined_fn),
54        help("check spelling, or define the function")
55    )]
56    UndefinedFunction {
57        name: String,
58        #[label("not found")]
59        span: SourceSpan,
60        #[source_code]
61        src: String,
62    },
63
64    #[error("Undefined field: `{field}` on type `{ty}`")]
65    #[diagnostic(
66        code(solscript::typeck::undefined_field),
67        help("check the struct definition for available fields")
68    )]
69    UndefinedField {
70        field: String,
71        ty: String,
72        #[label("no field `{field}` on type `{ty}`")]
73        span: SourceSpan,
74        #[source_code]
75        src: String,
76    },
77
78    #[error("Undefined method: `{method}` on type `{ty}`")]
79    #[diagnostic(
80        code(solscript::typeck::undefined_method),
81        help("check available methods for this type")
82    )]
83    UndefinedMethod {
84        method: String,
85        ty: String,
86        #[label("no method `{method}` on type `{ty}`")]
87        span: SourceSpan,
88        #[source_code]
89        src: String,
90    },
91
92    #[error("Cannot call non-function type `{ty}`")]
93    #[diagnostic(
94        code(solscript::typeck::not_callable),
95        help("only functions and interface methods can be called")
96    )]
97    NotCallable {
98        ty: String,
99        #[label("this is not a function")]
100        span: SourceSpan,
101        #[source_code]
102        src: String,
103    },
104
105    #[error("Wrong number of arguments: expected {expected}, found {found}")]
106    #[diagnostic(
107        code(solscript::typeck::wrong_arg_count),
108        help("check the function signature for required parameters")
109    )]
110    WrongArgCount {
111        expected: usize,
112        found: usize,
113        #[label("expected {expected} argument(s), found {found}")]
114        span: SourceSpan,
115        #[source_code]
116        src: String,
117    },
118
119    #[error("Cannot index type `{ty}`")]
120    #[diagnostic(
121        code(solscript::typeck::not_indexable),
122        help("only arrays, mappings, and dynamic arrays can be indexed")
123    )]
124    NotIndexable {
125        ty: String,
126        #[label("cannot use [] on this type")]
127        span: SourceSpan,
128        #[source_code]
129        src: String,
130    },
131
132    #[error("Cannot apply operator `{op}` to type `{ty}`")]
133    #[diagnostic(
134        code(solscript::typeck::invalid_unary_op),
135        help("check that the operator is valid for this type")
136    )]
137    InvalidUnaryOp {
138        op: String,
139        ty: String,
140        #[label("operator `{op}` cannot be applied to `{ty}`")]
141        span: SourceSpan,
142        #[source_code]
143        src: String,
144    },
145
146    #[error("Cannot apply operator `{op}` to types `{left}` and `{right}`")]
147    #[diagnostic(
148        code(solscript::typeck::invalid_binary_op),
149        help("ensure both operands have compatible types")
150    )]
151    InvalidBinaryOp {
152        op: String,
153        left: String,
154        right: String,
155        #[label("cannot apply `{op}` to `{left}` and `{right}`")]
156        span: SourceSpan,
157        #[source_code]
158        src: String,
159    },
160
161    #[error("Duplicate definition: `{name}`")]
162    #[diagnostic(
163        code(solscript::typeck::duplicate),
164        help("rename one of the definitions to avoid conflict")
165    )]
166    DuplicateDefinition {
167        name: String,
168        #[label("`{name}` is already defined")]
169        span: SourceSpan,
170        #[source_code]
171        src: String,
172    },
173
174    #[error("Missing return value")]
175    #[diagnostic(
176        code(solscript::typeck::missing_return),
177        help("add a return statement with the expected type")
178    )]
179    MissingReturn {
180        expected: String,
181        #[label("function expects to return `{expected}`")]
182        span: SourceSpan,
183        #[source_code]
184        src: String,
185    },
186
187    #[error("Undefined event: `{name}`")]
188    #[diagnostic(
189        code(solscript::typeck::undefined_event),
190        help("define the event before using it: event {name}(...);")
191    )]
192    UndefinedEvent {
193        name: String,
194        #[label("event `{name}` is not defined")]
195        span: SourceSpan,
196        #[source_code]
197        src: String,
198    },
199
200    #[error("Undefined modifier: `{name}`")]
201    #[diagnostic(
202        code(solscript::typeck::undefined_modifier),
203        help("define the modifier before using it")
204    )]
205    UndefinedModifier {
206        name: String,
207        #[label("modifier `{name}` is not defined")]
208        span: SourceSpan,
209        #[source_code]
210        src: String,
211    },
212
213    #[error("Undefined error: `{name}`")]
214    #[diagnostic(
215        code(solscript::typeck::undefined_error),
216        help("define the error before using it: error {name}(...);")
217    )]
218    UndefinedError {
219        name: String,
220        #[label("error `{name}` is not defined")]
221        span: SourceSpan,
222        #[source_code]
223        src: String,
224    },
225}
226
227impl TypeError {
228    pub fn type_mismatch(expected: &Type, found: &Type, span: (usize, usize), src: &str) -> Self {
229        Self::TypeMismatch {
230            expected: expected.to_string(),
231            found: found.to_string(),
232            span: SourceSpan::new(span.0.into(), span.1 - span.0),
233            src: src.to_string(),
234        }
235    }
236
237    pub fn undefined_variable(name: &str, span: (usize, usize), src: &str) -> Self {
238        Self::UndefinedVariable {
239            name: name.to_string(),
240            span: SourceSpan::new(span.0.into(), span.1 - span.0),
241            src: src.to_string(),
242        }
243    }
244
245    pub fn undefined_type(name: &str, span: (usize, usize), src: &str) -> Self {
246        Self::UndefinedType {
247            name: name.to_string(),
248            span: SourceSpan::new(span.0.into(), span.1 - span.0),
249            src: src.to_string(),
250        }
251    }
252
253    pub fn undefined_field(field: &str, ty: &Type, span: (usize, usize), src: &str) -> Self {
254        Self::UndefinedField {
255            field: field.to_string(),
256            ty: ty.to_string(),
257            span: SourceSpan::new(span.0.into(), span.1 - span.0),
258            src: src.to_string(),
259        }
260    }
261
262    pub fn undefined_method(method: &str, ty: &Type, span: (usize, usize), src: &str) -> Self {
263        Self::UndefinedMethod {
264            method: method.to_string(),
265            ty: ty.to_string(),
266            span: SourceSpan::new(span.0.into(), span.1 - span.0),
267            src: src.to_string(),
268        }
269    }
270
271    pub fn not_callable(ty: &Type, span: (usize, usize), src: &str) -> Self {
272        Self::NotCallable {
273            ty: ty.to_string(),
274            span: SourceSpan::new(span.0.into(), span.1 - span.0),
275            src: src.to_string(),
276        }
277    }
278
279    pub fn wrong_arg_count(expected: usize, found: usize, span: (usize, usize), src: &str) -> Self {
280        Self::WrongArgCount {
281            expected,
282            found,
283            span: SourceSpan::new(span.0.into(), span.1 - span.0),
284            src: src.to_string(),
285        }
286    }
287
288    pub fn invalid_binary_op(
289        op: &str,
290        left: &Type,
291        right: &Type,
292        span: (usize, usize),
293        src: &str,
294    ) -> Self {
295        Self::InvalidBinaryOp {
296            op: op.to_string(),
297            left: left.to_string(),
298            right: right.to_string(),
299            span: SourceSpan::new(span.0.into(), span.1 - span.0),
300            src: src.to_string(),
301        }
302    }
303}