machine-dialect 0.1.0a1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. machine_dialect/__main__.py +667 -0
  2. machine_dialect/agent/__init__.py +5 -0
  3. machine_dialect/agent/agent.py +360 -0
  4. machine_dialect/ast/__init__.py +95 -0
  5. machine_dialect/ast/ast_node.py +35 -0
  6. machine_dialect/ast/call_expression.py +82 -0
  7. machine_dialect/ast/dict_extraction.py +60 -0
  8. machine_dialect/ast/expressions.py +439 -0
  9. machine_dialect/ast/literals.py +309 -0
  10. machine_dialect/ast/program.py +35 -0
  11. machine_dialect/ast/statements.py +1433 -0
  12. machine_dialect/ast/tests/test_ast_string_representation.py +62 -0
  13. machine_dialect/ast/tests/test_boolean_literal.py +29 -0
  14. machine_dialect/ast/tests/test_collection_hir.py +138 -0
  15. machine_dialect/ast/tests/test_define_statement.py +142 -0
  16. machine_dialect/ast/tests/test_desugar.py +541 -0
  17. machine_dialect/ast/tests/test_foreach_desugar.py +245 -0
  18. machine_dialect/cfg/__init__.py +6 -0
  19. machine_dialect/cfg/config.py +156 -0
  20. machine_dialect/cfg/examples.py +221 -0
  21. machine_dialect/cfg/generate_with_ai.py +187 -0
  22. machine_dialect/cfg/openai_generation.py +200 -0
  23. machine_dialect/cfg/parser.py +94 -0
  24. machine_dialect/cfg/tests/__init__.py +1 -0
  25. machine_dialect/cfg/tests/test_cfg_parser.py +252 -0
  26. machine_dialect/cfg/tests/test_config.py +188 -0
  27. machine_dialect/cfg/tests/test_examples.py +391 -0
  28. machine_dialect/cfg/tests/test_generate_with_ai.py +354 -0
  29. machine_dialect/cfg/tests/test_openai_generation.py +256 -0
  30. machine_dialect/codegen/__init__.py +5 -0
  31. machine_dialect/codegen/bytecode_module.py +89 -0
  32. machine_dialect/codegen/bytecode_serializer.py +300 -0
  33. machine_dialect/codegen/opcodes.py +101 -0
  34. machine_dialect/codegen/register_codegen.py +1996 -0
  35. machine_dialect/codegen/symtab.py +208 -0
  36. machine_dialect/codegen/tests/__init__.py +1 -0
  37. machine_dialect/codegen/tests/test_array_operations_codegen.py +295 -0
  38. machine_dialect/codegen/tests/test_bytecode_serializer.py +185 -0
  39. machine_dialect/codegen/tests/test_register_codegen_ssa.py +324 -0
  40. machine_dialect/codegen/tests/test_symtab.py +418 -0
  41. machine_dialect/codegen/vm_serializer.py +621 -0
  42. machine_dialect/compiler/__init__.py +18 -0
  43. machine_dialect/compiler/compiler.py +197 -0
  44. machine_dialect/compiler/config.py +149 -0
  45. machine_dialect/compiler/context.py +149 -0
  46. machine_dialect/compiler/phases/__init__.py +19 -0
  47. machine_dialect/compiler/phases/bytecode_optimization.py +90 -0
  48. machine_dialect/compiler/phases/codegen.py +40 -0
  49. machine_dialect/compiler/phases/hir_generation.py +39 -0
  50. machine_dialect/compiler/phases/mir_generation.py +86 -0
  51. machine_dialect/compiler/phases/optimization.py +110 -0
  52. machine_dialect/compiler/phases/parsing.py +39 -0
  53. machine_dialect/compiler/pipeline.py +143 -0
  54. machine_dialect/compiler/tests/__init__.py +1 -0
  55. machine_dialect/compiler/tests/test_compiler.py +568 -0
  56. machine_dialect/compiler/vm_runner.py +173 -0
  57. machine_dialect/errors/__init__.py +32 -0
  58. machine_dialect/errors/exceptions.py +369 -0
  59. machine_dialect/errors/messages.py +82 -0
  60. machine_dialect/errors/tests/__init__.py +0 -0
  61. machine_dialect/errors/tests/test_expected_token_errors.py +188 -0
  62. machine_dialect/errors/tests/test_name_errors.py +118 -0
  63. machine_dialect/helpers/__init__.py +0 -0
  64. machine_dialect/helpers/stopwords.py +225 -0
  65. machine_dialect/helpers/validators.py +30 -0
  66. machine_dialect/lexer/__init__.py +9 -0
  67. machine_dialect/lexer/constants.py +23 -0
  68. machine_dialect/lexer/lexer.py +907 -0
  69. machine_dialect/lexer/tests/__init__.py +0 -0
  70. machine_dialect/lexer/tests/helpers.py +86 -0
  71. machine_dialect/lexer/tests/test_apostrophe_identifiers.py +122 -0
  72. machine_dialect/lexer/tests/test_backtick_identifiers.py +140 -0
  73. machine_dialect/lexer/tests/test_boolean_literals.py +108 -0
  74. machine_dialect/lexer/tests/test_case_insensitive_keywords.py +188 -0
  75. machine_dialect/lexer/tests/test_comments.py +200 -0
  76. machine_dialect/lexer/tests/test_double_asterisk_keywords.py +127 -0
  77. machine_dialect/lexer/tests/test_lexer_position.py +113 -0
  78. machine_dialect/lexer/tests/test_list_tokens.py +282 -0
  79. machine_dialect/lexer/tests/test_stopwords.py +80 -0
  80. machine_dialect/lexer/tests/test_strict_equality.py +129 -0
  81. machine_dialect/lexer/tests/test_token.py +41 -0
  82. machine_dialect/lexer/tests/test_tokenization.py +294 -0
  83. machine_dialect/lexer/tests/test_underscore_literals.py +343 -0
  84. machine_dialect/lexer/tests/test_url_literals.py +169 -0
  85. machine_dialect/lexer/tokens.py +487 -0
  86. machine_dialect/linter/__init__.py +10 -0
  87. machine_dialect/linter/__main__.py +144 -0
  88. machine_dialect/linter/linter.py +154 -0
  89. machine_dialect/linter/rules/__init__.py +8 -0
  90. machine_dialect/linter/rules/base.py +112 -0
  91. machine_dialect/linter/rules/statement_termination.py +99 -0
  92. machine_dialect/linter/tests/__init__.py +1 -0
  93. machine_dialect/linter/tests/mdrules/__init__.py +0 -0
  94. machine_dialect/linter/tests/mdrules/test_md101_statement_termination.py +181 -0
  95. machine_dialect/linter/tests/test_linter.py +81 -0
  96. machine_dialect/linter/tests/test_rules.py +110 -0
  97. machine_dialect/linter/tests/test_violations.py +71 -0
  98. machine_dialect/linter/violations.py +51 -0
  99. machine_dialect/mir/__init__.py +69 -0
  100. machine_dialect/mir/analyses/__init__.py +20 -0
  101. machine_dialect/mir/analyses/alias_analysis.py +315 -0
  102. machine_dialect/mir/analyses/dominance_analysis.py +49 -0
  103. machine_dialect/mir/analyses/escape_analysis.py +286 -0
  104. machine_dialect/mir/analyses/loop_analysis.py +272 -0
  105. machine_dialect/mir/analyses/tests/test_type_analysis.py +736 -0
  106. machine_dialect/mir/analyses/type_analysis.py +448 -0
  107. machine_dialect/mir/analyses/use_def_chains.py +232 -0
  108. machine_dialect/mir/basic_block.py +385 -0
  109. machine_dialect/mir/dataflow.py +445 -0
  110. machine_dialect/mir/debug_info.py +208 -0
  111. machine_dialect/mir/hir_to_mir.py +1738 -0
  112. machine_dialect/mir/mir_dumper.py +366 -0
  113. machine_dialect/mir/mir_function.py +167 -0
  114. machine_dialect/mir/mir_instructions.py +1877 -0
  115. machine_dialect/mir/mir_interpreter.py +556 -0
  116. machine_dialect/mir/mir_module.py +225 -0
  117. machine_dialect/mir/mir_printer.py +480 -0
  118. machine_dialect/mir/mir_transformer.py +410 -0
  119. machine_dialect/mir/mir_types.py +367 -0
  120. machine_dialect/mir/mir_validation.py +455 -0
  121. machine_dialect/mir/mir_values.py +268 -0
  122. machine_dialect/mir/optimization_config.py +233 -0
  123. machine_dialect/mir/optimization_pass.py +251 -0
  124. machine_dialect/mir/optimization_pipeline.py +355 -0
  125. machine_dialect/mir/optimizations/__init__.py +84 -0
  126. machine_dialect/mir/optimizations/algebraic_simplification.py +733 -0
  127. machine_dialect/mir/optimizations/branch_prediction.py +372 -0
  128. machine_dialect/mir/optimizations/constant_propagation.py +634 -0
  129. machine_dialect/mir/optimizations/cse.py +398 -0
  130. machine_dialect/mir/optimizations/dce.py +288 -0
  131. machine_dialect/mir/optimizations/inlining.py +551 -0
  132. machine_dialect/mir/optimizations/jump_threading.py +487 -0
  133. machine_dialect/mir/optimizations/licm.py +405 -0
  134. machine_dialect/mir/optimizations/loop_unrolling.py +366 -0
  135. machine_dialect/mir/optimizations/strength_reduction.py +422 -0
  136. machine_dialect/mir/optimizations/tail_call.py +207 -0
  137. machine_dialect/mir/optimizations/tests/test_loop_unrolling.py +483 -0
  138. machine_dialect/mir/optimizations/type_narrowing.py +397 -0
  139. machine_dialect/mir/optimizations/type_specialization.py +447 -0
  140. machine_dialect/mir/optimizations/type_specific.py +906 -0
  141. machine_dialect/mir/optimize_mir.py +89 -0
  142. machine_dialect/mir/pass_manager.py +391 -0
  143. machine_dialect/mir/profiling/__init__.py +26 -0
  144. machine_dialect/mir/profiling/profile_collector.py +318 -0
  145. machine_dialect/mir/profiling/profile_data.py +372 -0
  146. machine_dialect/mir/profiling/profile_reader.py +272 -0
  147. machine_dialect/mir/profiling/profile_writer.py +226 -0
  148. machine_dialect/mir/register_allocation.py +302 -0
  149. machine_dialect/mir/reporting/__init__.py +17 -0
  150. machine_dialect/mir/reporting/optimization_reporter.py +314 -0
  151. machine_dialect/mir/reporting/report_formatter.py +289 -0
  152. machine_dialect/mir/ssa_construction.py +342 -0
  153. machine_dialect/mir/tests/__init__.py +1 -0
  154. machine_dialect/mir/tests/test_algebraic_associativity.py +204 -0
  155. machine_dialect/mir/tests/test_algebraic_complex_patterns.py +221 -0
  156. machine_dialect/mir/tests/test_algebraic_division.py +126 -0
  157. machine_dialect/mir/tests/test_algebraic_simplification.py +863 -0
  158. machine_dialect/mir/tests/test_basic_block.py +425 -0
  159. machine_dialect/mir/tests/test_branch_prediction.py +459 -0
  160. machine_dialect/mir/tests/test_call_lowering.py +168 -0
  161. machine_dialect/mir/tests/test_collection_lowering.py +604 -0
  162. machine_dialect/mir/tests/test_cross_block_constant_propagation.py +255 -0
  163. machine_dialect/mir/tests/test_custom_passes.py +166 -0
  164. machine_dialect/mir/tests/test_debug_info.py +285 -0
  165. machine_dialect/mir/tests/test_dict_extraction_lowering.py +192 -0
  166. machine_dialect/mir/tests/test_dictionary_lowering.py +299 -0
  167. machine_dialect/mir/tests/test_double_negation.py +231 -0
  168. machine_dialect/mir/tests/test_escape_analysis.py +233 -0
  169. machine_dialect/mir/tests/test_hir_to_mir.py +465 -0
  170. machine_dialect/mir/tests/test_hir_to_mir_complete.py +389 -0
  171. machine_dialect/mir/tests/test_hir_to_mir_simple.py +130 -0
  172. machine_dialect/mir/tests/test_inlining.py +435 -0
  173. machine_dialect/mir/tests/test_licm.py +472 -0
  174. machine_dialect/mir/tests/test_mir_dumper.py +313 -0
  175. machine_dialect/mir/tests/test_mir_instructions.py +445 -0
  176. machine_dialect/mir/tests/test_mir_module.py +860 -0
  177. machine_dialect/mir/tests/test_mir_printer.py +387 -0
  178. machine_dialect/mir/tests/test_mir_types.py +123 -0
  179. machine_dialect/mir/tests/test_mir_types_enhanced.py +132 -0
  180. machine_dialect/mir/tests/test_mir_validation.py +378 -0
  181. machine_dialect/mir/tests/test_mir_values.py +168 -0
  182. machine_dialect/mir/tests/test_one_based_indexing.py +202 -0
  183. machine_dialect/mir/tests/test_optimization_helpers.py +60 -0
  184. machine_dialect/mir/tests/test_optimization_pipeline.py +554 -0
  185. machine_dialect/mir/tests/test_optimization_reporter.py +318 -0
  186. machine_dialect/mir/tests/test_pass_manager.py +294 -0
  187. machine_dialect/mir/tests/test_pass_registration.py +64 -0
  188. machine_dialect/mir/tests/test_profiling.py +356 -0
  189. machine_dialect/mir/tests/test_register_allocation.py +307 -0
  190. machine_dialect/mir/tests/test_report_formatters.py +372 -0
  191. machine_dialect/mir/tests/test_ssa_construction.py +433 -0
  192. machine_dialect/mir/tests/test_tail_call.py +236 -0
  193. machine_dialect/mir/tests/test_type_annotated_instructions.py +192 -0
  194. machine_dialect/mir/tests/test_type_narrowing.py +277 -0
  195. machine_dialect/mir/tests/test_type_specialization.py +421 -0
  196. machine_dialect/mir/tests/test_type_specific_optimization.py +545 -0
  197. machine_dialect/mir/tests/test_type_specific_optimization_advanced.py +382 -0
  198. machine_dialect/mir/type_inference.py +368 -0
  199. machine_dialect/parser/__init__.py +12 -0
  200. machine_dialect/parser/enums.py +45 -0
  201. machine_dialect/parser/parser.py +3655 -0
  202. machine_dialect/parser/protocols.py +11 -0
  203. machine_dialect/parser/symbol_table.py +169 -0
  204. machine_dialect/parser/tests/__init__.py +0 -0
  205. machine_dialect/parser/tests/helper_functions.py +193 -0
  206. machine_dialect/parser/tests/test_action_statements.py +334 -0
  207. machine_dialect/parser/tests/test_boolean_literal_expressions.py +152 -0
  208. machine_dialect/parser/tests/test_call_statements.py +154 -0
  209. machine_dialect/parser/tests/test_call_statements_errors.py +187 -0
  210. machine_dialect/parser/tests/test_collection_mutations.py +264 -0
  211. machine_dialect/parser/tests/test_conditional_expressions.py +343 -0
  212. machine_dialect/parser/tests/test_define_integration.py +468 -0
  213. machine_dialect/parser/tests/test_define_statements.py +311 -0
  214. machine_dialect/parser/tests/test_dict_extraction.py +115 -0
  215. machine_dialect/parser/tests/test_empty_literal.py +155 -0
  216. machine_dialect/parser/tests/test_float_literal_expressions.py +163 -0
  217. machine_dialect/parser/tests/test_identifier_expressions.py +57 -0
  218. machine_dialect/parser/tests/test_if_empty_block.py +61 -0
  219. machine_dialect/parser/tests/test_if_statements.py +299 -0
  220. machine_dialect/parser/tests/test_illegal_tokens.py +86 -0
  221. machine_dialect/parser/tests/test_infix_expressions.py +680 -0
  222. machine_dialect/parser/tests/test_integer_literal_expressions.py +137 -0
  223. machine_dialect/parser/tests/test_interaction_statements.py +269 -0
  224. machine_dialect/parser/tests/test_list_literals.py +277 -0
  225. machine_dialect/parser/tests/test_no_none_in_ast.py +94 -0
  226. machine_dialect/parser/tests/test_panic_mode_recovery.py +171 -0
  227. machine_dialect/parser/tests/test_parse_errors.py +114 -0
  228. machine_dialect/parser/tests/test_possessive_syntax.py +182 -0
  229. machine_dialect/parser/tests/test_prefix_expressions.py +415 -0
  230. machine_dialect/parser/tests/test_program.py +13 -0
  231. machine_dialect/parser/tests/test_return_statements.py +89 -0
  232. machine_dialect/parser/tests/test_set_statements.py +152 -0
  233. machine_dialect/parser/tests/test_strict_equality.py +258 -0
  234. machine_dialect/parser/tests/test_symbol_table.py +217 -0
  235. machine_dialect/parser/tests/test_url_literal_expressions.py +209 -0
  236. machine_dialect/parser/tests/test_utility_statements.py +423 -0
  237. machine_dialect/parser/token_buffer.py +159 -0
  238. machine_dialect/repl/__init__.py +3 -0
  239. machine_dialect/repl/repl.py +426 -0
  240. machine_dialect/repl/tests/__init__.py +0 -0
  241. machine_dialect/repl/tests/test_repl.py +606 -0
  242. machine_dialect/semantic/__init__.py +12 -0
  243. machine_dialect/semantic/analyzer.py +906 -0
  244. machine_dialect/semantic/error_messages.py +189 -0
  245. machine_dialect/semantic/tests/__init__.py +1 -0
  246. machine_dialect/semantic/tests/test_analyzer.py +364 -0
  247. machine_dialect/semantic/tests/test_error_messages.py +104 -0
  248. machine_dialect/tests/edge_cases/__init__.py +10 -0
  249. machine_dialect/tests/edge_cases/test_boundary_access.py +256 -0
  250. machine_dialect/tests/edge_cases/test_empty_collections.py +166 -0
  251. machine_dialect/tests/edge_cases/test_invalid_operations.py +243 -0
  252. machine_dialect/tests/edge_cases/test_named_list_edge_cases.py +295 -0
  253. machine_dialect/tests/edge_cases/test_nested_structures.py +313 -0
  254. machine_dialect/tests/edge_cases/test_type_mixing.py +277 -0
  255. machine_dialect/tests/integration/test_array_operations_emulation.py +248 -0
  256. machine_dialect/tests/integration/test_list_compilation.py +395 -0
  257. machine_dialect/tests/integration/test_lists_and_dictionaries.py +322 -0
  258. machine_dialect/type_checking/__init__.py +21 -0
  259. machine_dialect/type_checking/tests/__init__.py +1 -0
  260. machine_dialect/type_checking/tests/test_type_system.py +230 -0
  261. machine_dialect/type_checking/type_system.py +270 -0
  262. machine_dialect-0.1.0a1.dist-info/METADATA +128 -0
  263. machine_dialect-0.1.0a1.dist-info/RECORD +268 -0
  264. machine_dialect-0.1.0a1.dist-info/WHEEL +5 -0
  265. machine_dialect-0.1.0a1.dist-info/entry_points.txt +3 -0
  266. machine_dialect-0.1.0a1.dist-info/licenses/LICENSE +201 -0
  267. machine_dialect-0.1.0a1.dist-info/top_level.txt +2 -0
  268. machine_dialect_vm/__init__.pyi +15 -0
