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::type_hint::{GetTypeHint, TypeHint};
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<String>,
25    pub additional_error_details: Vec<String>,
26}
27
28impl AmbiguousTypeError {
29    pub fn new(
30        inferred_expr: &InferredType,
31        expr: &Expr,
32        expected: &TypeHint,
33    ) -> AmbiguousTypeError {
34        let actual_kind = inferred_expr.get_type_hint();
35        match actual_kind {
36            TypeHint::Ambiguous { possibilities } => {
37                let possibilities = possibilities
38                    .into_iter()
39                    .map(|x| x.to_string())
40                    .collect::<Vec<_>>();
41
42                AmbiguousTypeError {
43                    expr: expr.clone(),
44                    ambiguous_types: possibilities,
45                    additional_error_details: vec![],
46                }
47            }
48            _ => AmbiguousTypeError {
49                expr: expr.clone(),
50                ambiguous_types: vec![expected.to_string(), inferred_expr.printable()],
51                additional_error_details: vec![],
52            },
53        }
54    }
55
56    pub fn with_additional_error_detail(&self, detail: &str) -> AmbiguousTypeError {
57        let mut error = self.clone();
58        error.additional_error_details.push(detail.to_string());
59        error
60    }
61}
62
63pub enum InvalidPatternMatchError {
64    ConstructorMismatch {
65        predicate_expr: Expr,
66        match_expr: Expr,
67        constructor_name: String,
68    },
69    ArgSizeMismatch {
70        predicate_expr: Expr,
71        match_expr: Expr,
72        constructor_name: String,
73        expected_arg_size: usize,
74        actual_arg_size: usize,
75    },
76}
77
78impl InvalidPatternMatchError {
79    pub fn constructor_type_mismatch(
80        predicate_expr: &Expr,
81        match_expr: &Expr,
82        constructor_name: &str,
83    ) -> InvalidPatternMatchError {
84        InvalidPatternMatchError::ConstructorMismatch {
85            predicate_expr: predicate_expr.clone(),
86            match_expr: match_expr.clone(),
87            constructor_name: constructor_name.to_string(),
88        }
89    }
90
91    pub fn arg_size_mismatch(
92        predicate_expr: &Expr,
93        match_expr: &Expr,
94        constructor_name: &str,
95        expected_arg_size: usize,
96        actual_arg_size: usize,
97    ) -> InvalidPatternMatchError {
98        InvalidPatternMatchError::ArgSizeMismatch {
99            predicate_expr: predicate_expr.clone(),
100            match_expr: match_expr.clone(),
101            expected_arg_size,
102            actual_arg_size,
103            constructor_name: constructor_name.to_string(),
104        }
105    }
106}
107
108#[derive(Clone, Debug)]
109pub struct TypeMismatchError {
110    pub expr_with_wrong_type: Expr,
111    pub parent_expr: Option<Expr>,
112    pub expected_type: ExpectedType,
113    pub actual_type: ActualType,
114    pub field_path: Path,
115    pub additional_error_detail: Vec<String>,
116}
117
118#[derive(Clone, Debug)]
119pub enum ExpectedType {
120    AnalysedType(AnalysedType),
121    Hint(TypeHint),
122}
123
124// If the actual type is not fully known but only a hint through TypeKind
125#[derive(Clone, Debug)]
126pub enum ActualType {
127    Inferred(InferredType),
128    Hint(TypeHint),
129}
130
131impl TypeMismatchError {
132    pub fn updated_expected_type(&self, expected_type: &AnalysedType) -> TypeMismatchError {
133        let mut mismatch_error: TypeMismatchError = self.clone();
134        mismatch_error.expected_type = ExpectedType::AnalysedType(expected_type.clone());
135        mismatch_error
136    }
137
138    pub fn at_field(&self, field_name: String) -> TypeMismatchError {
139        let mut mismatch_error: TypeMismatchError = self.clone();
140        mismatch_error
141            .field_path
142            .push_front(PathElem::Field(field_name));
143        mismatch_error
144    }
145
146    pub fn with_actual_inferred_type(
147        expr: &Expr,
148        parent_expr: Option<&Expr>,
149        expected_type: AnalysedType,
150        actual_type: InferredType,
151    ) -> Self {
152        TypeMismatchError {
153            expr_with_wrong_type: expr.clone(),
154            parent_expr: parent_expr.cloned(),
155            expected_type: ExpectedType::AnalysedType(expected_type),
156            actual_type: ActualType::Inferred(actual_type),
157            field_path: Path::default(),
158            additional_error_detail: Vec::new(),
159        }
160    }
161
162    pub fn with_actual_type_kind(
163        expr: &Expr,
164        parent_expr: Option<&Expr>,
165        expected_type: AnalysedType,
166        actual_type: &TypeHint,
167    ) -> Self {
168        TypeMismatchError {
169            expr_with_wrong_type: expr.clone(),
170            parent_expr: parent_expr.cloned(),
171            expected_type: ExpectedType::AnalysedType(expected_type),
172            actual_type: ActualType::Hint(actual_type.clone()),
173            field_path: Path::default(),
174            additional_error_detail: Vec::new(),
175        }
176    }
177}
178
179pub struct MultipleUnResolvedTypesError(pub Vec<UnResolvedTypesError>);
180
181#[derive(Debug, Clone)]
182pub struct UnResolvedTypesError {
183    pub unresolved_expr: Expr,
184    pub parent_expr: Option<Expr>,
185    pub additional_messages: Vec<String>,
186    pub help_messages: Vec<String>,
187    pub path: Path,
188}
189
190impl UnResolvedTypesError {
191    pub fn from(expr: &Expr, parent_expr: Option<Expr>) -> Self {
192        let unresolved_types = UnResolvedTypesError {
193            unresolved_expr: expr.clone(),
194            additional_messages: Vec::new(),
195            parent_expr: parent_expr.clone(),
196            help_messages: Vec::new(),
197            path: Path::default(),
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_parent_expr(&self, expr: &Expr) -> UnResolvedTypesError {
212        let mut unresolved_error: UnResolvedTypesError = self.clone();
213        unresolved_error.parent_expr = Some(expr.clone());
214        unresolved_error
215    }
216
217    pub fn with_additional_error_detail(&self, message: impl AsRef<str>) -> UnResolvedTypesError {
218        let mut unresolved_error: UnResolvedTypesError = self.clone();
219        unresolved_error
220            .additional_messages
221            .push(message.as_ref().to_string());
222        unresolved_error
223    }
224
225    pub fn with_help_message(&self, message: impl AsRef<str>) -> UnResolvedTypesError {
226        let mut unresolved_error: UnResolvedTypesError = self.clone();
227        unresolved_error
228            .help_messages
229            .push(message.as_ref().to_string());
230
231        unresolved_error
232    }
233
234    pub fn at_field(&self, field_name: String) -> UnResolvedTypesError {
235        let mut unresolved_error: UnResolvedTypesError = self.clone();
236        unresolved_error
237            .path
238            .push_front(PathElem::Field(field_name));
239        unresolved_error
240    }
241
242    pub fn at_index(&self, index: usize) -> UnResolvedTypesError {
243        let mut unresolved_error: UnResolvedTypesError = self.clone();
244        unresolved_error.path.push_front(PathElem::Index(index));
245        unresolved_error
246    }
247}
248
249impl Display for UnResolvedTypesError {
250    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
251        let span = self.unresolved_expr.source_span();
252
253        writeln!(
254            f,
255            "cannot determine the type of the following rib expression found at line {}, column {}",
256            span.start_line(),
257            span.start_column()
258        )?;
259
260        writeln!(f, "`{}`", self.unresolved_expr)?;
261
262        if let Some(parent) = &self.parent_expr {
263            writeln!(f, "found within:")?;
264            writeln!(f, "`{}`", parent)?;
265        }
266
267        if !self.additional_messages.is_empty() {
268            for message in &self.additional_messages {
269                writeln!(f, "{}", message)?;
270            }
271        }
272
273        Ok(())
274    }
275}
276
277#[derive(Debug, Clone)]
278pub enum FunctionCallError {
279    InvalidFunctionCall {
280        function_name: String,
281        expr: Expr,
282        message: String,
283    },
284    TypeMisMatch {
285        function_name: String,
286        argument: Expr,
287        error: TypeMismatchError,
288    },
289    MissingRecordFields {
290        function_name: String,
291        argument: Expr,
292        missing_fields: Vec<Path>,
293    },
294    UnResolvedTypes {
295        function_name: String,
296        argument: Expr,
297        unresolved_error: UnResolvedTypesError,
298        expected_type: AnalysedType,
299    },
300
301    InvalidResourceMethodCall {
302        resource_method_name: String,
303        invalid_lhs: Expr,
304    },
305
306    InvalidGenericTypeParameter {
307        generic_type_parameter: String,
308        expr: Expr,
309        message: String,
310    },
311
312    ArgumentSizeMisMatch {
313        function_name: String,
314        expr: Expr,
315        expected: usize,
316        provided: usize,
317    },
318}
319
320pub struct InvalidWorkerName {
321    pub worker_name_expr: Expr,
322    pub message: String,
323}
324
325#[derive(Clone)]
326pub struct CustomError {
327    pub expr: Expr,
328    pub message: String,
329    pub help_message: Vec<String>,
330}
331
332impl CustomError {
333    pub fn new(expr: &Expr, message: impl AsRef<str>) -> CustomError {
334        CustomError {
335            expr: expr.clone(),
336            message: message.as_ref().to_string(),
337            help_message: Vec::new(),
338        }
339    }
340
341    pub fn with_help_message(&self, message: impl AsRef<str>) -> CustomError {
342        let mut custom_error: CustomError = self.clone();
343        custom_error.help_message.push(message.as_ref().to_string());
344        custom_error
345    }
346}