1#![warn(missing_docs)]
29#![warn(clippy::all)]
30#![deny(unsafe_code)]
31
32#[macro_use]
33#[allow(unused_macros)]
34mod generated_contracts;
35
36pub mod box_transform;
37pub mod concurrency_transform;
38pub mod enum_gen;
39pub mod pattern_gen;
40pub mod test_generator;
41mod transform_gen;
42mod type_gen;
43
44use decy_hir::{HirExpression, HirFunction, HirType};
45use std::collections::HashMap;
46
47#[derive(Debug, Clone)]
50struct TypeContext {
51 variables: HashMap<String, HirType>,
52 structs: HashMap<String, Vec<(String, HirType)>>, functions: HashMap<String, Vec<HirType>>, slice_func_args: HashMap<String, Vec<(usize, usize)>>,
58 string_iter_params: HashMap<String, String>,
61 string_iter_funcs: HashMap<String, Vec<(usize, bool)>>,
64 globals: std::collections::HashSet<String>,
66 renamed_locals: HashMap<String, String>,
68}
69
70impl TypeContext {
71 fn new() -> Self {
72 Self {
73 variables: HashMap::new(),
74 structs: HashMap::new(),
75 functions: HashMap::new(),
76 slice_func_args: HashMap::new(),
77 string_iter_params: HashMap::new(),
78 string_iter_funcs: HashMap::new(),
79 globals: std::collections::HashSet::new(),
80 renamed_locals: HashMap::new(),
81 }
82 }
83
84 fn add_renamed_local(&mut self, original: String, renamed: String) {
86 self.renamed_locals.insert(original, renamed);
87 }
88
89 fn get_renamed_local(&self, name: &str) -> Option<&String> {
91 self.renamed_locals.get(name)
92 }
93
94 fn add_global(&mut self, name: String) {
96 self.globals.insert(name);
97 }
98
99 fn is_global(&self, name: &str) -> bool {
101 self.globals.contains(name)
102 }
103
104 fn add_string_iter_func(&mut self, func_name: String, params: Vec<(usize, bool)>) {
106 self.string_iter_funcs.insert(func_name, params);
107 }
108
109 fn get_string_iter_func(&self, func_name: &str) -> Option<&Vec<(usize, bool)>> {
111 self.string_iter_funcs.get(func_name)
112 }
113
114 fn add_string_iter_param(&mut self, param_name: String, index_var: String) {
116 self.string_iter_params.insert(param_name, index_var);
117 }
118
119 #[cfg(test)]
121 fn is_string_iter_param(&self, name: &str) -> bool {
122 self.string_iter_params.contains_key(name)
123 }
124
125 fn get_string_iter_index(&self, name: &str) -> Option<&String> {
127 self.string_iter_params.get(name)
128 }
129
130 fn add_function(&mut self, name: String, param_types: Vec<HirType>) {
132 self.functions.insert(name, param_types);
133 }
134
135 fn add_slice_func_args(&mut self, name: String, arg_mappings: Vec<(usize, usize)>) {
137 self.slice_func_args.insert(name, arg_mappings);
138 }
139
140 fn get_slice_func_len_indices(&self, func_name: &str) -> Option<&Vec<(usize, usize)>> {
142 self.slice_func_args.get(func_name)
143 }
144
145 fn get_function_param_type(&self, func_name: &str, param_index: usize) -> Option<&HirType> {
147 self.functions.get(func_name).and_then(|params| params.get(param_index))
148 }
149
150 fn from_function(func: &HirFunction) -> Self {
151 let mut ctx = Self::new();
152 for param in func.parameters() {
154 ctx.variables.insert(param.name().to_string(), param.param_type().clone());
155 }
156 ctx
157 }
158
159 fn add_variable(&mut self, name: String, var_type: HirType) {
160 self.variables.insert(name, var_type);
161 }
162
163 fn add_struct(&mut self, struct_def: &decy_hir::HirStruct) {
164 let fields: Vec<(String, HirType)> = struct_def
165 .fields()
166 .iter()
167 .map(|f| (f.name().to_string(), f.field_type().clone()))
168 .collect();
169 self.structs.insert(struct_def.name().to_string(), fields);
170 }
171
172 fn struct_has_default(&self, struct_name: &str) -> bool {
175 if let Some(fields) = self.structs.get(struct_name) {
176 !fields.iter().any(|(_, field_type)| {
178 matches!(
179 field_type,
180 HirType::Array { size: Some(n), .. } if *n > 32
181 )
182 })
183 } else {
184 false
186 }
187 }
188
189 fn get_type(&self, name: &str) -> Option<&HirType> {
190 self.variables.get(name)
191 }
192
193 fn get_field_type(&self, object_expr: &HirExpression, field_name: &str) -> Option<HirType> {
194 let object_type = match object_expr {
196 HirExpression::Variable(var_name) => self.get_type(var_name)?,
197 _ => return None,
198 };
199
200 let struct_name = match object_type {
202 HirType::Struct(name) => name,
203 HirType::Pointer(inner) => {
204 if let HirType::Struct(name) = &**inner {
206 name
207 } else {
208 return None;
209 }
210 }
211 HirType::Box(inner) => {
213 if let HirType::Struct(name) = &**inner {
214 name
215 } else {
216 return None;
217 }
218 }
219 HirType::Reference { inner, .. } => {
221 if let HirType::Struct(name) = &**inner {
222 name
223 } else {
224 return None;
225 }
226 }
227 _ => return None,
228 };
229
230 let fields = self.structs.get(struct_name)?;
232 fields.iter().find(|(name, _)| name == field_name).map(|(_, field_type)| field_type.clone())
233 }
234
235 fn is_pointer(&self, name: &str) -> bool {
236 matches!(self.get_type(name), Some(HirType::Pointer(_)))
237 }
238
239 fn is_option(&self, name: &str) -> bool {
240 matches!(self.get_type(name), Some(HirType::Option(_)))
241 }
242
243 fn is_vec(&self, name: &str) -> bool {
244 matches!(self.get_type(name), Some(HirType::Vec(_)))
245 }
246
247 fn infer_expression_type(&self, expr: &HirExpression) -> Option<HirType> {
250 match expr {
251 HirExpression::Variable(name) => self.get_type(name).cloned(),
252 HirExpression::IntLiteral(_) => Some(HirType::Int),
254 HirExpression::FloatLiteral(_) => Some(HirType::Double), HirExpression::CharLiteral(_) => Some(HirType::Char),
256 HirExpression::Dereference(inner) => {
257 match self.infer_expression_type(inner) {
261 Some(HirType::Pointer(pointee_type)) => Some(*pointee_type),
262 Some(HirType::Box(inner_type)) => Some(*inner_type),
263 Some(HirType::Reference { inner: ref_inner, .. }) => Some(*ref_inner),
264 Some(HirType::Vec(elem_type)) => Some(*elem_type),
266 _ => None,
267 }
268 }
269 HirExpression::ArrayIndex { array, index: _ } => {
270 if let Some(array_type) = self.infer_expression_type(array) {
272 match array_type {
273 HirType::Array { element_type, .. } => Some(*element_type),
274 HirType::Pointer(element_type) => Some(*element_type),
275 HirType::Reference { inner, .. } => match *inner {
278 HirType::Vec(elem_type) => Some(*elem_type),
279 HirType::Array { element_type, .. } => Some(*element_type),
280 _ => None,
281 },
282 HirType::Vec(elem_type) => Some(*elem_type),
283 _ => None,
284 }
285 } else {
286 None
287 }
288 }
289 HirExpression::FieldAccess { object, field } => {
291 if let Some(obj_type) = self.infer_expression_type(object) {
293 self.get_field_type_from_type(&obj_type, field)
294 } else {
295 None
296 }
297 }
298 HirExpression::PointerFieldAccess { pointer, field } => {
300 if let Some(ptr_type) = self.infer_expression_type(pointer) {
302 match ptr_type {
303 HirType::Pointer(inner) | HirType::Box(inner) => {
304 self.get_field_type_from_type(&inner, field)
305 }
306 HirType::Reference { inner, .. } => {
308 self.get_field_type_from_type(&inner, field)
309 }
310 _ => None,
311 }
312 } else {
313 None
314 }
315 }
316 HirExpression::BinaryOp { left, right, op } => {
318 use decy_hir::BinaryOperator;
319 let left_type = self.infer_expression_type(left);
320 let right_type = self.infer_expression_type(right);
321
322 match op {
324 BinaryOperator::Add
325 | BinaryOperator::Subtract
326 | BinaryOperator::Multiply
327 | BinaryOperator::Divide
328 | BinaryOperator::Modulo => {
329 if matches!(left_type, Some(HirType::Double))
331 || matches!(right_type, Some(HirType::Double))
332 {
333 return Some(HirType::Double);
334 }
335 if matches!(left_type, Some(HirType::Float))
337 || matches!(right_type, Some(HirType::Float))
338 {
339 return Some(HirType::Float);
340 }
341 Some(HirType::Int)
343 }
344 BinaryOperator::Equal
346 | BinaryOperator::NotEqual
347 | BinaryOperator::LessThan
348 | BinaryOperator::GreaterThan
349 | BinaryOperator::LessEqual
350 | BinaryOperator::GreaterEqual
351 | BinaryOperator::LogicalAnd
352 | BinaryOperator::LogicalOr => Some(HirType::Int),
353 BinaryOperator::BitwiseAnd
355 | BinaryOperator::BitwiseOr
356 | BinaryOperator::BitwiseXor
357 | BinaryOperator::LeftShift
358 | BinaryOperator::RightShift => Some(HirType::Int),
359 _ => None,
360 }
361 }
362 _ => None,
363 }
364 }
365
366 fn get_field_type_from_type(&self, obj_type: &HirType, field_name: &str) -> Option<HirType> {
368 let struct_name = match obj_type {
369 HirType::Struct(name) => name,
370 _ => return None,
371 };
372 let fields = self.structs.get(struct_name)?;
373 fields.iter().find(|(name, _)| name == field_name).map(|(_, field_type)| field_type.clone())
374 }
375}
376
377fn escape_rust_keyword(name: &str) -> String {
380 const RUST_KEYWORDS: &[&str] = &[
382 "as", "async", "await", "break", "const", "continue", "crate", "dyn", "else", "enum",
383 "extern", "false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", "move",
384 "mut", "pub", "ref", "return", "self", "Self", "static", "struct", "super", "trait",
385 "true", "type", "unsafe", "use", "where", "while",
386 "abstract", "become", "box", "do", "final", "macro", "override", "priv", "try", "typeof",
388 "unsized", "virtual", "yield",
389 ];
390
391 if RUST_KEYWORDS.contains(&name) {
392 format!("r#{}", name)
393 } else {
394 name.to_string()
395 }
396}
397
398#[derive(Debug, Clone)]
400pub struct CodeGenerator {
401 box_transformer: box_transform::BoxTransformer,
402}
403
404impl CodeGenerator {
405 pub fn new() -> Self {
415 Self { box_transformer: box_transform::BoxTransformer::new() }
416 }
417
418 fn unsafe_block(code: &str, safety_reason: &str) -> String {
421 format!("/* SAFETY: {} */ unsafe {{ {} }}", safety_reason, code)
422 }
423
424 fn unsafe_stmt(code: &str, safety_reason: &str) -> String {
427 format!("// SAFETY: {}\n unsafe {{ {}; }}", safety_reason, code)
428 }
429
430 pub fn generate_macro(
481 &self,
482 macro_def: &decy_hir::HirMacroDefinition,
483 ) -> anyhow::Result<String> {
484 if macro_def.is_function_like() {
485 return self.generate_function_like_macro(macro_def);
487 }
488
489 let name = macro_def.name();
491 let body = macro_def.body();
492
493 if body.is_empty() {
495 return Ok(format!("// Empty macro: {}", name));
496 }
497
498 let (rust_type, rust_value) = self.infer_macro_type(body)?;
500
501 Ok(format!("const {}: {} = {};", name, rust_type, rust_value))
502 }
503
504 fn generate_function_like_macro(
519 &self,
520 macro_def: &decy_hir::HirMacroDefinition,
521 ) -> anyhow::Result<String> {
522 let name = macro_def.name();
523 let params = macro_def.parameters();
524 let body = macro_def.body();
525
526 let fn_name = self.convert_to_snake_case(name);
528
529 let param_list =
531 params.iter().map(|p| format!("{}: i32", p)).collect::<Vec<_>>().join(", ");
532
533 let rust_body = self.transform_macro_body(body, params)?;
535
536 let return_type = self.infer_return_type(body);
538
539 let result = format!(
541 "#[inline]\nfn {}({}) -> {} {{\n {}\n}}",
542 fn_name, param_list, return_type, rust_body
543 );
544
545 Ok(result)
546 }
547
548 fn convert_to_snake_case(&self, name: &str) -> String {
550 name.to_lowercase()
551 }
552
553 fn transform_macro_body(&self, body: &str, params: &[String]) -> anyhow::Result<String> {
560 let mut result = body.to_string();
561
562 if result.contains('?') && result.contains(':') {
564 result = self.transform_ternary(&result)?;
565 } else {
566 for param in params {
568 result = result.replace(&format!("({})", param), param);
569 }
570
571 result = self.remove_outer_parens(&result);
573
574 result = self.add_operator_spaces(&result);
576 }
577
578 Ok(result)
579 }
580
581 fn transform_ternary(&self, expr: &str) -> anyhow::Result<String> {
585 let question_pos = expr.find('?').unwrap_or(0);
587 let colon_pos = expr.rfind(':').unwrap_or(0);
588
589 if question_pos == 0 || colon_pos == 0 || colon_pos <= question_pos {
590 return Ok(expr.to_string());
592 }
593
594 let condition = expr[..question_pos].trim();
596 let true_expr = expr[question_pos + 1..colon_pos].trim();
597 let false_expr = expr[colon_pos + 1..].trim();
598
599 let condition = self.remove_outer_parens(condition);
601 let condition = self.clean_expression(&condition);
602 let true_expr = self.remove_outer_parens(true_expr);
603 let true_expr = self.clean_expression(&true_expr);
604 let false_expr = self.remove_outer_parens(false_expr);
605 let false_expr = self.clean_expression(&false_expr);
606
607 Ok(format!("if {} {{ {} }} else {{ {} }}", condition, true_expr, false_expr))
608 }
609
610 fn remove_outer_parens(&self, expr: &str) -> String {
612 Self::remove_outer_parens_impl(expr)
613 }
614
615 fn remove_outer_parens_impl(expr: &str) -> String {
617 let trimmed = expr.trim();
618 if trimmed.starts_with('(') && trimmed.ends_with(')') {
619 let mut depth = 0;
621 let chars: Vec<char> = trimmed.chars().collect();
622 for (i, ch) in chars.iter().enumerate() {
623 match ch {
624 '(' => depth += 1,
625 ')' => {
626 depth -= 1;
627 if depth == 0 && i < chars.len() - 1 {
628 return trimmed.to_string();
630 }
631 }
632 _ => {}
633 }
634 }
635 return Self::remove_outer_parens_impl(&trimmed[1..trimmed.len() - 1]);
637 }
638 trimmed.to_string()
639 }
640
641 fn clean_expression(&self, expr: &str) -> String {
643 let mut result = expr.to_string();
644
645 result = result.replace("-(x)", "-x");
647 result = result.replace("-(a)", "-a");
648 result = result.replace("-(b)", "-b");
649 result = result.replace("-(c)", "-c");
650 result = result.replace("-(n)", "-n");
651
652 result = result.replace("(x)", "x");
655 result = result.replace("(a)", "a");
656 result = result.replace("(b)", "b");
657 result = result.replace("(c)", "c");
658 result = result.replace("(n)", "n");
659
660 result = self.add_operator_spaces(&result);
662
663 result
664 }
665
666 fn add_operator_spaces(&self, expr: &str) -> String {
668 let mut result = expr.to_string();
669
670 result = result.replace(">", " > ");
672 result = result.replace("<", " < ");
673 result = result.replace("==", " == ");
674 result = result.replace("!=", " != ");
675 result = result.replace(">=", " >= ");
676 result = result.replace("<=", " <= ");
677
678 result = result.replace("&&", " && ");
680 result = result.replace("||", " || ");
681
682 result = result.replace("+", " + ");
684 let chars: Vec<char> = result.chars().collect();
687 let mut new_result = String::new();
688 for (i, ch) in chars.iter().enumerate() {
689 if *ch == '-' {
690 if i > 0 && !chars[i - 1].is_whitespace() && chars[i - 1] != '(' {
692 new_result.push(' ');
693 new_result.push(*ch);
694 new_result.push(' ');
695 } else {
696 new_result.push(*ch);
698 }
699 } else {
700 new_result.push(*ch);
701 }
702 }
703 result = new_result;
704
705 result = result.replace("*", " * ");
706 result = result.replace("/", " / ");
707 result = result.replace("%", " % ");
708
709 while result.contains(" ") {
711 result = result.replace(" ", " ");
712 }
713
714 result.trim().to_string()
715 }
716
717 fn infer_return_type(&self, body: &str) -> String {
725 if body.contains('?') && body.contains(':') {
727 return "i32".to_string();
730 }
731
732 if body.contains("&&") || body.contains("||") {
734 return "bool".to_string();
735 }
736
737 if (body.contains('>') || body.contains('<') || body.contains("==") || body.contains("!="))
739 && !body.contains('?')
740 {
741 "bool".to_string()
743 } else {
744 "i32".to_string()
746 }
747 }
748
749 fn infer_macro_type(&self, body: &str) -> anyhow::Result<(String, String)> {
779 let body = body.trim();
780
781 if body.starts_with('"') && body.ends_with('"') {
783 return Ok(("&str".to_string(), body.to_string()));
784 }
785
786 if body.starts_with('\'') && body.ends_with('\'') {
788 return Ok(("char".to_string(), body.to_string()));
789 }
790
791 if body.contains('.') || body.contains('e') || body.contains('E') {
793 return Ok(("f64".to_string(), body.to_string()));
794 }
795
796 if body.starts_with("0x") || body.starts_with("0X") {
798 return Ok(("i32".to_string(), body.to_string()));
799 }
800
801 if body.starts_with('0')
803 && body.len() > 1
804 && body.chars().nth(1).expect("len>1").is_ascii_digit()
805 {
806 return Ok(("i32".to_string(), body.to_string()));
807 }
808
809 if body.parse::<i32>().is_ok() {
811 return Ok(("i32".to_string(), body.to_string()));
812 }
813
814 Ok(("i32".to_string(), body.to_string()))
816 }
817
818 pub fn box_transformer(&self) -> &box_transform::BoxTransformer {
820 &self.box_transformer
821 }
822
823 pub fn map_type(hir_type: &HirType) -> String {
836 match hir_type {
837 HirType::Void => "()".to_string(),
838 HirType::Bool => "bool".to_string(),
839 HirType::Int => "i32".to_string(),
840 HirType::UnsignedInt => "u32".to_string(), HirType::Float => "f32".to_string(),
842 HirType::Double => "f64".to_string(),
843 HirType::Char => "u8".to_string(),
844 HirType::SignedChar => "i8".to_string(), HirType::Pointer(inner) => {
846 format!("*mut {}", Self::map_type(inner))
847 }
848 HirType::Box(inner) => {
849 format!("Box<{}>", Self::map_type(inner))
850 }
851 HirType::Vec(inner) => {
852 format!("Vec<{}>", Self::map_type(inner))
853 }
854 HirType::Option(inner) => {
855 format!("Option<{}>", Self::map_type(inner))
856 }
857 HirType::Reference { inner, mutable } => {
858 if let HirType::Vec(element_type) = &**inner {
860 let element_str = Self::map_type(element_type);
861 if *mutable {
862 format!("&mut [{}]", element_str)
863 } else {
864 format!("&[{}]", element_str)
865 }
866 } else if *mutable {
867 format!("&mut {}", Self::map_type(inner))
868 } else {
869 format!("&{}", Self::map_type(inner))
870 }
871 }
872 HirType::Struct(name) => name.clone(),
873 HirType::Enum(name) => name.clone(),
874 HirType::Array { element_type, size } => {
875 if let Some(n) = size {
876 format!("[{}; {}]", Self::map_type(element_type), n)
877 } else {
878 format!("[{}]", Self::map_type(element_type))
880 }
881 }
882 HirType::FunctionPointer { param_types, return_type } => {
883 let params: Vec<String> = param_types.iter().map(Self::map_type).collect();
885 let params_str = params.join(", ");
886
887 if matches!(**return_type, HirType::Void) {
889 format!("fn({})", params_str)
890 } else {
891 format!("fn({}) -> {}", params_str, Self::map_type(return_type))
892 }
893 }
894 HirType::StringLiteral => "&str".to_string(),
895 HirType::OwnedString => "String".to_string(),
896 HirType::StringReference => "&str".to_string(),
897 HirType::Union(_) => {
898 "/* Union type */".to_string()
901 }
902 HirType::TypeAlias(name) => name.clone(),
904 }
905 }
906
907 fn map_sizeof_type(&self, c_type_name: &str) -> String {
912 let trimmed = c_type_name.trim();
913
914 match trimmed {
916 "int" => "i32".to_string(),
917 "short" | "short int" => "i16".to_string(),
918 "long" | "long int" => "i64".to_string(),
919 "long long" | "long long int" => "i64".to_string(),
920 "unsigned int" | "unsigned" => "u32".to_string(),
921 "unsigned short" | "unsigned short int" => "u16".to_string(),
922 "unsigned long" | "unsigned long int" => "u64".to_string(),
923 "unsigned long long" | "unsigned long long int" => "u64".to_string(),
924 "unsigned char" => "u8".to_string(),
925 "signed char" => "i8".to_string(),
926 "float" => "f32".to_string(),
927 "double" => "f64".to_string(),
928 "char" => "u8".to_string(),
929 "void" => "()".to_string(),
930 "char*" | "char *" => "*mut u8".to_string(),
932 "int*" | "int *" => "*mut i32".to_string(),
933 "void*" | "void *" => "*mut ()".to_string(),
934 _ => {
935 if let Some(struct_name) = trimmed.strip_prefix("struct ") {
937 struct_name.trim().to_string()
938 } else {
939 trimmed.to_string()
941 }
942 }
943 }
944 }
945
946}
947
948mod expr_gen;
949mod func_gen;
950mod stmt_gen;
951
952impl Default for CodeGenerator {
953 fn default() -> Self {
954 Self::new()
955 }
956}
957
958#[cfg(test)]
959#[path = "codegen_tests.rs"]
960mod codegen_tests;
961
962#[cfg(test)]
963#[path = "property_tests.rs"]
964mod property_tests;
965
966#[cfg(test)]
967#[path = "vec_property_tests.rs"]
968mod vec_property_tests;
969
970#[cfg(test)]
971#[path = "struct_codegen_tests.rs"]
972mod struct_codegen_tests;
973
974#[cfg(test)]
975#[path = "class_codegen_tests.rs"]
976mod class_codegen_tests;
977
978#[cfg(test)]
979#[path = "for_loop_codegen_tests.rs"]
980mod for_loop_codegen_tests;
981
982#[cfg(test)]
983#[path = "string_codegen_tests.rs"]
984mod string_codegen_tests;
985
986#[cfg(test)]
987#[path = "string_property_tests.rs"]
988mod string_property_tests;
989
990#[cfg(test)]
991#[path = "switch_codegen_tests.rs"]
992mod switch_codegen_tests;
993
994#[cfg(test)]
995#[path = "switch_property_tests.rs"]
996mod switch_property_tests;
997
998#[cfg(test)]
999#[path = "global_variable_codegen_tests.rs"]
1000mod global_variable_codegen_tests;
1001
1002#[cfg(test)]
1003#[path = "coverage_tests.rs"]
1004mod coverage_tests;
1005
1006#[cfg(test)]
1007#[path = "pattern_gen_tests.rs"]
1008mod pattern_gen_tests;
1009
1010#[cfg(test)]
1011#[path = "format_specifier_tests.rs"]
1012mod format_specifier_tests;
1013
1014#[cfg(test)]
1015#[path = "expression_coverage_tests.rs"]
1016mod expression_coverage_tests;
1017
1018#[cfg(test)]
1019#[path = "codegen_coverage_tests.rs"]
1020mod codegen_coverage_tests;
1021
1022#[cfg(test)]
1023#[path = "statement_coverage_tests.rs"]
1024mod statement_coverage_tests;
1025
1026#[cfg(test)]
1027#[path = "expression_target_type_tests.rs"]
1028mod expression_target_type_tests;
1029
1030#[cfg(test)]
1031#[path = "expression_deep_branch_tests.rs"]
1032mod expression_deep_branch_tests;
1033
1034#[cfg(test)]
1035#[path = "box_transform_coverage_tests.rs"]
1036mod box_transform_coverage_tests;
1037
1038#[cfg(test)]
1039#[path = "format_and_sig_tests.rs"]
1040mod format_and_sig_tests;
1041
1042#[cfg(test)]
1043#[path = "expr_stmt_deep_tests.rs"]
1044mod expr_stmt_deep_tests;
1045
1046#[cfg(test)]
1047#[path = "expr_codegen_deep2_tests.rs"]
1048mod expr_codegen_deep2_tests;
1049
1050#[cfg(test)]
1051#[path = "expr_target_deep_tests.rs"]
1052mod expr_target_deep_tests;
1053
1054#[cfg(test)]
1055#[path = "codegen_remaining_tests.rs"]
1056mod codegen_remaining_tests;
1057
1058#[cfg(test)]
1065#[path = "type_context_coverage_tests.rs"]
1066mod type_context_coverage_tests;