slang_frontend/semantic_analysis/operations/helpers.rs
1use super::super::error::SemanticAnalysisError;
2use slang_ir::Location;
3use slang_shared::CompilationContext;
4use slang_types::TypeId;
5
6/// Helper functions for common type checking operations.
7/// This module provides utility functions that are shared across different operation types.
8
9/// Creates a boolean type ID.
10/// This is a convenience function used by relational and logical operations.
11///
12/// ### Returns
13/// * `TypeId` representing the boolean type
14pub fn bool_type() -> TypeId {
15 TypeId::bool()
16}
17
18/// Creates an operation type mismatch error.
19/// This is a convenience function to create consistent error messages across operations.
20///
21/// ### Arguments
22/// * `operator` - The operator that failed
23/// * `left_type` - The type of the left operand
24/// * `right_type` - The type of the right operand
25/// * `location` - The source location of the operation
26///
27/// ### Returns
28/// * `SemanticAnalysisError` with operation type mismatch details
29pub fn operation_type_mismatch_error(
30 operator: &str,
31 left_type: &TypeId,
32 right_type: &TypeId,
33 location: &Location,
34) -> SemanticAnalysisError {
35 SemanticAnalysisError::OperationTypeMismatch {
36 operator: operator.to_string(),
37 left_type: left_type.clone(),
38 right_type: right_type.clone(),
39 location: *location,
40 }
41}
42
43/// Creates a logical operator type mismatch error.
44/// This is a convenience function for logical operations that require boolean operands.
45///
46/// ### Arguments
47/// * `operator` - The logical operator that failed
48/// * `left_type` - The type of the left operand
49/// * `right_type` - The type of the right operand
50/// * `location` - The source location of the operation
51///
52/// ### Returns
53/// * `SemanticAnalysisError` with logical operator type mismatch details
54pub fn logical_operator_type_mismatch_error(
55 operator: &str,
56 left_type: &TypeId,
57 right_type: &TypeId,
58 location: &Location,
59) -> SemanticAnalysisError {
60 SemanticAnalysisError::LogicalOperatorTypeMismatch {
61 operator: operator.to_string(),
62 left_type: left_type.clone(),
63 right_type: right_type.clone(),
64 location: *location,
65 }
66}
67
68/// Checks if two types are identical.
69/// This is used by operations that require exact type matches.
70///
71/// ### Arguments
72/// * `left_type` - The first type to compare
73/// * `right_type` - The second type to compare
74///
75/// ### Returns
76/// * `true` if the types are identical
77/// * `false` otherwise
78pub fn types_are_identical(left_type: &TypeId, right_type: &TypeId) -> bool {
79 left_type == right_type
80}
81
82/// Checks if a type is a numeric type (integer or float).
83/// This is used to validate operations that only work on numeric types.
84///
85/// ### Arguments
86/// * `_context` - The compilation context (unused but kept for API consistency)
87/// * `type_id` - The type to check
88///
89/// ### Returns
90/// * `true` if the type is numeric
91/// * `false` otherwise
92pub fn is_numeric_type(context: &CompilationContext, type_id: &TypeId) -> bool {
93 if let Some(primitive) = context.get_primitive_type_from_id(type_id) {
94 primitive.is_numeric()
95 } else {
96 false
97 }
98}
99
100/// Checks if a type is a boolean type.
101/// This is used by logical operations.
102///
103/// ### Arguments
104/// * `type_id` - The type to check
105///
106/// ### Returns
107/// * `true` if the type is boolean
108/// * `false` otherwise
109pub fn is_boolean_type(type_id: &TypeId) -> bool {
110 *type_id == TypeId::bool()
111}
112
113/// Checks if a type is the unit type.
114/// Unit types are not allowed in most operations.
115///
116/// ### Arguments
117/// * `type_id` - The type to check
118///
119/// ### Returns
120/// * `true` if the type is unit
121/// * `false` otherwise
122pub fn is_unit_type(type_id: &TypeId) -> bool {
123 *type_id == TypeId::unit()
124}
125
126/// Checks if a type is a string type.
127/// String types have special rules for the addition operator (concatenation).
128///
129/// ### Arguments
130/// * `type_id` - The type to check
131///
132/// ### Returns
133/// * `true` if the type is string
134/// * `false` otherwise
135pub fn is_string_type(type_id: &TypeId) -> bool {
136 *type_id == TypeId::string()
137}
138
139/// Checks if a type is an unspecified integer literal.
140/// These can be coerced to specific integer types.
141///
142/// ### Arguments
143/// * `type_id` - The type to check
144///
145/// ### Returns
146/// * `true` if the type is an unspecified integer
147/// * `false` otherwise
148pub fn is_unspecified_integer_type(type_id: &TypeId) -> bool {
149 *type_id == TypeId::unspecified_int()
150}
151
152/// Checks if a type is an unspecified float literal.
153/// These can be coerced to specific float types.
154///
155/// ### Arguments
156/// * `type_id` - The type to check
157///
158/// ### Returns
159/// * `true` if the type is an unspecified float
160/// * `false` otherwise
161pub fn is_unspecified_float_type(type_id: &TypeId) -> bool {
162 *type_id == TypeId::unspecified_float()
163}