slang_frontend/semantic_analysis/validation/coordinator.rs
1use slang_shared::CompilationContext;
2use slang_types::TypeId;
3use slang_ir::ast::{BinaryExpr, Expression, LetStatement};
4
5use super::{
6 TypeChecker,
7 TypeCoercion,
8 TypeInference,
9 TypeValidation,
10 inference::{finalize_inferred_type, determine_let_statement_type},
11 coercion::{check_unspecified_int_for_type, check_unspecified_float_for_type},
12};
13use super::super::traits::SemanticResult;
14
15/// Coordinates between specialized type checking modules
16///
17/// This struct provides a unified interface for type checking operations
18/// while delegating to specialized modules for specific concerns like
19/// inference, coercion, and validation.
20pub struct TypeCheckingCoordinator<'a> {
21 checker: TypeChecker<'a>,
22 coercion: TypeCoercion<'a>,
23 _inference: TypeInference, // Unused for now but kept for future extensions
24 validation: TypeValidation<'a>,
25}
26
27impl<'a> TypeCheckingCoordinator<'a> {
28 /// Create a new type checking coordinator
29 ///
30 /// # Arguments
31 /// * `context` - The compilation context for type information
32 pub fn new(context: &'a CompilationContext) -> Self {
33 Self {
34 checker: TypeChecker::new(context),
35 coercion: TypeCoercion::new(context),
36 _inference: TypeInference{},
37 validation: TypeValidation::new(context),
38 }
39 }
40
41 /// Check if two types are compatible for assignment with coercion
42 ///
43 /// # Arguments
44 /// * `target` - The target type (left side of assignment)
45 /// * `source` - The source type (right side of assignment)
46 ///
47 /// # Returns
48 /// `true` if assignment is allowed, `false` otherwise
49 pub fn check_assignment_compatibility(&self, target: &TypeId, source: &TypeId) -> bool {
50 self.checker.check_assignment_compatibility(target, source)
51 }
52
53 /// Check if a function call is valid and return the result type
54 ///
55 /// # Arguments
56 /// * `function_type` - The function's type signature
57 /// * `argument_types` - The types of the provided arguments
58 ///
59 /// # Returns
60 /// Result containing the return type or an error
61 pub fn check_function_call(
62 &self,
63 function_type: &TypeId,
64 argument_types: &[TypeId],
65 ) -> SemanticResult {
66 self.checker.check_function_call(function_type, argument_types)
67 }
68
69 /// Check if mixed-type arithmetic operations are allowed with coercion
70 ///
71 /// # Arguments
72 /// * `left_type` - The type of the left operand
73 /// * `right_type` - The type of the right operand
74 /// * `bin_expr` - The binary expression containing both operands and the operator
75 ///
76 /// # Returns
77 /// Result containing the operation result type or an error
78 pub fn check_mixed_arithmetic_with_coercion(
79 &self,
80 left_type: &TypeId,
81 right_type: &TypeId,
82 bin_expr: &BinaryExpr,
83 ) -> SemanticResult {
84 self.coercion.check_mixed_arithmetic_operation(left_type, right_type, bin_expr)
85 }
86
87 /// Determine the final type for a let statement with potential inference
88 ///
89 /// # Arguments
90 /// * `let_stmt` - The let statement being analyzed
91 /// * `expr_type` - The type of the initialization expression
92 ///
93 /// # Returns
94 /// Result containing the final determined type
95 pub fn determine_let_statement_type(
96 &self,
97 let_stmt: &LetStatement,
98 expr_type: TypeId,
99 ) -> SemanticResult {
100 determine_let_statement_type(self.checker.context(), let_stmt, expr_type)
101 }
102
103 /// Finalize an inferred type (convert unspecified literals to concrete types)
104 ///
105 /// # Arguments
106 /// * `type_id` - The type to finalize
107 ///
108 /// # Returns
109 /// The concrete type (i64 for unspecified integers, f64 for unspecified floats)
110 pub fn finalize_inferred_type(&self, type_id: TypeId) -> TypeId {
111 finalize_inferred_type(type_id)
112 }
113
114 /// Validate that a literal value is within range for its target type
115 ///
116 /// # Arguments
117 /// * `expr` - The expression containing the literal
118 /// * `target_type` - The target type to validate against
119 ///
120 /// # Returns
121 /// Result indicating if validation passed
122 pub fn validate_literal_range(
123 &self,
124 expr: &Expression,
125 target_type: &TypeId,
126 ) -> SemanticResult {
127 // Use coercion module's range checking capabilities
128 if self.is_integer_type(target_type) {
129 check_unspecified_int_for_type(self.checker.context(), expr, target_type)
130 } else if self.is_float_type(target_type) {
131 check_unspecified_float_for_type(self.checker.context(), expr, target_type)
132 } else {
133 Ok(target_type.clone())
134 }
135 }
136
137 /// Validate function declaration constraints
138 ///
139 /// # Arguments
140 /// * `func_decl` - The function declaration to validate
141 ///
142 /// # Returns
143 /// Result indicating if validation passed
144 pub fn validate_function_declaration(
145 &self,
146 func_decl: &slang_ir::ast::FunctionDeclarationStmt,
147 ) -> SemanticResult {
148 self.validation.validate_function_declaration(func_decl)
149 }
150
151 /// Check if a type is numeric
152 pub fn is_numeric_type(&self, type_id: &TypeId) -> bool {
153 self.checker.is_numeric_type(type_id)
154 }
155
156 /// Check if a type is an integer type
157 pub fn is_integer_type(&self, type_id: &TypeId) -> bool {
158 self.checker.is_integer_type(type_id)
159 }
160
161 /// Check if a type is a float type
162 pub fn is_float_type(&self, type_id: &TypeId) -> bool {
163 self.checker.is_float_type(type_id)
164 }
165
166 /// Check if a type is an unsigned integer type
167 pub fn is_unsigned_integer_type(&self, type_id: &TypeId) -> bool {
168 self.checker.is_unsigned_integer_type(type_id)
169 }
170
171 /// Check if an unspecified literal can be coerced to a target type
172 pub fn can_coerce_unspecified_literal(&self, source: &TypeId, target: &TypeId) -> bool {
173 self.coercion.can_coerce(source, target)
174 }
175}