@@ -0,0 +1,736 @@
1
+ """Unit tests for type analysis module."""
2
+
3
+ import pytest
4
+
5
+ from machine_dialect.mir.analyses.type_analysis import (
6
+ GenericType,
7
+ TypeAnalysis,
8
+ TypeConstraint,
9
+ TypeEnvironment,
10
+ TypeInfo,
11
+ )
12
+ from machine_dialect.mir.basic_block import BasicBlock
13
+ from machine_dialect.mir.mir_function import MIRFunction
14
+ from machine_dialect.mir.mir_instructions import (
15
+ BinaryOp,
16
+ Call,
17
+ Copy,
18
+ LoadConst,
19
+ Phi,
20
+ UnaryOp,
21
+ )
22
+ from machine_dialect.mir.mir_types import MIRType, MIRUnionType
23
+ from machine_dialect.mir.mir_values import Constant, MIRValue, Temp, Variable
24
+ from machine_dialect.mir.optimization_pass import PassInfo, PassType, PreservationLevel
25
+
26
+
27
+ class TestTypeConstraint:
28
+ """Tests for TypeConstraint enum."""
29
+
30
+ def test_constraint_values(self) -> None:
31
+ """Test that all constraint types are defined."""
32
+ assert TypeConstraint.ANY is not None
33
+ assert TypeConstraint.NUMERIC is not None
34
+ assert TypeConstraint.COMPARABLE is not None
35
+ assert TypeConstraint.CALLABLE is not None
36
+ assert TypeConstraint.ITERABLE is not None
37
+
38
+ def test_constraint_uniqueness(self) -> None:
39
+ """Test that constraint values are unique."""
40
+ constraints = [
41
+ TypeConstraint.ANY,
42
+ TypeConstraint.NUMERIC,
43
+ TypeConstraint.COMPARABLE,
44
+ TypeConstraint.CALLABLE,
45
+ TypeConstraint.ITERABLE,
46
+ ]
47
+ assert len(constraints) == len(set(constraints))
48
+
49
+
50
+ class TestGenericType:
51
+ """Tests for GenericType class."""
52
+
53
+ def test_initialization(self) -> None:
54
+ """Test GenericType initialization."""
55
+ generic = GenericType("T")
56
+ assert generic.name == "T"
57
+ assert generic.constraint == TypeConstraint.ANY
58
+ assert generic.concrete_type is None
59
+
60
+ def test_initialization_with_constraint(self) -> None:
61
+ """Test GenericType initialization with constraint."""
62
+ generic = GenericType("T", TypeConstraint.NUMERIC)
63
+ assert generic.name == "T"
64
+ assert generic.constraint == TypeConstraint.NUMERIC
65
+ assert generic.concrete_type is None
66
+
67
+ def test_is_bound_unbound(self) -> None:
68
+ """Test is_bound returns False for unbound type."""
69
+ generic = GenericType("T")
70
+ assert not generic.is_bound()
71
+
72
+ def test_is_bound_bound(self) -> None:
73
+ """Test is_bound returns True for bound type."""
74
+ generic = GenericType("T")
75
+ generic.concrete_type = MIRType.INT
76
+ assert generic.is_bound()
77
+
78
+ def test_bind_to_compatible_type(self) -> None:
79
+ """Test binding to compatible type."""
80
+ generic = GenericType("T", TypeConstraint.NUMERIC)
81
+ assert generic.bind(MIRType.INT)
82
+ assert generic.concrete_type == MIRType.INT
83
+
84
+ def test_bind_to_incompatible_type(self) -> None:
85
+ """Test binding to incompatible type."""
86
+ generic = GenericType("T", TypeConstraint.NUMERIC)
87
+ assert not generic.bind(MIRType.STRING)
88
+ assert generic.concrete_type is None
89
+
90
+ def test_bind_already_bound_same_type(self) -> None:
91
+ """Test binding already bound type to same type."""
92
+ generic = GenericType("T")
93
+ assert generic.bind(MIRType.INT)
94
+ assert generic.bind(MIRType.INT) # Should succeed
95
+ assert generic.concrete_type == MIRType.INT
96
+
97
+ def test_bind_already_bound_different_type(self) -> None:
98
+ """Test binding already bound type to different type."""
99
+ generic = GenericType("T")
100
+ assert generic.bind(MIRType.INT)
101
+ assert not generic.bind(MIRType.STRING) # Should fail
102
+ assert generic.concrete_type == MIRType.INT
103
+
104
+ def test_satisfies_constraint_any(self) -> None:
105
+ """Test ANY constraint accepts all types."""
106
+ generic = GenericType("T", TypeConstraint.ANY)
107
+ assert generic._satisfies_constraint(MIRType.INT)
108
+ assert generic._satisfies_constraint(MIRType.STRING)
109
+ assert generic._satisfies_constraint(MIRType.BOOL)
110
+
111
+ def test_satisfies_constraint_numeric(self) -> None:
112
+ """Test NUMERIC constraint accepts only numeric types."""
113
+ generic = GenericType("T", TypeConstraint.NUMERIC)
114
+ assert generic._satisfies_constraint(MIRType.INT)
115
+ assert generic._satisfies_constraint(MIRType.FLOAT)
116
+ assert not generic._satisfies_constraint(MIRType.STRING)
117
+ assert not generic._satisfies_constraint(MIRType.BOOL)
118
+
119
+ def test_satisfies_constraint_comparable(self) -> None:
120
+ """Test COMPARABLE constraint accepts comparable types."""
121
+ generic = GenericType("T", TypeConstraint.COMPARABLE)
122
+ assert generic._satisfies_constraint(MIRType.INT)
123
+ assert generic._satisfies_constraint(MIRType.FLOAT)
124
+ assert generic._satisfies_constraint(MIRType.STRING)
125
+ assert not generic._satisfies_constraint(MIRType.BOOL)
126
+
127
+ def test_satisfies_constraint_callable(self) -> None:
128
+ """Test CALLABLE constraint accepts only function type."""
129
+ generic = GenericType("T", TypeConstraint.CALLABLE)
130
+ assert generic._satisfies_constraint(MIRType.FUNCTION)
131
+ assert not generic._satisfies_constraint(MIRType.INT)
132
+ assert not generic._satisfies_constraint(MIRType.STRING)
133
+
134
+
135
+ class TestTypeInfo:
136
+ """Tests for TypeInfo class."""
137
+
138
+ def test_initialization(self) -> None:
139
+ """Test TypeInfo initialization."""
140
+ type_info = TypeInfo(MIRType.INT)
141
+ assert type_info.base_type == MIRType.INT
142
+ assert not type_info.is_generic
143
+ assert type_info.generic_type is None
144
+ assert not type_info.nullable
145
+ assert type_info.constant_value is None
146
+
147
+ def test_initialization_with_all_fields(self) -> None:
148
+ """Test TypeInfo initialization with all fields."""
149
+ generic = GenericType("T")
150
+ type_info = TypeInfo(
151
+ base_type=MIRType.INT,
152
+ is_generic=True,
153
+ generic_type=generic,
154
+ nullable=True,
155
+ constant_value=42,
156
+ )
157
+ assert type_info.base_type == MIRType.INT
158
+ assert type_info.is_generic
159
+ assert type_info.generic_type == generic
160
+ assert type_info.nullable
161
+ assert type_info.constant_value == 42
162
+
163
+ def test_get_concrete_type_non_generic(self) -> None:
164
+ """Test get_concrete_type for non-generic type."""
165
+ type_info = TypeInfo(MIRType.STRING)
166
+ assert type_info.get_concrete_type() == MIRType.STRING
167
+
168
+ def test_get_concrete_type_unbound_generic(self) -> None:
169
+ """Test get_concrete_type for unbound generic type."""
170
+ generic = GenericType("T")
171
+ type_info = TypeInfo(MIRType.UNKNOWN, is_generic=True, generic_type=generic)
172
+ assert type_info.get_concrete_type() == MIRType.UNKNOWN
173
+
174
+ def test_get_concrete_type_bound_generic(self) -> None:
175
+ """Test get_concrete_type for bound generic type."""
176
+ generic = GenericType("T")
177
+ generic.bind(MIRType.INT)
178
+ type_info = TypeInfo(MIRType.UNKNOWN, is_generic=True, generic_type=generic)
179
+ assert type_info.get_concrete_type() == MIRType.INT
180
+
181
+ def test_union_type(self) -> None:
182
+ """Test TypeInfo with union type."""
183
+ union_type = MIRUnionType([MIRType.INT, MIRType.FLOAT])
184
+ type_info = TypeInfo(union_type)
185
+ assert type_info.base_type == union_type
186
+ assert isinstance(type_info.base_type, MIRUnionType)
187
+
188
+
189
+ class TestTypeEnvironment:
190
+ """Tests for TypeEnvironment class."""
191
+
192
+ def test_initialization(self) -> None:
193
+ """Test TypeEnvironment initialization."""
194
+ env = TypeEnvironment()
195
+ assert env.types == {}
196
+ assert env.generic_bindings == {}
197
+
198
+ def test_get_type_not_present(self) -> None:
199
+ """Test get_type for value not in environment."""
200
+ env = TypeEnvironment()
201
+ value = Variable("x", MIRType.INT)
202
+ assert env.get_type(value) is None
203
+
204
+ def test_set_and_get_type(self) -> None:
205
+ """Test setting and getting type information."""
206
+ env = TypeEnvironment()
207
+ value = Variable("x", MIRType.INT)
208
+ type_info = TypeInfo(MIRType.INT, constant_value=42)
209
+
210
+ env.set_type(value, type_info)
211
+ retrieved = env.get_type(value)
212
+
213
+ assert retrieved is not None
214
+ assert retrieved.base_type == MIRType.INT
215
+ assert retrieved.constant_value == 42
216
+
217
+ def test_merge_empty_environments(self) -> None:
218
+ """Test merging two empty environments."""
219
+ env1 = TypeEnvironment()
220
+ env2 = TypeEnvironment()
221
+ merged = env1.merge(env2)
222
+
223
+ assert merged.types == {}
224
+ assert merged.generic_bindings == {}
225
+
226
+ def test_merge_disjoint_values(self) -> None:
227
+ """Test merging environments with disjoint values."""
228
+ env1 = TypeEnvironment()
229
+ env2 = TypeEnvironment()
230
+
231
+ var1 = Variable("x", MIRType.INT)
232
+ var2 = Variable("y", MIRType.STRING)
233
+
234
+ env1.set_type(var1, TypeInfo(MIRType.INT))
235
+ env2.set_type(var2, TypeInfo(MIRType.STRING))
236
+
237
+ merged = env1.merge(env2)
238
+
239
+ assert merged.get_type(var1) is not None
240
+ assert merged.get_type(var1).base_type == MIRType.INT # type: ignore
241
+ assert merged.get_type(var2) is not None
242
+ assert merged.get_type(var2).base_type == MIRType.STRING # type: ignore
243
+
244
+ def test_merge_same_value_unknown_resolution(self) -> None:
245
+ """Test merging same value where one type is unknown."""
246
+ env1 = TypeEnvironment()
247
+ env2 = TypeEnvironment()
248
+
249
+ var = Variable("x", MIRType.INT)
250
+
251
+ env1.set_type(var, TypeInfo(MIRType.UNKNOWN))
252
+ env2.set_type(var, TypeInfo(MIRType.INT))
253
+
254
+ merged = env1.merge(env2)
255
+
256
+ assert merged.get_type(var) is not None
257
+ assert merged.get_type(var).base_type == MIRType.INT # type: ignore
258
+
259
+ def test_merge_same_value_both_known(self) -> None:
260
+ """Test merging same value where both types are known."""
261
+ env1 = TypeEnvironment()
262
+ env2 = TypeEnvironment()
263
+
264
+ var = Variable("x", MIRType.INT)
265
+
266
+ env1.set_type(var, TypeInfo(MIRType.INT))
267
+ env2.set_type(var, TypeInfo(MIRType.STRING))
268
+
269
+ merged = env1.merge(env2)
270
+
271
+ # Should keep first type when both are known
272
+ assert merged.get_type(var) is not None
273
+ assert merged.get_type(var).base_type == MIRType.INT # type: ignore
274
+
275
+ def test_merge_generic_bindings(self) -> None:
276
+ """Test merging generic bindings."""
277
+ env1 = TypeEnvironment()
278
+ env2 = TypeEnvironment()
279
+
280
+ generic1 = GenericType("T")
281
+ generic2 = GenericType("U")
282
+
283
+ env1.generic_bindings["T"] = generic1
284
+ env2.generic_bindings["U"] = generic2
285
+
286
+ merged = env1.merge(env2)
287
+
288
+ assert "T" in merged.generic_bindings
289
+ assert "U" in merged.generic_bindings
290
+ assert merged.generic_bindings["T"] == generic1
291
+ assert merged.generic_bindings["U"] == generic2
292
+
293
+
294
+ class TestTypeAnalysis:
295
+ """Tests for TypeAnalysis class."""
296
+
297
+ @pytest.fixture
298
+ def analysis(self) -> TypeAnalysis:
299
+ """Create a TypeAnalysis instance."""
300
+ return TypeAnalysis()
301
+
302
+ def test_initialization(self, analysis: TypeAnalysis) -> None:
303
+ """Test TypeAnalysis initialization."""
304
+ assert analysis.environments == {}
305
+ assert not analysis.is_valid()
306
+
307
+ def test_get_info(self, analysis: TypeAnalysis) -> None:
308
+ """Test get_info method."""
309
+ info = analysis.get_info()
310
+
311
+ assert isinstance(info, PassInfo)
312
+ assert info.name == "type-analysis"
313
+ assert info.description == "Enhanced type analysis with generics"
314
+ assert info.pass_type == PassType.ANALYSIS
315
+ assert info.requires == []
316
+ assert info.preserves == PreservationLevel.ALL
317
+
318
+ def test_finalize(self, analysis: TypeAnalysis) -> None:
319
+ """Test finalize method."""
320
+ # Should not raise any exceptions
321
+ analysis.finalize()
322
+
323
+ def test_analyze_load_const(self, analysis: TypeAnalysis) -> None:
324
+ """Test type analysis of LoadConst instruction."""
325
+ function = MIRFunction("test")
326
+ block = BasicBlock("entry")
327
+
328
+ dest = Temp(MIRType.INT)
329
+ inst = LoadConst(dest, 42, source_location=(1, 1))
330
+
331
+ block.add_instruction(inst)
332
+ function.cfg.add_block(block)
333
+ function.cfg.set_entry_block(block)
334
+
335
+ env = analysis.run_on_function(function)
336
+
337
+ type_info = env.get_type(dest)
338
+ assert type_info is not None
339
+ assert type_info.base_type == MIRType.INT
340
+ assert type_info.constant_value == 42
341
+
342
+ def test_analyze_copy(self, analysis: TypeAnalysis) -> None:
343
+ """Test type analysis of Copy instruction."""
344
+ function = MIRFunction("test")
345
+ block = BasicBlock("entry")
346
+
347
+ source = Variable("x", MIRType.STRING)
348
+ dest = Temp(MIRType.STRING)
349
+
350
+ # First set up source type
351
+ const_dest = source
352
+ load_inst = LoadConst(const_dest, "hello", source_location=(1, 1))
353
+
354
+ # Then copy
355
+ copy_inst = Copy(dest, source, source_location=(2, 1))
356
+
357
+ block.add_instruction(load_inst)
358
+ block.add_instruction(copy_inst)
359
+ function.cfg.add_block(block)
360
+ function.cfg.set_entry_block(block)
361
+
362
+ env = analysis.run_on_function(function)
363
+
364
+ type_info = env.get_type(dest)
365
+ assert type_info is not None
366
+ assert type_info.base_type == MIRType.STRING
367
+
368
+ def test_analyze_binary_op_arithmetic(self, analysis: TypeAnalysis) -> None:
369
+ """Test type analysis of arithmetic binary operations."""
370
+ function = MIRFunction("test")
371
+ block = BasicBlock("entry")
372
+
373
+ left = Constant(10, MIRType.INT)
374
+ right = Constant(20, MIRType.INT)
375
+ dest = Temp(MIRType.INT)
376
+
377
+ inst = BinaryOp(dest, "+", left, right, source_location=(1, 1))
378
+
379
+ block.add_instruction(inst)
380
+ function.cfg.add_block(block)
381
+ function.cfg.set_entry_block(block)
382
+
383
+ env = analysis.run_on_function(function)
384
+
385
+ type_info = env.get_type(dest)
386
+ assert type_info is not None
387
+ assert type_info.base_type == MIRType.INT
388
+
389
+ def test_analyze_binary_op_comparison(self, analysis: TypeAnalysis) -> None:
390
+ """Test type analysis of comparison operations."""
391
+ function = MIRFunction("test")
392
+ block = BasicBlock("entry")
393
+
394
+ left = Constant(10, MIRType.INT)
395
+ right = Constant(20, MIRType.INT)
396
+ dest = Temp(MIRType.BOOL)
397
+
398
+ inst = BinaryOp(dest, "<", left, right, source_location=(1, 1))
399
+
400
+ block.add_instruction(inst)
401
+ function.cfg.add_block(block)
402
+ function.cfg.set_entry_block(block)
403
+
404
+ env = analysis.run_on_function(function)
405
+
406
+ type_info = env.get_type(dest)
407
+ assert type_info is not None
408
+ assert type_info.base_type == MIRType.BOOL
409
+
410
+ def test_analyze_binary_op_logical(self, analysis: TypeAnalysis) -> None:
411
+ """Test type analysis of logical operations."""
412
+ function = MIRFunction("test")
413
+ block = BasicBlock("entry")
414
+
415
+ left = Constant(True, MIRType.BOOL)
416
+ right = Constant(False, MIRType.BOOL)
417
+ dest = Temp(MIRType.BOOL)
418
+
419
+ inst = BinaryOp(dest, "and", left, right, source_location=(1, 1))
420
+
421
+ block.add_instruction(inst)
422
+ function.cfg.add_block(block)
423
+ function.cfg.set_entry_block(block)
424
+
425
+ env = analysis.run_on_function(function)
426
+
427
+ type_info = env.get_type(dest)
428
+ assert type_info is not None
429
+ assert type_info.base_type == MIRType.BOOL
430
+
431
+ def test_analyze_binary_op_mixed_numeric(self, analysis: TypeAnalysis) -> None:
432
+ """Test type analysis with mixed int/float operations."""
433
+ function = MIRFunction("test")
434
+ block = BasicBlock("entry")
435
+
436
+ left = Constant(10, MIRType.INT)
437
+ right = Constant(3.14, MIRType.FLOAT)
438
+ dest = Temp(MIRType.FLOAT)
439
+
440
+ inst = BinaryOp(dest, "+", left, right, source_location=(1, 1))
441
+
442
+ block.add_instruction(inst)
443
+ function.cfg.add_block(block)
444
+ function.cfg.set_entry_block(block)
445
+
446
+ env = analysis.run_on_function(function)
447
+
448
+ type_info = env.get_type(dest)
449
+ assert type_info is not None
450
+ assert type_info.base_type == MIRType.FLOAT # Float dominates
451
+
452
+ def test_analyze_binary_op_string_concat(self, analysis: TypeAnalysis) -> None:
453
+ """Test type analysis of string concatenation."""
454
+ function = MIRFunction("test")
455
+ block = BasicBlock("entry")
456
+
457
+ left = Constant("hello", MIRType.STRING)
458
+ right = Constant("world", MIRType.STRING)
459
+ dest = Temp(MIRType.STRING)
460
+
461
+ inst = BinaryOp(dest, "+", left, right, source_location=(1, 1))
462
+
463
+ block.add_instruction(inst)
464
+ function.cfg.add_block(block)
465
+ function.cfg.set_entry_block(block)
466
+
467
+ env = analysis.run_on_function(function)
468
+
469
+ type_info = env.get_type(dest)
470
+ assert type_info is not None
471
+ assert type_info.base_type == MIRType.STRING
472
+
473
+ def test_analyze_unary_op_negation(self, analysis: TypeAnalysis) -> None:
474
+ """Test type analysis of numeric negation."""
475
+ function = MIRFunction("test")
476
+ block = BasicBlock("entry")
477
+
478
+ operand = Constant(42, MIRType.INT)
479
+ dest = Temp(MIRType.INT)
480
+
481
+ inst = UnaryOp(dest, "-", operand, source_location=(1, 1))
482
+
483
+ block.add_instruction(inst)
484
+ function.cfg.add_block(block)
485
+ function.cfg.set_entry_block(block)
486
+
487
+ env = analysis.run_on_function(function)
488
+
489
+ type_info = env.get_type(dest)
490
+ assert type_info is not None
491
+ assert type_info.base_type == MIRType.INT
492
+
493
+ def test_analyze_unary_op_not(self, analysis: TypeAnalysis) -> None:
494
+ """Test type analysis of logical not."""
495
+ function = MIRFunction("test")
496
+ block = BasicBlock("entry")
497
+
498
+ operand = Constant(True, MIRType.BOOL)
499
+ dest = Temp(MIRType.BOOL)
500
+
501
+ inst = UnaryOp(dest, "not", operand, source_location=(1, 1))
502
+
503
+ block.add_instruction(inst)
504
+ function.cfg.add_block(block)
505
+ function.cfg.set_entry_block(block)
506
+
507
+ env = analysis.run_on_function(function)
508
+
509
+ type_info = env.get_type(dest)
510
+ assert type_info is not None
511
+ assert type_info.base_type == MIRType.BOOL
512
+
513
+ def test_analyze_call(self, analysis: TypeAnalysis) -> None:
514
+ """Test type analysis of function call."""
515
+ function = MIRFunction("test")
516
+ block = BasicBlock("entry")
517
+
518
+ args: list[MIRValue] = [Constant("hello", MIRType.STRING)]
519
+ dest = Temp(MIRType.UNKNOWN)
520
+
521
+ inst = Call(dest, "print", args, source_location=(1, 1))
522
+
523
+ block.add_instruction(inst)
524
+ function.cfg.add_block(block)
525
+ function.cfg.set_entry_block(block)
526
+
527
+ env = analysis.run_on_function(function)
528
+
529
+ type_info = env.get_type(dest)
530
+ assert type_info is not None
531
+ assert type_info.base_type == MIRType.UNKNOWN
532
+
533
+ @pytest.mark.skip(
534
+ reason="Control flow graph connectivity issues in the test setup, not problems with the type analysis itself"
535
+ )
536
+ def test_analyze_phi(self, analysis: TypeAnalysis) -> None:
537
+ """Test type analysis of Phi node."""
538
+ function = MIRFunction("test")
539
+
540
+ # Create blocks
541
+ entry = BasicBlock("entry")
542
+ then_block = BasicBlock("then")
543
+ else_block = BasicBlock("else")
544
+ merge = BasicBlock("merge")
545
+
546
+ # Phi node with two incoming values
547
+ dest = Temp(MIRType.INT)
548
+ val1 = Constant(10, MIRType.INT)
549
+ val2 = Constant(20, MIRType.INT)
550
+
551
+ phi = Phi(dest, [(val1, "then"), (val2, "else")], source_location=(1, 1))
552
+
553
+ merge.add_instruction(phi)
554
+
555
+ function.cfg.add_block(entry)
556
+ function.cfg.add_block(then_block)
557
+ function.cfg.add_block(else_block)
558
+ function.cfg.add_block(merge)
559
+ function.cfg.set_entry_block(entry)
560
+
561
+ env = analysis.run_on_function(function)
562
+
563
+ type_info = env.get_type(dest)
564
+ assert type_info is not None
565
+ assert type_info.base_type == MIRType.INT
566
+
567
+ @pytest.mark.skip(
568
+ reason="Control flow graph connectivity issues in the test setup, not problems with the type analysis itself"
569
+ )
570
+ def test_analyze_phi_mixed_numeric(self, analysis: TypeAnalysis) -> None:
571
+ """Test type analysis of Phi with mixed numeric types."""
572
+ function = MIRFunction("test")
573
+
574
+ merge = BasicBlock("merge")
575
+
576
+ dest = Temp(MIRType.FLOAT)
577
+ val1 = Constant(10, MIRType.INT)
578
+ val2 = Constant(3.14, MIRType.FLOAT)
579
+
580
+ phi = Phi(dest, [(val1, "then"), (val2, "else")], source_location=(1, 1))
581
+
582
+ merge.add_instruction(phi)
583
+ function.cfg.add_block(merge)
584
+ function.cfg.set_entry_block(merge)
585
+
586
+ env = analysis.run_on_function(function)
587
+
588
+ type_info = env.get_type(dest)
589
+ assert type_info is not None
590
+ assert type_info.base_type == MIRType.FLOAT # Float dominates
591
+
592
+ def test_analyze_parameters(self, analysis: TypeAnalysis) -> None:
593
+ """Test type analysis of function parameters."""
594
+ function = MIRFunction("test")
595
+
596
+ param1 = Variable("x", MIRType.INT)
597
+ param2 = Variable("y", MIRType.STRING)
598
+ function.params = [param1, param2]
599
+
600
+ block = BasicBlock("entry")
601
+ function.cfg.add_block(block)
602
+ function.cfg.set_entry_block(block)
603
+
604
+ env = analysis.run_on_function(function)
605
+
606
+ type_info1 = env.get_type(param1)
607
+ assert type_info1 is not None
608
+ assert type_info1.base_type == MIRType.INT
609
+ assert not type_info1.nullable
610
+
611
+ type_info2 = env.get_type(param2)
612
+ assert type_info2 is not None
613
+ assert type_info2.base_type == MIRType.STRING
614
+ assert not type_info2.nullable
615
+
616
+ def test_get_analysis_caches_result(self, analysis: TypeAnalysis) -> None:
617
+ """Test that get_analysis caches results."""
618
+ function = MIRFunction("test")
619
+ block = BasicBlock("entry")
620
+ function.cfg.add_block(block)
621
+ function.cfg.set_entry_block(block)
622
+
623
+ # First call should analyze
624
+ env1 = analysis.get_analysis(function)
625
+ assert "test" in analysis.environments
626
+
627
+ # Second call should return cached result
628
+ env2 = analysis.get_analysis(function)
629
+ assert env1 is env2 # Same object
630
+
631
+ def test_get_analysis_reanalyzes_if_invalid(self, analysis: TypeAnalysis) -> None:
632
+ """Test that get_analysis reanalyzes if invalid."""
633
+ function = MIRFunction("test")
634
+ block = BasicBlock("entry")
635
+ function.cfg.add_block(block)
636
+ function.cfg.set_entry_block(block)
637
+
638
+ # First analysis
639
+ analysis.get_analysis(function)
640
+
641
+ # Invalidate
642
+ analysis.invalidate()
643
+ assert not analysis.is_valid()
644
+
645
+ # Should reanalyze
646
+ analysis.get_analysis(function)
647
+ assert analysis.is_valid()
648
+ # Note: First and second analysis results might not be the same object after reanalysis
649
+
650
+ def test_infer_binary_op_unknown_types(self, analysis: TypeAnalysis) -> None:
651
+ """Test binary operation with unknown operand types."""
652
+ type_info = analysis._infer_binary_op_type(
653
+ "+",
654
+ TypeInfo(MIRType.UNKNOWN),
655
+ TypeInfo(MIRType.INT),
656
+ )
657
+ assert type_info.base_type == MIRType.UNKNOWN
658
+
659
+ def test_infer_unary_op_unknown_type(self, analysis: TypeAnalysis) -> None:
660
+ """Test unary operation with unknown operand type."""
661
+ type_info = analysis._infer_unary_op_type(
662
+ "-",
663
+ TypeInfo(MIRType.UNKNOWN),
664
+ )
665
+ assert type_info.base_type == MIRType.UNKNOWN
666
+
667
+ def test_merge_types_empty_list(self, analysis: TypeAnalysis) -> None:
668
+ """Test merging empty list of types."""
669
+ result = analysis._merge_types([])
670
+ assert result.base_type == MIRType.UNKNOWN
671
+
672
+ def test_merge_types_single_type(self, analysis: TypeAnalysis) -> None:
673
+ """Test merging single type."""
674
+ type_info = TypeInfo(MIRType.STRING)
675
+ result = analysis._merge_types([type_info])
676
+ assert result.base_type == MIRType.STRING
677
+
678
+ def test_merge_types_same_types(self, analysis: TypeAnalysis) -> None:
679
+ """Test merging multiple same types."""
680
+ types = [
681
+ TypeInfo(MIRType.BOOL),
682
+ TypeInfo(MIRType.BOOL),
683
+ TypeInfo(MIRType.BOOL),
684
+ ]
685
+ result = analysis._merge_types(types)
686
+ assert result.base_type == MIRType.BOOL
687
+
688
+ def test_merge_types_incompatible(self, analysis: TypeAnalysis) -> None:
689
+ """Test merging incompatible types."""
690
+ types = [
691
+ TypeInfo(MIRType.STRING),
692
+ TypeInfo(MIRType.BOOL),
693
+ TypeInfo(MIRType.INT),
694
+ ]
695
+ result = analysis._merge_types(types)
696
+ assert result.base_type == MIRType.UNKNOWN
697
+ assert result.nullable
698
+
699
+ def test_analyze_complex_function(self, analysis: TypeAnalysis) -> None:
700
+ """Test type analysis on a complex function with multiple blocks."""
701
+ function = MIRFunction("complex")
702
+
703
+ # Create blocks
704
+ entry = BasicBlock("entry")
705
+ loop = BasicBlock("loop")
706
+ exit_block = BasicBlock("exit")
707
+
708
+ # Entry block: initialize counter
709
+ counter = Variable("counter", MIRType.INT)
710
+ init = LoadConst(counter, 0, source_location=(1, 1))
711
+ entry.add_instruction(init)
712
+
713
+ # Loop block: increment counter
714
+ temp1 = Temp(MIRType.INT)
715
+ const_one = Constant(1, MIRType.INT)
716
+ add = BinaryOp(temp1, "+", counter, const_one, source_location=(2, 1))
717
+ loop.add_instruction(add)
718
+
719
+ # Add blocks to CFG
720
+ function.cfg.add_block(entry)
721
+ function.cfg.add_block(loop)
722
+ function.cfg.add_block(exit_block)
723
+ function.cfg.set_entry_block(entry)
724
+
725
+ # Run analysis
726
+ env = analysis.run_on_function(function)
727
+
728
+ # Check types
729
+ counter_type = env.get_type(counter)
730
+ assert counter_type is not None
731
+ assert counter_type.base_type == MIRType.INT
732
+ assert counter_type.constant_value == 0
733
+
734
+ temp_type = env.get_type(temp1)
735
+ assert temp_type is not None
736
+ assert temp_type.base_type == MIRType.INT