rib/type_inference/
errors.rs

1// Copyright 2024-2025 Golem Cloud
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::type_inference::kind::{GetTypeKind, TypeKind};
16use crate::{Expr, InferredType, Path, PathElem};
17use golem_wasm_ast::analysis::AnalysedType;
18use std::fmt;
19use std::fmt::Display;
20
21#[derive(Debug, Clone)]
22pub struct AmbiguousTypeError {
23    pub expr: Expr,
24    pub ambiguous_types: Vec<TypeKind>, // At this point, the max resolution is only until a kind
25    pub additional_error_details: Vec<String>,
26}
27
28impl AmbiguousTypeError {
29    pub fn new(
30        inferred_expr: &InferredType,
31        expr: &Expr,
32        expected: &TypeKind,
33    ) -> AmbiguousTypeError {
34        let actual_kind = inferred_expr.get_type_kind();
35        match actual_kind {
36            TypeKind::Ambiguous { possibilities } => {
37                let possibilities = possibilities.into_iter().collect::<Vec<_>>();
38
39                AmbiguousTypeError {
40                    expr: expr.clone(),
41                    ambiguous_types: possibilities,
42                    additional_error_details: vec![],
43                }
44            }
45            actual_kind => AmbiguousTypeError {
46                expr: expr.clone(),
47                ambiguous_types: vec![expected.clone(), actual_kind],
48                additional_error_details: vec![],
49            },
50        }
51    }
52
53    pub fn with_additional_error_detail(&self, detail: &str) -> AmbiguousTypeError {
54        let mut error = self.clone();
55        error.additional_error_details.push(detail.to_string());
56        error
57    }
58}
59
60pub enum InvalidPatternMatchError {
61    ConstructorMismatch {
62        predicate_expr: Expr,
63        match_expr: Expr,
64        constructor_name: String,
65    },
66    ArgSizeMismatch {
67        predicate_expr: Expr,
68        match_expr: Expr,
69        constructor_name: String,
70        expected_arg_size: usize,
71        actual_arg_size: usize,
72    },
73}
74
75impl InvalidPatternMatchError {
76    pub fn constructor_type_mismatch(
77        predicate_expr: &Expr,
78        match_expr: &Expr,
79        constructor_name: &str,
80    ) -> InvalidPatternMatchError {
81        InvalidPatternMatchError::ConstructorMismatch {
82            predicate_expr: predicate_expr.clone(),
83            match_expr: match_expr.clone(),
84            constructor_name: constructor_name.to_string(),
85        }
86    }
87
88    pub fn arg_size_mismatch(
89        predicate_expr: &Expr,
90        match_expr: &Expr,
91        constructor_name: &str,
92        expected_arg_size: usize,
93        actual_arg_size: usize,
94    ) -> InvalidPatternMatchError {
95        InvalidPatternMatchError::ArgSizeMismatch {
96            predicate_expr: predicate_expr.clone(),
97            match_expr: match_expr.clone(),
98            expected_arg_size,
99            actual_arg_size,
100            constructor_name: constructor_name.to_string(),
101        }
102    }
103}
104
105#[derive(Clone, Debug)]
106pub struct TypeMismatchError {
107    pub expr_with_wrong_type: Expr,
108    pub parent_expr: Option<Expr>,
109    pub expected_type: ExpectedType,
110    pub actual_type: ActualType,
111    pub field_path: Path,
112    pub additional_error_detail: Vec<String>,
113}
114
115#[derive(Clone, Debug)]
116pub enum ExpectedType {
117    AnalysedType(AnalysedType),
118    Kind(TypeKind),
119}
120
121// If the actual type is not fully known but only a hint through TypeKind
122#[derive(Clone, Debug)]
123pub enum ActualType {
124    Inferred(InferredType),
125    Kind(TypeKind),
126}
127
128impl TypeMismatchError {
129    pub fn updated_expected_type(&self, expected_type: &AnalysedType) -> TypeMismatchError {
130        let mut mismatch_error: TypeMismatchError = self.clone();
131        mismatch_error.expected_type = ExpectedType::AnalysedType(expected_type.clone());
132        mismatch_error
133    }
134
135    pub fn at_field(&self, field_name: String) -> TypeMismatchError {
136        let mut mismatch_error: TypeMismatchError = self.clone();
137        mismatch_error
138            .field_path
139            .push_front(PathElem::Field(field_name));
140        mismatch_error
141    }
142
143    pub fn with_actual_inferred_type(
144        expr: &Expr,
145        parent_expr: Option<&Expr>,
146        expected_type: AnalysedType,
147        actual_type: InferredType,
148    ) -> Self {
149        TypeMismatchError {
150            expr_with_wrong_type: expr.clone(),
151            parent_expr: parent_expr.cloned(),
152            expected_type: ExpectedType::AnalysedType(expected_type),
153            actual_type: ActualType::Inferred(actual_type),
154            field_path: Path::default(),
155            additional_error_detail: Vec::new(),
156        }
157    }
158
159    pub fn with_actual_type_kind(
160        expr: &Expr,
161        parent_expr: Option<&Expr>,
162        expected_type: AnalysedType,
163        actual_type: &TypeKind,
164    ) -> Self {
165        TypeMismatchError {
166            expr_with_wrong_type: expr.clone(),
167            parent_expr: parent_expr.cloned(),
168            expected_type: ExpectedType::AnalysedType(expected_type),
169            actual_type: ActualType::Kind(actual_type.clone()),
170            field_path: Path::default(),
171            additional_error_detail: Vec::new(),
172        }
173    }
174}
175
176pub struct MultipleUnResolvedTypesError(pub Vec<UnResolvedTypesError>);
177
178#[derive(Clone)]
179pub struct UnResolvedTypesError {
180    pub unresolved_expr: Expr,
181    pub parent_expr: Option<Expr>,
182    pub additional_messages: Vec<String>,
183    pub help_messages: Vec<String>,
184    pub path: Path,
185}
186
187impl UnResolvedTypesError {
188    pub fn from(expr: &Expr, parent_expr: Option<Expr>) -> Self {
189        let unresolved_types = UnResolvedTypesError {
190            unresolved_expr: expr.clone(),
191            additional_messages: Vec::new(),
192            parent_expr: parent_expr.clone(),
193            help_messages: Vec::new(),
194            path: Path::default(),
195        };
196
197        unresolved_types.with_default_help_messages()
198    }
199
200    pub fn with_default_help_messages(&self) -> Self {
201        self.with_help_message(
202            "consider specifying the type explicitly. Examples: `1: u64`, `person.age: u8`",
203        )
204        .with_help_message(
205            "or specify the type in let binding. Example: let numbers: list<u8> = [1, 2, 3]",
206        )
207    }
208
209    pub fn with_parent_expr(&self, expr: &Expr) -> UnResolvedTypesError {
210        let mut unresolved_error: UnResolvedTypesError = self.clone();
211        unresolved_error.parent_expr = Some(expr.clone());
212        unresolved_error
213    }
214
215    pub fn with_additional_error_detail(&self, message: impl AsRef<str>) -> UnResolvedTypesError {
216        let mut unresolved_error: UnResolvedTypesError = self.clone();
217        unresolved_error
218            .additional_messages
219            .push(message.as_ref().to_string());
220        unresolved_error
221    }
222
223    pub fn with_help_message(&self, message: impl AsRef<str>) -> UnResolvedTypesError {
224        let mut unresolved_error: UnResolvedTypesError = self.clone();
225        unresolved_error
226            .help_messages
227            .push(message.as_ref().to_string());
228
229        unresolved_error
230    }
231
232    pub fn at_field(&self, field_name: String) -> UnResolvedTypesError {
233        let mut unresolved_error: UnResolvedTypesError = self.clone();
234        unresolved_error
235            .path
236            .push_front(PathElem::Field(field_name));
237        unresolved_error
238    }
239
240    pub fn at_index(&self, index: usize) -> UnResolvedTypesError {
241        let mut unresolved_error: UnResolvedTypesError = self.clone();
242        unresolved_error.path.push_front(PathElem::Index(index));
243        unresolved_error
244    }
245}
246
247impl Display for UnResolvedTypesError {
248    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
249        let span = self.unresolved_expr.source_span();
250
251        writeln!(
252            f,
253            "cannot determine the type of the following rib expression found at line {}, column {}",
254            span.start_line(),
255            span.start_column()
256        )?;
257
258        writeln!(f, "`{}`", self.unresolved_expr)?;
259
260        if let Some(parent) = &self.parent_expr {
261            writeln!(f, "found within:")?;
262            writeln!(f, "`{}`", parent)?;
263        }
264
265        if !self.additional_messages.is_empty() {
266            for message in &self.additional_messages {
267                writeln!(f, "{}", message)?;
268            }
269        }
270
271        Ok(())
272    }
273}
274
275pub enum FunctionCallError {
276    InvalidFunctionCall {
277        function_name: String,
278        expr: Expr,
279        message: String,
280    },
281    TypeMisMatch {
282        function_name: String,
283        argument: Expr,
284        error: TypeMismatchError,
285    },
286    MissingRecordFields {
287        function_name: String,
288        argument: Expr,
289        missing_fields: Vec<Path>,
290    },
291    UnResolvedTypes {
292        function_name: String,
293        argument: Expr,
294        unresolved_error: UnResolvedTypesError,
295        expected_type: AnalysedType,
296    },
297
298    InvalidResourceMethodCall {
299        resource_method_name: String,
300        invalid_lhs: Expr,
301    },
302
303    InvalidGenericTypeParameter {
304        generic_type_parameter: String,
305        expr: Expr,
306        message: String,
307    },
308
309    ArgumentSizeMisMatch {
310        function_name: String,
311        expr: Expr,
312        expected: usize,
313        provided: usize,
314    },
315}
316
317pub struct InvalidWorkerName {
318    pub worker_name_expr: Expr,
319    pub message: String,
320}
321
322#[derive(Clone)]
323pub struct CustomError {
324    pub expr: Expr,
325    pub message: String,
326    pub help_message: Vec<String>,
327}
328
329impl CustomError {
330    pub fn new(expr: &Expr, message: impl AsRef<str>) -> CustomError {
331        CustomError {
332            expr: expr.clone(),
333            message: message.as_ref().to_string(),
334            help_message: Vec::new(),
335        }
336    }
337
338    pub fn with_help_message(&self, message: impl AsRef<str>) -> CustomError {
339        let mut custom_error: CustomError = self.clone();
340        custom_error.help_message.push(message.as_ref().to_string());
341        custom_error
342    }
343}