slang_frontend/semantic_analysis/
type_system.rs1use super::{error::SemanticAnalysisError, traits::SemanticResult};
2use slang_ir::ast::{
3 BinaryExpr, BinaryOperator, Expression, LetStatement, LiteralValue, UnaryOperator,
4};
5use slang_shared::CompilationContext;
6use slang_types::{TypeId, TYPE_NAME_U32, TYPE_NAME_U64};
7
8pub fn is_integer_type(context: &CompilationContext, type_id: &TypeId) -> bool {
17 context.is_integer_type(type_id)
18}
19
20pub fn is_float_type(context: &CompilationContext, type_id: &TypeId) -> bool {
29 context.is_float_type(type_id)
30}
31
32pub fn is_unsigned_type(context: &CompilationContext, type_id: &TypeId) -> bool {
41 let type_name = context.get_type_name(type_id);
42 type_name == TYPE_NAME_U64 || type_name == TYPE_NAME_U32
43}
44
45pub fn check_unspecified_int_for_type(
58 context: &CompilationContext,
59 expr: &Expression,
60 target_type: &TypeId,
61) -> SemanticResult {
62 if let Expression::Unary(unary_expr) = expr {
63 if unary_expr.operator == UnaryOperator::Negate {
64 if let Expression::Literal(lit) = &*unary_expr.right {
65 if let LiteralValue::UnspecifiedInteger(n) = &lit.value {
66 if context.get_type_name(target_type) == "u32"
67 || context.get_type_name(target_type) == "u64"
68 {
69 return Err(SemanticAnalysisError::ValueOutOfRange {
70 value: format!("-{}", n),
71 target_type: target_type.clone(),
72 is_float: false,
73 location: expr.location(),
74 });
75 }
76 }
77 }
78 }
79 }
80
81 if let Expression::Literal(lit) = expr {
82 if let LiteralValue::UnspecifiedInteger(n) = &lit.value {
83 let value_in_range = context.check_value_in_range(n, target_type);
84
85 if value_in_range {
86 return Ok(target_type.clone());
87 } else {
88 return Err(SemanticAnalysisError::ValueOutOfRange {
89 value: n.to_string(),
90 target_type: target_type.clone(),
91 is_float: false,
92 location: expr.location(),
93 });
94 }
95 }
96 }
97 Ok(target_type.clone())
98}
99
100pub fn check_unspecified_float_for_type(
113 context: &CompilationContext,
114 expr: &Expression,
115 target_type: &TypeId,
116) -> SemanticResult {
117 if let Expression::Literal(lit) = expr {
118 if let LiteralValue::UnspecifiedFloat(f) = &lit.value {
119 let value_in_range = context.check_float_value_in_range(f, target_type);
120
121 if value_in_range {
122 return Ok(target_type.clone());
123 } else {
124 return Err(SemanticAnalysisError::ValueOutOfRange {
125 value: f.to_string(),
126 target_type: target_type.clone(),
127 is_float: true,
128 location: expr.location(),
129 });
130 }
131 }
132 }
133 Ok(target_type.clone())
134}
135
136pub fn finalize_inferred_type(type_id: TypeId) -> TypeId {
147 if type_id == TypeId::unspecified_int() {
148 TypeId::i64()
149 } else if type_id == TypeId::unspecified_float() {
150 TypeId::f64()
151 } else {
152 type_id
153 }
154}
155
156pub fn determine_let_statement_type(
169 context: &CompilationContext,
170 let_stmt: &LetStatement,
171 expr_type: TypeId,
172) -> SemanticResult {
173 if let_stmt.expr_type == TypeId::unknown() {
174 return Ok(expr_type);
175 }
176
177 if let_stmt.expr_type == expr_type {
178 if is_unsigned_type(context, &let_stmt.expr_type) {
179 check_unspecified_int_for_type(context, &let_stmt.value, &let_stmt.expr_type)?;
180 }
181 return Ok(let_stmt.expr_type.clone());
182 }
183
184 if context.get_function_type(&let_stmt.expr_type).is_some()
185 && context.get_function_type(&expr_type).is_some()
186 {
187 if let_stmt.expr_type == expr_type {
188 return Ok(let_stmt.expr_type.clone());
189 } else {
190 return Err(SemanticAnalysisError::TypeMismatch {
191 expected: let_stmt.expr_type.clone(),
192 actual: expr_type,
193 context: Some(let_stmt.name.clone()),
194 location: let_stmt.location,
195 });
196 }
197 }
198
199 if expr_type == TypeId::unspecified_int() {
200 return handle_unspecified_int_assignment(context, let_stmt, &expr_type);
201 }
202
203 if expr_type == TypeId::unspecified_float() {
204 return handle_unspecified_float_assignment(context, let_stmt, &expr_type);
205 }
206
207 Err(SemanticAnalysisError::TypeMismatch {
208 expected: let_stmt.expr_type.clone(),
209 actual: expr_type,
210 context: Some(let_stmt.name.clone()),
211 location: let_stmt.location,
212 })
213}
214
215pub fn handle_unspecified_int_assignment(
226 context: &CompilationContext,
227 let_stmt: &LetStatement,
228 _expr_type: &TypeId,
229) -> SemanticResult {
230 if is_integer_type(context, &let_stmt.expr_type) {
231 check_unspecified_int_for_type(context, &let_stmt.value, &let_stmt.expr_type)
232 } else {
233 Err(SemanticAnalysisError::TypeMismatch {
234 expected: let_stmt.expr_type.clone(),
235 actual: TypeId::unspecified_int(),
236 context: Some(let_stmt.name.clone()),
237 location: let_stmt.location,
238 })
239 }
240}
241
242pub fn handle_unspecified_float_assignment(
253 context: &CompilationContext,
254 let_stmt: &LetStatement,
255 _expr_type: &TypeId,
256) -> SemanticResult {
257 if is_float_type(context, &let_stmt.expr_type) {
258 check_unspecified_float_for_type(context, &let_stmt.value, &let_stmt.expr_type)
259 } else {
260 Err(SemanticAnalysisError::TypeMismatch {
261 expected: let_stmt.expr_type.clone(),
262 actual: TypeId::unspecified_float(),
263 context: Some(let_stmt.name.clone()),
264 location: let_stmt.location,
265 })
266 }
267}
268
269pub fn check_mixed_arithmetic_operation(
286 context: &CompilationContext,
287 left_type: &TypeId,
288 right_type: &TypeId,
289 bin_expr: &BinaryExpr,
290) -> SemanticResult {
291 if *left_type == TypeId::unspecified_int() && is_integer_type(context, right_type) {
292 return check_unspecified_int_for_type(context, &bin_expr.left, right_type);
293 }
294
295 if *right_type == TypeId::unspecified_int() && is_integer_type(context, left_type) {
296 return check_unspecified_int_for_type(context, &bin_expr.right, left_type);
297 }
298
299 if *left_type == TypeId::unspecified_float() && is_float_type(context, right_type) {
300 return check_unspecified_float_for_type(context, &bin_expr.left, right_type);
301 }
302
303 if *right_type == TypeId::unspecified_float() && is_float_type(context, left_type) {
304 return check_unspecified_float_for_type(context, &bin_expr.right, left_type);
305 }
306
307 if bin_expr.operator == BinaryOperator::Add
308 && *left_type == TypeId::string()
309 && *right_type == TypeId::string()
310 {
311 return Ok(TypeId::string());
312 }
313
314 Err(SemanticAnalysisError::OperationTypeMismatch {
315 operator: bin_expr.operator.to_string(),
316 left_type: left_type.clone(),
317 right_type: right_type.clone(),
318 location: bin_expr.location,
319 })
320}