rib/type_inference/
errors.rs

1// Copyright 2024-2025 Golem Cloud
2//
3// Licensed under the Golem Source License v1.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://license.golem.cloud/LICENSE
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::rib_source_span::SourceSpan;
16use crate::type_inference::type_hint::{GetTypeHint, TypeHint};
17use crate::{InferredType, Path, PathElem};
18use golem_wasm_ast::analysis::AnalysedType;
19
20#[derive(Debug, Clone)]
21pub struct AmbiguousTypeError {
22    pub ambiguous_expr_source_span: SourceSpan,
23    pub ambiguous_types: Vec<String>,
24    pub additional_error_details: Vec<String>,
25}
26
27impl AmbiguousTypeError {
28    pub fn new(
29        inferred_expr: &InferredType,
30        source_span: &SourceSpan,
31        expected: &TypeHint,
32    ) -> AmbiguousTypeError {
33        let actual_kind = inferred_expr.get_type_hint();
34        match actual_kind {
35            TypeHint::Ambiguous { possibilities } => {
36                let possibilities = possibilities
37                    .into_iter()
38                    .map(|x| x.to_string())
39                    .collect::<Vec<_>>();
40
41                AmbiguousTypeError {
42                    ambiguous_expr_source_span: source_span.clone(),
43                    ambiguous_types: possibilities,
44                    additional_error_details: vec![],
45                }
46            }
47            _ => AmbiguousTypeError {
48                ambiguous_expr_source_span: source_span.clone(),
49                ambiguous_types: vec![expected.to_string(), inferred_expr.printable()],
50                additional_error_details: vec![],
51            },
52        }
53    }
54
55    pub fn with_additional_error_detail(&self, detail: &str) -> AmbiguousTypeError {
56        let mut error = self.clone();
57        error.additional_error_details.push(detail.to_string());
58        error
59    }
60}
61
62pub enum InvalidPatternMatchError {
63    ConstructorMismatch {
64        match_expr_source_span: SourceSpan,
65        constructor_name: String,
66    },
67    ArgSizeMismatch {
68        match_expr_source_span: SourceSpan,
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        match_expr_source_span: SourceSpan,
78        constructor_name: &str,
79    ) -> InvalidPatternMatchError {
80        InvalidPatternMatchError::ConstructorMismatch {
81            match_expr_source_span,
82            constructor_name: constructor_name.to_string(),
83        }
84    }
85
86    pub fn arg_size_mismatch(
87        match_expr_source_span: SourceSpan,
88        constructor_name: &str,
89        expected_arg_size: usize,
90        actual_arg_size: usize,
91    ) -> InvalidPatternMatchError {
92        InvalidPatternMatchError::ArgSizeMismatch {
93            match_expr_source_span,
94            expected_arg_size,
95            actual_arg_size,
96            constructor_name: constructor_name.to_string(),
97        }
98    }
99}
100
101#[derive(Debug, Clone)]
102pub struct UnificationError {}
103
104#[derive(Clone, Debug)]
105pub struct TypeMismatchError {
106    pub source_span: SourceSpan,
107    pub expected_type: ExpectedType,
108    pub actual_type: ActualType,
109    pub field_path: Path,
110    pub additional_error_detail: Vec<String>,
111}
112
113#[derive(Clone, Debug)]
114pub enum ExpectedType {
115    AnalysedType(AnalysedType),
116    // If the expected type is not fully known yet but only a hint is available.
117    // Example: when compiler cannot proceed unless it is a `record`, or `list` etc
118    Hint(TypeHint),
119    InferredType(InferredType),
120}
121
122#[derive(Clone, Debug)]
123pub enum ActualType {
124    Inferred(InferredType),
125    // If the actual type is not fully known yet but only a hint is available
126    Hint(TypeHint),
127}
128
129impl TypeMismatchError {
130    pub fn updated_expected_type(&self, expected_type: &AnalysedType) -> TypeMismatchError {
131        let mut mismatch_error: TypeMismatchError = self.clone();
132        mismatch_error.expected_type = ExpectedType::AnalysedType(expected_type.clone());
133        mismatch_error
134    }
135
136    pub fn at_field(&self, field_name: String) -> TypeMismatchError {
137        let mut mismatch_error: TypeMismatchError = self.clone();
138        mismatch_error
139            .field_path
140            .push_front(PathElem::Field(field_name));
141        mismatch_error
142    }
143}
144
145// A type unification can fail either due to a type mismatch or due to unresolved types
146pub enum TypeUnificationError {
147    TypeMismatchError { error: TypeMismatchError },
148    UnresolvedTypesError { error: UnResolvedTypesError },
149}
150
151impl TypeUnificationError {
152    pub fn unresolved_types_error(
153        source_span: SourceSpan,
154        additional_messages: Vec<String>,
155    ) -> TypeUnificationError {
156        TypeUnificationError::UnresolvedTypesError {
157            error: UnResolvedTypesError {
158                source_span,
159                additional_messages,
160                help_messages: vec![],
161                path: Path::default(),
162            },
163        }
164    }
165    pub fn type_mismatch_error(
166        source_span: SourceSpan,
167        expected_type: InferredType,
168        actual_type: InferredType,
169        additional_error_detail: Vec<String>,
170    ) -> TypeUnificationError {
171        TypeUnificationError::TypeMismatchError {
172            error: TypeMismatchError {
173                source_span,
174                expected_type: ExpectedType::InferredType(expected_type),
175                actual_type: ActualType::Inferred(actual_type),
176                field_path: Path::default(),
177                additional_error_detail,
178            },
179        }
180    }
181}
182
183#[derive(Debug, Clone)]
184pub struct UnResolvedTypesError {
185    pub source_span: SourceSpan,
186    pub help_messages: Vec<String>,
187    pub path: Path,
188    pub additional_messages: Vec<String>,
189}
190
191impl UnResolvedTypesError {
192    pub fn from(source_span: SourceSpan) -> Self {
193        let unresolved_types = UnResolvedTypesError {
194            source_span,
195            help_messages: Vec::new(),
196            path: Path::default(),
197            additional_messages: Vec::new(),
198        };
199
200        unresolved_types.with_default_help_messages()
201    }
202
203    pub fn with_default_help_messages(&self) -> Self {
204        self.with_help_message(
205            "try specifying the expected type explicitly",
206        ).with_help_message(
207            "if the issue persists, please review the script for potential type inconsistencies"
208        )
209    }
210
211    pub fn with_additional_error_detail(&self, message: impl AsRef<str>) -> UnResolvedTypesError {
212        let mut unresolved_error: UnResolvedTypesError = self.clone();
213        unresolved_error
214            .additional_messages
215            .push(message.as_ref().to_string());
216        unresolved_error
217    }
218
219    pub fn with_help_message(&self, message: impl AsRef<str>) -> UnResolvedTypesError {
220        let mut unresolved_error: UnResolvedTypesError = self.clone();
221        unresolved_error
222            .help_messages
223            .push(message.as_ref().to_string());
224
225        unresolved_error
226    }
227
228    pub fn at_field(&self, field_name: String) -> UnResolvedTypesError {
229        let mut unresolved_error: UnResolvedTypesError = self.clone();
230        unresolved_error
231            .path
232            .push_front(PathElem::Field(field_name));
233        unresolved_error
234    }
235
236    pub fn at_index(&self, index: usize) -> UnResolvedTypesError {
237        let mut unresolved_error: UnResolvedTypesError = self.clone();
238        unresolved_error.path.push_front(PathElem::Index(index));
239        unresolved_error
240    }
241}
242
243#[derive(Debug, Clone)]
244pub enum FunctionCallError {
245    InvalidFunctionCall {
246        function_name: String,
247        source_span: SourceSpan,
248        message: String,
249    },
250    TypeMisMatch {
251        function_name: String,
252        argument_source_span: SourceSpan,
253        error: TypeMismatchError,
254    },
255    MissingRecordFields {
256        function_name: String,
257        argument_source_span: SourceSpan,
258        missing_fields: Vec<Path>,
259    },
260    UnResolvedTypes {
261        function_name: String,
262        source_span: SourceSpan,
263        unresolved_error: UnResolvedTypesError,
264        expected_type: AnalysedType,
265    },
266
267    InvalidResourceMethodCall {
268        resource_method_name: String,
269        invalid_lhs_source_span: SourceSpan,
270    },
271
272    InvalidGenericTypeParameter {
273        generic_type_parameter: String,
274        source_span: SourceSpan,
275        message: String,
276    },
277
278    ArgumentSizeMisMatch {
279        function_name: String,
280        source_span: SourceSpan,
281        expected: usize,
282        provided: usize,
283    },
284}
285
286impl FunctionCallError {
287    pub fn invalid_function_call(
288        function_name: &str,
289        function_source_span: SourceSpan,
290        message: impl AsRef<str>,
291    ) -> FunctionCallError {
292        FunctionCallError::InvalidFunctionCall {
293            function_name: function_name.to_string(),
294            source_span: function_source_span,
295            message: message.as_ref().to_string(),
296        }
297    }
298    pub fn invalid_generic_type_parameter(
299        generic_type_parameter: &str,
300        message: impl AsRef<str>,
301        source_span: SourceSpan,
302    ) -> FunctionCallError {
303        FunctionCallError::InvalidGenericTypeParameter {
304            generic_type_parameter: generic_type_parameter.to_string(),
305            message: message.as_ref().to_string(),
306            source_span,
307        }
308    }
309}
310
311pub struct InvalidWorkerName {
312    pub worker_name_source_span: SourceSpan,
313    pub message: String,
314}
315
316#[derive(Clone)]
317pub struct CustomError {
318    pub source_span: SourceSpan,
319    pub message: String,
320    pub help_message: Vec<String>,
321}
322
323impl CustomError {
324    pub fn new(source_span: SourceSpan, message: impl AsRef<str>) -> CustomError {
325        CustomError {
326            source_span,
327            message: message.as_ref().to_string(),
328            help_message: Vec::new(),
329        }
330    }
331
332    pub fn with_help_message(&self, message: impl AsRef<str>) -> CustomError {
333        let mut custom_error: CustomError = self.clone();
334        custom_error.help_message.push(message.as_ref().to_string());
335        custom_error
336    }
337}