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,448 @@
1
+ """Enhanced type analysis for MIR.
2
+
3
+ This module provides advanced type analysis capabilities including
4
+ type inference, type tracking, and generic type support.
5
+ """
6
+
7
+ from dataclasses import dataclass, field
8
+ from enum import Enum, auto
9
+ from typing import Any
10
+
11
+ from machine_dialect.mir.basic_block import BasicBlock
12
+ from machine_dialect.mir.mir_function import MIRFunction
13
+ from machine_dialect.mir.mir_instructions import (
14
+ BinaryOp,
15
+ Call,
16
+ Copy,
17
+ LoadConst,
18
+ MIRInstruction,
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 (
25
+ FunctionAnalysisPass,
26
+ PassInfo,
27
+ PassType,
28
+ PreservationLevel,
29
+ )
30
+
31
+
32
+ class TypeConstraint(Enum):
33
+ """Type constraints for generic types."""
34
+
35
+ ANY = auto() # No constraint
36
+ NUMERIC = auto() # Int or Float
37
+ COMPARABLE = auto() # Supports comparison
38
+ CALLABLE = auto() # Function type
39
+ ITERABLE = auto() # Can be iterated
40
+
41
+
42
+ @dataclass
43
+ class GenericType:
44
+ """Generic type representation.
45
+
46
+ Attributes:
47
+ name: Type variable name (e.g., 'T', 'U').
48
+ constraint: Optional constraint on the type.
49
+ concrete_type: Concrete type when specialized.
50
+ """
51
+
52
+ name: str
53
+ constraint: TypeConstraint = TypeConstraint.ANY
54
+ concrete_type: MIRType | None = None
55
+
56
+ def is_bound(self) -> bool:
57
+ """Check if generic type is bound to concrete type.
58
+
59
+ Returns:
60
+ True if bound to a concrete type, False otherwise.
61
+ """
62
+ return self.concrete_type is not None
63
+
64
+ def bind(self, mir_type: MIRType) -> bool:
65
+ """Bind generic type to concrete type.
66
+
67
+ Args:
68
+ mir_type: The concrete type to bind to.
69
+
70
+ Returns:
71
+ True if binding succeeded, False if incompatible.
72
+ """
73
+ if self.is_bound():
74
+ return self.concrete_type == mir_type
75
+
76
+ # Check constraint compatibility
77
+ if not self._satisfies_constraint(mir_type):
78
+ return False
79
+
80
+ self.concrete_type = mir_type
81
+ return True
82
+
83
+ def _satisfies_constraint(self, mir_type: MIRType) -> bool:
84
+ """Check if type satisfies constraint.
85
+
86
+ Args:
87
+ mir_type: The type to check.
88
+
89
+ Returns:
90
+ True if constraint is satisfied.
91
+ """
92
+ if self.constraint == TypeConstraint.ANY:
93
+ return True
94
+ elif self.constraint == TypeConstraint.NUMERIC:
95
+ return mir_type in (MIRType.INT, MIRType.FLOAT)
96
+ elif self.constraint == TypeConstraint.COMPARABLE:
97
+ return mir_type in (MIRType.INT, MIRType.FLOAT, MIRType.STRING)
98
+ elif self.constraint == TypeConstraint.CALLABLE:
99
+ return mir_type == MIRType.FUNCTION
100
+ else:
101
+ return True
102
+
103
+
104
+ @dataclass
105
+ class TypeInfo:
106
+ """Extended type information for a value.
107
+
108
+ Attributes:
109
+ base_type: The base MIR type.
110
+ is_generic: Whether this is a generic type.
111
+ generic_type: Generic type information if applicable.
112
+ nullable: Whether the value can be null/empty.
113
+ constant_value: Known constant value if any.
114
+ """
115
+
116
+ base_type: MIRType | MIRUnionType
117
+ is_generic: bool = False
118
+ generic_type: GenericType | None = None
119
+ nullable: bool = False
120
+ constant_value: Any = None
121
+
122
+ def get_concrete_type(self) -> MIRType | MIRUnionType:
123
+ """Get the concrete type.
124
+
125
+ Returns:
126
+ The concrete MIR type, or base type if not generic/bound.
127
+ """
128
+ if self.is_generic and self.generic_type and self.generic_type.is_bound():
129
+ concrete = self.generic_type.concrete_type
130
+ if concrete is not None:
131
+ return concrete
132
+ return self.base_type
133
+
134
+
135
+ @dataclass
136
+ class TypeEnvironment:
137
+ """Type environment for tracking value types.
138
+
139
+ Attributes:
140
+ types: Mapping from values to type information.
141
+ generic_bindings: Current generic type bindings.
142
+ """
143
+
144
+ types: dict[MIRValue, TypeInfo] = field(default_factory=dict)
145
+ generic_bindings: dict[str, GenericType] = field(default_factory=dict)
146
+
147
+ def get_type(self, value: MIRValue) -> TypeInfo | None:
148
+ """Get type information for a value.
149
+
150
+ Args:
151
+ value: The value to query.
152
+
153
+ Returns:
154
+ Type information if available, None otherwise.
155
+ """
156
+ return self.types.get(value)
157
+
158
+ def set_type(self, value: MIRValue, type_info: TypeInfo) -> None:
159
+ """Set type information for a value.
160
+
161
+ Args:
162
+ value: The value to set type for.
163
+ type_info: The type information.
164
+ """
165
+ self.types[value] = type_info
166
+
167
+ def merge(self, other: "TypeEnvironment") -> "TypeEnvironment":
168
+ """Merge with another type environment.
169
+
170
+ Args:
171
+ other: The other environment to merge.
172
+
173
+ Returns:
174
+ New environment containing merged type information.
175
+ """
176
+ merged = TypeEnvironment()
177
+
178
+ # Merge types, choosing more specific when possible
179
+ for value in set(self.types.keys()) | set(other.types.keys()):
180
+ if value in self.types and value in other.types:
181
+ # Choose more specific type
182
+ self_type = self.types[value]
183
+ other_type = other.types[value]
184
+
185
+ if self_type.base_type == MIRType.UNKNOWN:
186
+ merged.types[value] = other_type
187
+ elif other_type.base_type == MIRType.UNKNOWN:
188
+ merged.types[value] = self_type
189
+ else:
190
+ # Keep first if both are known
191
+ merged.types[value] = self_type
192
+ elif value in self.types:
193
+ merged.types[value] = self.types[value]
194
+ else:
195
+ merged.types[value] = other.types[value]
196
+
197
+ # Merge generic bindings
198
+ merged.generic_bindings.update(self.generic_bindings)
199
+ merged.generic_bindings.update(other.generic_bindings)
200
+
201
+ return merged
202
+
203
+
204
+ class TypeAnalysis(FunctionAnalysisPass):
205
+ """Enhanced type analysis pass.
206
+
207
+ This analysis provides detailed type information including
208
+ generic types, nullability, and constant values.
209
+ """
210
+
211
+ def __init__(self) -> None:
212
+ """Initialize type analysis."""
213
+ super().__init__()
214
+ self.environments: dict[str, TypeEnvironment] = {}
215
+
216
+ def get_info(self) -> PassInfo:
217
+ """Get pass information.
218
+
219
+ Returns:
220
+ Pass metadata including name, description, and dependencies.
221
+ """
222
+ return PassInfo(
223
+ name="type-analysis",
224
+ description="Enhanced type analysis with generics",
225
+ pass_type=PassType.ANALYSIS,
226
+ requires=[],
227
+ preserves=PreservationLevel.ALL,
228
+ )
229
+
230
+ def finalize(self) -> None:
231
+ """Finalize the analysis.
232
+
233
+ Note:
234
+ Currently performs no finalization actions.
235
+ """
236
+ pass
237
+
238
+ def run_on_function(self, function: MIRFunction) -> TypeEnvironment:
239
+ """Run type analysis on a function.
240
+
241
+ Args:
242
+ function: The function to analyze.
243
+
244
+ Returns:
245
+ Type environment for the function.
246
+ """
247
+ self._analyze_function(function)
248
+ return self.environments.get(function.name, TypeEnvironment())
249
+
250
+ def get_analysis(self, function: MIRFunction) -> TypeEnvironment:
251
+ """Get type analysis results for a function.
252
+
253
+ Args:
254
+ function: The function to analyze.
255
+
256
+ Returns:
257
+ Type environment for the function.
258
+ """
259
+ func_name = function.name
260
+
261
+ if func_name not in self.environments or not self.is_valid():
262
+ self._analyze_function(function)
263
+
264
+ return self.environments.get(func_name, TypeEnvironment())
265
+
266
+ def _analyze_function(self, function: MIRFunction) -> None:
267
+ """Analyze types in a function.
268
+
269
+ Args:
270
+ function: The function to analyze.
271
+ """
272
+ env = TypeEnvironment()
273
+
274
+ # Initialize parameter types
275
+ for param in function.params:
276
+ type_info = TypeInfo(base_type=param.type, nullable=param.type == MIRType.UNKNOWN)
277
+ env.set_type(param, type_info)
278
+
279
+ # Analyze each basic block
280
+ for block in function.cfg.blocks.values():
281
+ self._analyze_block(block, env)
282
+
283
+ # Store the environment
284
+ self.environments[function.name] = env
285
+ self._valid = True
286
+
287
+ def _analyze_block(self, block: BasicBlock, env: TypeEnvironment) -> None:
288
+ """Analyze types in a basic block.
289
+
290
+ Args:
291
+ block: The block to analyze.
292
+ env: Current type environment.
293
+ """
294
+ for inst in block.instructions:
295
+ self._analyze_instruction(inst, env)
296
+
297
+ def _analyze_instruction(self, inst: MIRInstruction, env: TypeEnvironment) -> None:
298
+ """Analyze types for an instruction.
299
+
300
+ Args:
301
+ inst: The instruction to analyze.
302
+ env: Current type environment.
303
+ """
304
+ if isinstance(inst, LoadConst):
305
+ # Constant has known type and value
306
+ type_info = TypeInfo(base_type=inst.constant.type, constant_value=inst.constant.value)
307
+ env.set_type(inst.dest, type_info)
308
+
309
+ elif isinstance(inst, Copy):
310
+ # Copy propagates type
311
+ source_type = env.get_type(inst.source)
312
+ if source_type:
313
+ env.set_type(inst.dest, source_type)
314
+
315
+ elif isinstance(inst, BinaryOp):
316
+ # Infer result type from operands
317
+ left_type = self._get_value_type(inst.left, env)
318
+ right_type = self._get_value_type(inst.right, env)
319
+
320
+ result_type = self._infer_binary_op_type(inst.op, left_type, right_type)
321
+ env.set_type(inst.dest, result_type)
322
+
323
+ elif isinstance(inst, UnaryOp):
324
+ # Infer result type from operand
325
+ operand_type = self._get_value_type(inst.operand, env)
326
+ result_type = self._infer_unary_op_type(inst.op, operand_type)
327
+ env.set_type(inst.dest, result_type)
328
+
329
+ elif isinstance(inst, Call):
330
+ # For now, mark result as unknown
331
+ # In future, could use function signatures
332
+ if inst.dest:
333
+ type_info = TypeInfo(base_type=MIRType.UNKNOWN)
334
+ env.set_type(inst.dest, type_info)
335
+
336
+ elif isinstance(inst, Phi):
337
+ # Phi node merges types from sources
338
+ source_types = [self._get_value_type(source, env) for source, _ in inst.incoming]
339
+
340
+ # Find common type
341
+ merged_type = self._merge_types(source_types)
342
+ env.set_type(inst.dest, merged_type)
343
+
344
+ def _get_value_type(self, value: MIRValue, env: TypeEnvironment) -> TypeInfo:
345
+ """Get type info for a value.
346
+
347
+ Args:
348
+ value: The value to get type for.
349
+ env: Current type environment.
350
+
351
+ Returns:
352
+ Type information from environment or inferred from value.
353
+ """
354
+ # Check environment first
355
+ type_info = env.get_type(value)
356
+ if type_info:
357
+ return type_info
358
+
359
+ # Fall back to basic type
360
+ if isinstance(value, Constant):
361
+ return TypeInfo(base_type=value.type, constant_value=value.value)
362
+ elif isinstance(value, Variable):
363
+ return TypeInfo(base_type=value.type)
364
+ elif isinstance(value, Temp):
365
+ return TypeInfo(base_type=value.type)
366
+ else:
367
+ return TypeInfo(base_type=MIRType.UNKNOWN)
368
+
369
+ def _infer_binary_op_type(self, op: str, left: TypeInfo, right: TypeInfo) -> TypeInfo:
370
+ """Infer result type of binary operation.
371
+
372
+ Args:
373
+ op: The operator.
374
+ left: Left operand type.
375
+ right: Right operand type.
376
+
377
+ Returns:
378
+ Result type information.
379
+ """
380
+ # Comparison operators return boolean
381
+ if op in ("==", "!=", "<", ">", "<=", ">="):
382
+ return TypeInfo(base_type=MIRType.BOOL)
383
+
384
+ # Logical operators work on booleans
385
+ if op in ("and", "or"):
386
+ return TypeInfo(base_type=MIRType.BOOL)
387
+
388
+ # Arithmetic operators
389
+ if op in ("+", "-", "*", "/", "%", "^"):
390
+ # If both are numeric, result is numeric
391
+ if left.base_type in (MIRType.INT, MIRType.FLOAT):
392
+ if right.base_type in (MIRType.INT, MIRType.FLOAT):
393
+ # Float dominates
394
+ if left.base_type == MIRType.FLOAT or right.base_type == MIRType.FLOAT:
395
+ return TypeInfo(base_type=MIRType.FLOAT)
396
+ else:
397
+ return TypeInfo(base_type=MIRType.INT)
398
+
399
+ # String concatenation
400
+ if op == "+" and left.base_type == MIRType.STRING:
401
+ return TypeInfo(base_type=MIRType.STRING)
402
+
403
+ # Default to unknown
404
+ return TypeInfo(base_type=MIRType.UNKNOWN)
405
+
406
+ def _infer_unary_op_type(self, op: str, operand: TypeInfo) -> TypeInfo:
407
+ """Infer result type of unary operation.
408
+
409
+ Args:
410
+ op: The operator.
411
+ operand: Operand type.
412
+
413
+ Returns:
414
+ Result type information.
415
+ """
416
+ if op == "-":
417
+ # Negation preserves numeric type
418
+ if operand.base_type in (MIRType.INT, MIRType.FLOAT):
419
+ return TypeInfo(base_type=operand.base_type)
420
+ elif op == "not":
421
+ # Logical not returns boolean
422
+ return TypeInfo(base_type=MIRType.BOOL)
423
+
424
+ return TypeInfo(base_type=MIRType.UNKNOWN)
425
+
426
+ def _merge_types(self, types: list[TypeInfo]) -> TypeInfo:
427
+ """Merge multiple types into common type.
428
+
429
+ Args:
430
+ types: List of types to merge.
431
+
432
+ Returns:
433
+ Merged type information.
434
+ """
435
+ if not types:
436
+ return TypeInfo(base_type=MIRType.UNKNOWN)
437
+
438
+ # If all same type, return that
439
+ base_types = [t.base_type for t in types]
440
+ if len(set(base_types)) == 1:
441
+ return types[0]
442
+
443
+ # If mix of int and float, return float
444
+ if set(base_types) <= {MIRType.INT, MIRType.FLOAT}:
445
+ return TypeInfo(base_type=MIRType.FLOAT)
446
+
447
+ # Otherwise unknown
448
+ return TypeInfo(base_type=MIRType.UNKNOWN, nullable=True)
@@ -0,0 +1,232 @@
1
+ """Use-def and def-use chain analysis for MIR.
2
+
3
+ This module builds explicit use-def and def-use chains from the SSA form,
4
+ enabling efficient queries for optimization passes.
5
+ """
6
+
7
+ from collections import defaultdict
8
+ from dataclasses import dataclass
9
+
10
+ from machine_dialect.mir.basic_block import BasicBlock
11
+ from machine_dialect.mir.mir_function import MIRFunction
12
+ from machine_dialect.mir.mir_instructions import MIRInstruction
13
+ from machine_dialect.mir.mir_values import MIRValue, Temp, Variable
14
+ from machine_dialect.mir.optimization_pass import (
15
+ FunctionAnalysisPass,
16
+ PassInfo,
17
+ PassType,
18
+ PreservationLevel,
19
+ )
20
+
21
+
22
+ @dataclass
23
+ class UseDefInfo:
24
+ """Use-def information for a value.
25
+
26
+ Attributes:
27
+ value: The MIR value.
28
+ definition: Instruction that defines this value.
29
+ uses: List of instructions that use this value.
30
+ defining_block: Block containing the definition.
31
+ use_blocks: Blocks containing uses.
32
+ """
33
+
34
+ value: MIRValue
35
+ definition: MIRInstruction | None
36
+ uses: list[MIRInstruction]
37
+ defining_block: BasicBlock | None
38
+ use_blocks: list[BasicBlock]
39
+
40
+
41
+ class UseDefChains:
42
+ """Container for use-def and def-use chains."""
43
+
44
+ def __init__(self) -> None:
45
+ """Initialize use-def chains."""
46
+ # Map from value to its use-def info
47
+ self.use_def_map: dict[MIRValue, UseDefInfo] = {}
48
+ # Map from instruction to values it defines
49
+ self.inst_defs: dict[MIRInstruction, list[MIRValue]] = defaultdict(list)
50
+ # Map from instruction to values it uses
51
+ self.inst_uses: dict[MIRInstruction, list[MIRValue]] = defaultdict(list)
52
+
53
+ def get_definition(self, value: MIRValue) -> MIRInstruction | None:
54
+ """Get the instruction that defines a value.
55
+
56
+ Args:
57
+ value: The value to query.
58
+
59
+ Returns:
60
+ Defining instruction or None.
61
+ """
62
+ info = self.use_def_map.get(value)
63
+ return info.definition if info else None
64
+
65
+ def get_uses(self, value: MIRValue) -> list[MIRInstruction]:
66
+ """Get instructions that use a value.
67
+
68
+ Args:
69
+ value: The value to query.
70
+
71
+ Returns:
72
+ List of using instructions.
73
+ """
74
+ info = self.use_def_map.get(value)
75
+ return info.uses if info else []
76
+
77
+ def get_defined_values(self, inst: MIRInstruction) -> list[MIRValue]:
78
+ """Get values defined by an instruction.
79
+
80
+ Args:
81
+ inst: The instruction to query.
82
+
83
+ Returns:
84
+ List of defined values.
85
+ """
86
+ return self.inst_defs.get(inst, [])
87
+
88
+ def get_used_values(self, inst: MIRInstruction) -> list[MIRValue]:
89
+ """Get values used by an instruction.
90
+
91
+ Args:
92
+ inst: The instruction to query.
93
+
94
+ Returns:
95
+ List of used values.
96
+ """
97
+ return self.inst_uses.get(inst, [])
98
+
99
+ def is_dead(self, value: MIRValue) -> bool:
100
+ """Check if a value is dead (has no uses).
101
+
102
+ Args:
103
+ value: The value to check.
104
+
105
+ Returns:
106
+ True if the value has no uses.
107
+ """
108
+ info = self.use_def_map.get(value)
109
+ return info is None or len(info.uses) == 0
110
+
111
+ def has_single_use(self, value: MIRValue) -> bool:
112
+ """Check if a value has exactly one use.
113
+
114
+ Args:
115
+ value: The value to check.
116
+
117
+ Returns:
118
+ True if the value has exactly one use.
119
+ """
120
+ info = self.use_def_map.get(value)
121
+ return info is not None and len(info.uses) == 1
122
+
123
+ def get_num_uses(self, value: MIRValue) -> int:
124
+ """Get the number of uses of a value.
125
+
126
+ Args:
127
+ value: The value to check.
128
+
129
+ Returns:
130
+ Number of uses.
131
+ """
132
+ info = self.use_def_map.get(value)
133
+ return len(info.uses) if info else 0
134
+
135
+
136
+ class UseDefChainsAnalysis(FunctionAnalysisPass):
137
+ """Analysis pass that builds use-def chains."""
138
+
139
+ def get_info(self) -> PassInfo:
140
+ """Get pass information.
141
+
142
+ Returns:
143
+ Pass information.
144
+ """
145
+ return PassInfo(
146
+ name="use-def-chains",
147
+ description="Build use-def and def-use chains",
148
+ pass_type=PassType.ANALYSIS,
149
+ requires=[],
150
+ preserves=PreservationLevel.ALL,
151
+ )
152
+
153
+ def run_on_function(self, function: MIRFunction) -> UseDefChains:
154
+ """Build use-def chains for a function.
155
+
156
+ Args:
157
+ function: The function to analyze.
158
+
159
+ Returns:
160
+ Use-def chains.
161
+ """
162
+ chains = UseDefChains()
163
+
164
+ # Process all blocks
165
+ for block in function.cfg.blocks.values():
166
+ # Process phi nodes
167
+ for phi in block.phi_nodes:
168
+ self._process_instruction(phi, block, chains)
169
+
170
+ # Process regular instructions
171
+ for inst in block.instructions:
172
+ self._process_instruction(inst, block, chains)
173
+
174
+ return chains
175
+
176
+ def _process_instruction(
177
+ self,
178
+ inst: MIRInstruction,
179
+ block: BasicBlock,
180
+ chains: UseDefChains,
181
+ ) -> None:
182
+ """Process a single instruction.
183
+
184
+ Args:
185
+ inst: Instruction to process.
186
+ block: Containing block.
187
+ chains: Chains to update.
188
+ """
189
+ # Process definitions
190
+ for def_val in inst.get_defs():
191
+ if isinstance(def_val, Variable | Temp):
192
+ # Create or update use-def info
193
+ if def_val not in chains.use_def_map:
194
+ chains.use_def_map[def_val] = UseDefInfo(
195
+ value=def_val,
196
+ definition=inst,
197
+ uses=[],
198
+ defining_block=block,
199
+ use_blocks=[],
200
+ )
201
+ else:
202
+ # Update definition (for variables that may be redefined)
203
+ chains.use_def_map[def_val].definition = inst
204
+ chains.use_def_map[def_val].defining_block = block
205
+
206
+ # Record instruction's definitions
207
+ chains.inst_defs[inst].append(def_val)
208
+
209
+ # Process uses
210
+ for use_val in inst.get_uses():
211
+ if isinstance(use_val, Variable | Temp):
212
+ # Create use-def info if needed
213
+ if use_val not in chains.use_def_map:
214
+ chains.use_def_map[use_val] = UseDefInfo(
215
+ value=use_val,
216
+ definition=None, # No definition found yet
217
+ uses=[],
218
+ defining_block=None,
219
+ use_blocks=[],
220
+ )
221
+
222
+ # Add this instruction as a use
223
+ chains.use_def_map[use_val].uses.append(inst)
224
+ if block not in chains.use_def_map[use_val].use_blocks:
225
+ chains.use_def_map[use_val].use_blocks.append(block)
226
+
227
+ # Record instruction's uses
228
+ chains.inst_uses[inst].append(use_val)
229
+
230
+ def finalize(self) -> None:
231
+ """Finalize the pass."""
232
+ pass