mt-lang 0.2.0

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 (258) hide show
  1. checksums.yaml +7 -0
  2. data/.ruby-version +1 -0
  3. data/AUTHORS +3 -0
  4. data/Gemfile +19 -0
  5. data/Gemfile.lock +82 -0
  6. data/LICENSE +21 -0
  7. data/README.md +1208 -0
  8. data/Rakefile +332 -0
  9. data/bin/mtc +8 -0
  10. data/bin/profile-mtc-checks +133 -0
  11. data/bin/tracy-profiler +0 -0
  12. data/docs/build-guide.md +536 -0
  13. data/docs/index.html +2778 -0
  14. data/docs/language-design.md +1519 -0
  15. data/docs/language-manual.md +1534 -0
  16. data/lib/milk_tea/base.rb +49 -0
  17. data/lib/milk_tea/bindings/bindgen/ast_parser.rb +398 -0
  18. data/lib/milk_tea/bindings/bindgen/declaration.rb +319 -0
  19. data/lib/milk_tea/bindings/bindgen/emitter.rb +387 -0
  20. data/lib/milk_tea/bindings/bindgen/overrides.rb +134 -0
  21. data/lib/milk_tea/bindings/bindgen/type_mapper.rb +622 -0
  22. data/lib/milk_tea/bindings/bindgen.rb +207 -0
  23. data/lib/milk_tea/bindings/cli.rb +121 -0
  24. data/lib/milk_tea/bindings/imported_bindings/defaults.rb +210 -0
  25. data/lib/milk_tea/bindings/imported_bindings/generator.rb +1114 -0
  26. data/lib/milk_tea/bindings/imported_bindings/method_source.rb +190 -0
  27. data/lib/milk_tea/bindings/imported_bindings/naming.rb +286 -0
  28. data/lib/milk_tea/bindings/imported_bindings.rb +215 -0
  29. data/lib/milk_tea/bindings/opengl_registry.rb +547 -0
  30. data/lib/milk_tea/bindings/raw_bindings/defaults.rb +1338 -0
  31. data/lib/milk_tea/bindings/raw_bindings.rb +269 -0
  32. data/lib/milk_tea/bindings/steamworks.rb +629 -0
  33. data/lib/milk_tea/bindings/upstream_sources.rb +352 -0
  34. data/lib/milk_tea/bindings/vendored_box2d.rb +79 -0
  35. data/lib/milk_tea/bindings/vendored_c_library.rb +322 -0
  36. data/lib/milk_tea/bindings/vendored_cjson.rb +52 -0
  37. data/lib/milk_tea/bindings/vendored_flecs.rb +78 -0
  38. data/lib/milk_tea/bindings/vendored_glfw.rb +77 -0
  39. data/lib/milk_tea/bindings/vendored_libuv.rb +75 -0
  40. data/lib/milk_tea/bindings/vendored_pcre2.rb +84 -0
  41. data/lib/milk_tea/bindings/vendored_raylib.rb +131 -0
  42. data/lib/milk_tea/bindings/vendored_sdl3.rb +78 -0
  43. data/lib/milk_tea/bindings/vendored_steamworks.rb +71 -0
  44. data/lib/milk_tea/bindings/vendored_tool.rb +71 -0
  45. data/lib/milk_tea/bindings/vendored_tools.rb +23 -0
  46. data/lib/milk_tea/bindings/vendored_tracy.rb +37 -0
  47. data/lib/milk_tea/bindings.rb +23 -0
  48. data/lib/milk_tea/core/ast.rb +311 -0
  49. data/lib/milk_tea/core/async_runtime_installer.rb +28 -0
  50. data/lib/milk_tea/core/binding_types.rb +18 -0
  51. data/lib/milk_tea/core/bindings/attribute_binding.rb +58 -0
  52. data/lib/milk_tea/core/bindings/function_binding.rb +5 -0
  53. data/lib/milk_tea/core/bindings/module_binding.rb +58 -0
  54. data/lib/milk_tea/core/bindings/value_binding.rb +21 -0
  55. data/lib/milk_tea/core/c_backend/aggregate_utils.rb +103 -0
  56. data/lib/milk_tea/core/c_backend/control_flow_emission.rb +412 -0
  57. data/lib/milk_tea/core/c_backend/expressions.rb +468 -0
  58. data/lib/milk_tea/core/c_backend/feature_detection.rb +483 -0
  59. data/lib/milk_tea/core/c_backend/reachability.rb +398 -0
  60. data/lib/milk_tea/core/c_backend/reinterpret.rb +226 -0
  61. data/lib/milk_tea/core/c_backend/runtime_helpers.rb +1080 -0
  62. data/lib/milk_tea/core/c_backend/statements.rb +563 -0
  63. data/lib/milk_tea/core/c_backend/type_collectors.rb +1545 -0
  64. data/lib/milk_tea/core/c_backend/type_declaration.rb +223 -0
  65. data/lib/milk_tea/core/c_backend/type_system.rb +345 -0
  66. data/lib/milk_tea/core/c_backend.rb +287 -0
  67. data/lib/milk_tea/core/compatibility_helpers.rb +79 -0
  68. data/lib/milk_tea/core/compile_time/const_eval.rb +187 -0
  69. data/lib/milk_tea/core/compile_time.rb +329 -0
  70. data/lib/milk_tea/core/control_flow/builder.rb +582 -0
  71. data/lib/milk_tea/core/control_flow/constant_propagation.rb +143 -0
  72. data/lib/milk_tea/core/control_flow/dataflow.rb +74 -0
  73. data/lib/milk_tea/core/control_flow/definite_assignment.rb +79 -0
  74. data/lib/milk_tea/core/control_flow/graph.rb +90 -0
  75. data/lib/milk_tea/core/control_flow/liveness.rb +24 -0
  76. data/lib/milk_tea/core/control_flow/nullability_flow.rb +43 -0
  77. data/lib/milk_tea/core/control_flow/reachability.rb +22 -0
  78. data/lib/milk_tea/core/control_flow/termination.rb +31 -0
  79. data/lib/milk_tea/core/control_flow.rb +34 -0
  80. data/lib/milk_tea/core/cst.rb +48 -0
  81. data/lib/milk_tea/core/cst_builder.rb +19 -0
  82. data/lib/milk_tea/core/ir.rb +85 -0
  83. data/lib/milk_tea/core/keywords.rb +97 -0
  84. data/lib/milk_tea/core/lexer/character_classes.rb +60 -0
  85. data/lib/milk_tea/core/lexer/format_strings.rb +225 -0
  86. data/lib/milk_tea/core/lexer/heredocs.rb +199 -0
  87. data/lib/milk_tea/core/lexer/indentation.rb +62 -0
  88. data/lib/milk_tea/core/lexer/numbers.rb +96 -0
  89. data/lib/milk_tea/core/lexer/recovery.rb +32 -0
  90. data/lib/milk_tea/core/lexer/strings.rb +167 -0
  91. data/lib/milk_tea/core/lexer/symbols.rb +71 -0
  92. data/lib/milk_tea/core/lexer/trivia.rb +53 -0
  93. data/lib/milk_tea/core/lexer.rb +430 -0
  94. data/lib/milk_tea/core/lowering/artifacts.rb +26 -0
  95. data/lib/milk_tea/core/lowering/async/analysis.rb +245 -0
  96. data/lib/milk_tea/core/lowering/async/lowering.rb +1399 -0
  97. data/lib/milk_tea/core/lowering/async/normalization.rb +459 -0
  98. data/lib/milk_tea/core/lowering/async.rb +714 -0
  99. data/lib/milk_tea/core/lowering/block.rb +1052 -0
  100. data/lib/milk_tea/core/lowering/calls.rb +1565 -0
  101. data/lib/milk_tea/core/lowering/declarations.rb +214 -0
  102. data/lib/milk_tea/core/lowering/dyn.rb +206 -0
  103. data/lib/milk_tea/core/lowering/events.rb +1054 -0
  104. data/lib/milk_tea/core/lowering/expressions.rb +1645 -0
  105. data/lib/milk_tea/core/lowering/foreign_cstr.rb +206 -0
  106. data/lib/milk_tea/core/lowering/functions.rb +242 -0
  107. data/lib/milk_tea/core/lowering/loops.rb +1087 -0
  108. data/lib/milk_tea/core/lowering/lowering_context.rb +80 -0
  109. data/lib/milk_tea/core/lowering/proc.rb +419 -0
  110. data/lib/milk_tea/core/lowering/resolve.rb +2516 -0
  111. data/lib/milk_tea/core/lowering/scans.rb +220 -0
  112. data/lib/milk_tea/core/lowering/str_buffer.rb +125 -0
  113. data/lib/milk_tea/core/lowering/utils.rb +1453 -0
  114. data/lib/milk_tea/core/lowering.rb +378 -0
  115. data/lib/milk_tea/core/module_binder.rb +181 -0
  116. data/lib/milk_tea/core/module_loader/errors.rb +21 -0
  117. data/lib/milk_tea/core/module_loader.rb +479 -0
  118. data/lib/milk_tea/core/module_path_resolver.rb +153 -0
  119. data/lib/milk_tea/core/module_roots.rb +88 -0
  120. data/lib/milk_tea/core/parser/attributes.rb +71 -0
  121. data/lib/milk_tea/core/parser/blocks.rb +119 -0
  122. data/lib/milk_tea/core/parser/declarations.rb +749 -0
  123. data/lib/milk_tea/core/parser/expressions.rb +624 -0
  124. data/lib/milk_tea/core/parser/recovery.rb +131 -0
  125. data/lib/milk_tea/core/parser/statements.rb +756 -0
  126. data/lib/milk_tea/core/parser/types.rb +271 -0
  127. data/lib/milk_tea/core/parser.rb +400 -0
  128. data/lib/milk_tea/core/prelude_installer.rb +29 -0
  129. data/lib/milk_tea/core/pretty_printer/ast_formatter.rb +917 -0
  130. data/lib/milk_tea/core/pretty_printer/base_formatter.rb +87 -0
  131. data/lib/milk_tea/core/pretty_printer/ir_formatter.rb +300 -0
  132. data/lib/milk_tea/core/pretty_printer.rb +17 -0
  133. data/lib/milk_tea/core/semantic_analyzer/analysis_context.rb +314 -0
  134. data/lib/milk_tea/core/semantic_analyzer/attributes.rb +184 -0
  135. data/lib/milk_tea/core/semantic_analyzer/calls.rb +992 -0
  136. data/lib/milk_tea/core/semantic_analyzer/expressions.rb +1735 -0
  137. data/lib/milk_tea/core/semantic_analyzer/flow_refinement.rb +355 -0
  138. data/lib/milk_tea/core/semantic_analyzer/foreign_functions.rb +155 -0
  139. data/lib/milk_tea/core/semantic_analyzer/function_binding.rb +354 -0
  140. data/lib/milk_tea/core/semantic_analyzer/generics.rb +383 -0
  141. data/lib/milk_tea/core/semantic_analyzer/interface_conformance.rb +78 -0
  142. data/lib/milk_tea/core/semantic_analyzer/module_context.rb +35 -0
  143. data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +1438 -0
  144. data/lib/milk_tea/core/semantic_analyzer/nullability.rb +421 -0
  145. data/lib/milk_tea/core/semantic_analyzer/statements.rb +1308 -0
  146. data/lib/milk_tea/core/semantic_analyzer/top_level.rb +588 -0
  147. data/lib/milk_tea/core/semantic_analyzer/type_compatibility.rb +307 -0
  148. data/lib/milk_tea/core/semantic_analyzer/type_declaration.rb +851 -0
  149. data/lib/milk_tea/core/semantic_analyzer.rb +327 -0
  150. data/lib/milk_tea/core/token.rb +26 -0
  151. data/lib/milk_tea/core/token_stream.rb +30 -0
  152. data/lib/milk_tea/core/types/layout.rb +243 -0
  153. data/lib/milk_tea/core/types/predicates.rb +609 -0
  154. data/lib/milk_tea/core/types/registry.rb +83 -0
  155. data/lib/milk_tea/core/types/types.rb +1696 -0
  156. data/lib/milk_tea/core/types/visitor.rb +442 -0
  157. data/lib/milk_tea/core.rb +25 -0
  158. data/lib/milk_tea/dap/backends/lldb_dap.rb +158 -0
  159. data/lib/milk_tea/dap/protocol.rb +58 -0
  160. data/lib/milk_tea/dap/server/breakpoints.rb +66 -0
  161. data/lib/milk_tea/dap/server/debug_map.rb +291 -0
  162. data/lib/milk_tea/dap/server/handlers.rb +374 -0
  163. data/lib/milk_tea/dap/server/launch.rb +261 -0
  164. data/lib/milk_tea/dap/server/lldb_backend.rb +380 -0
  165. data/lib/milk_tea/dap/server/pause_diagnostics.rb +109 -0
  166. data/lib/milk_tea/dap/server/utilities.rb +160 -0
  167. data/lib/milk_tea/dap/server/wire.rb +55 -0
  168. data/lib/milk_tea/dap/server.rb +131 -0
  169. data/lib/milk_tea/dap/session.rb +152 -0
  170. data/lib/milk_tea/dap.rb +6 -0
  171. data/lib/milk_tea/lsp/dependency_resolution.rb +52 -0
  172. data/lib/milk_tea/lsp/diagnostics.rb +611 -0
  173. data/lib/milk_tea/lsp/protocol.rb +104 -0
  174. data/lib/milk_tea/lsp/server/call_hierarchy.rb +274 -0
  175. data/lib/milk_tea/lsp/server/code_actions.rb +446 -0
  176. data/lib/milk_tea/lsp/server/code_lens.rb +97 -0
  177. data/lib/milk_tea/lsp/server/completion.rb +1099 -0
  178. data/lib/milk_tea/lsp/server/configuration.rb +167 -0
  179. data/lib/milk_tea/lsp/server/debug_info.rb +45 -0
  180. data/lib/milk_tea/lsp/server/definition.rb +779 -0
  181. data/lib/milk_tea/lsp/server/diagnostics_scheduling.rb +239 -0
  182. data/lib/milk_tea/lsp/server/execute_command.rb +25 -0
  183. data/lib/milk_tea/lsp/server/folding_range.rb +153 -0
  184. data/lib/milk_tea/lsp/server/formatting.rb +575 -0
  185. data/lib/milk_tea/lsp/server/hover.rb +1465 -0
  186. data/lib/milk_tea/lsp/server/inlay_hints.rb +204 -0
  187. data/lib/milk_tea/lsp/server/lifecycle.rb +234 -0
  188. data/lib/milk_tea/lsp/server/linked_editing_range.rb +43 -0
  189. data/lib/milk_tea/lsp/server/on_type_formatting.rb +73 -0
  190. data/lib/milk_tea/lsp/server/progress.rb +47 -0
  191. data/lib/milk_tea/lsp/server/references.rb +433 -0
  192. data/lib/milk_tea/lsp/server/rename.rb +598 -0
  193. data/lib/milk_tea/lsp/server/selection_range.rb +130 -0
  194. data/lib/milk_tea/lsp/server/semantic_tokens.rb +1745 -0
  195. data/lib/milk_tea/lsp/server/signature_help.rb +200 -0
  196. data/lib/milk_tea/lsp/server/text_documents.rb +125 -0
  197. data/lib/milk_tea/lsp/server/type_hierarchy.rb +167 -0
  198. data/lib/milk_tea/lsp/server/utilities.rb +520 -0
  199. data/lib/milk_tea/lsp/server.rb +415 -0
  200. data/lib/milk_tea/lsp/workspace/analysis.rb +209 -0
  201. data/lib/milk_tea/lsp/workspace/caches.rb +260 -0
  202. data/lib/milk_tea/lsp/workspace/collection.rb +98 -0
  203. data/lib/milk_tea/lsp/workspace/definition_index.rb +184 -0
  204. data/lib/milk_tea/lsp/workspace/dependency_graph.rb +282 -0
  205. data/lib/milk_tea/lsp/workspace/store.rb +154 -0
  206. data/lib/milk_tea/lsp/workspace/utilities.rb +490 -0
  207. data/lib/milk_tea/lsp/workspace.rb +127 -0
  208. data/lib/milk_tea/lsp.rb +13 -0
  209. data/lib/milk_tea/packages/atomic_write.rb +63 -0
  210. data/lib/milk_tea/packages/dependency_solver.rb +194 -0
  211. data/lib/milk_tea/packages/graph.rb +139 -0
  212. data/lib/milk_tea/packages/lock.rb +421 -0
  213. data/lib/milk_tea/packages/manager_cli.rb +485 -0
  214. data/lib/milk_tea/packages/manifest.rb +356 -0
  215. data/lib/milk_tea/packages/manifest_editor.rb +134 -0
  216. data/lib/milk_tea/packages/registry_metadata_provider.rb +34 -0
  217. data/lib/milk_tea/packages/registry_store.rb +420 -0
  218. data/lib/milk_tea/packages/services.rb +41 -0
  219. data/lib/milk_tea/packages/source_cache.rb +71 -0
  220. data/lib/milk_tea/packages/source_fetcher.rb +124 -0
  221. data/lib/milk_tea/packages/source_resolver.rb +389 -0
  222. data/lib/milk_tea/packages/version.rb +164 -0
  223. data/lib/milk_tea/packages.rb +16 -0
  224. data/lib/milk_tea/tooling/asset_pack.rb +141 -0
  225. data/lib/milk_tea/tooling/build.rb +1124 -0
  226. data/lib/milk_tea/tooling/build_cache.rb +240 -0
  227. data/lib/milk_tea/tooling/cli.rb +2688 -0
  228. data/lib/milk_tea/tooling/cst_formatter.rb +13 -0
  229. data/lib/milk_tea/tooling/debug_info_formatter.rb +456 -0
  230. data/lib/milk_tea/tooling/debug_map.rb +248 -0
  231. data/lib/milk_tea/tooling/docs_app.rb +369 -0
  232. data/lib/milk_tea/tooling/error_formatter.rb +86 -0
  233. data/lib/milk_tea/tooling/formatter.rb +787 -0
  234. data/lib/milk_tea/tooling/linter/doc_tags.rb +212 -0
  235. data/lib/milk_tea/tooling/linter/fix_engine.rb +237 -0
  236. data/lib/milk_tea/tooling/linter/flow_rules.rb +380 -0
  237. data/lib/milk_tea/tooling/linter/imports_platform.rb +841 -0
  238. data/lib/milk_tea/tooling/linter/release_rules.rb +744 -0
  239. data/lib/milk_tea/tooling/linter/reserved_names.rb +199 -0
  240. data/lib/milk_tea/tooling/linter/rules.rb +593 -0
  241. data/lib/milk_tea/tooling/linter/source_helpers.rb +407 -0
  242. data/lib/milk_tea/tooling/linter/trailing_comma.rb +139 -0
  243. data/lib/milk_tea/tooling/linter/visitors.rb +1286 -0
  244. data/lib/milk_tea/tooling/linter.rb +798 -0
  245. data/lib/milk_tea/tooling/project_scaffold.rb +82 -0
  246. data/lib/milk_tea/tooling/public/css/docs.css +166 -0
  247. data/lib/milk_tea/tooling/public/js/docs.js +94 -0
  248. data/lib/milk_tea/tooling/run.rb +408 -0
  249. data/lib/milk_tea/tooling/templates/wasm_shell.html +48 -0
  250. data/lib/milk_tea/tooling/toolchain_cli.rb +157 -0
  251. data/lib/milk_tea/tooling/views/404.erb +7 -0
  252. data/lib/milk_tea/tooling/views/index.erb +87 -0
  253. data/lib/milk_tea/tooling/views/layout.erb +69 -0
  254. data/lib/milk_tea/tooling/views/module.erb +97 -0
  255. data/lib/milk_tea/tooling/views/stdlib.erb +21 -0
  256. data/lib/milk_tea/tooling.rb +20 -0
  257. data/lib/milk_tea.rb +8 -0
  258. metadata +426 -0
@@ -0,0 +1,1438 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MilkTea
4
+ class SemanticAnalyzer
5
+ class Checker
6
+ private
7
+
8
+ def current_type_params
9
+ @current_type_substitutions || {}
10
+ end
11
+
12
+ def current_type_param_constraints
13
+ @current_type_param_constraints || {}
14
+ end
15
+
16
+ def lookup_value(name, scopes)
17
+ scopes.reverse_each do |scope|
18
+ return scope[name] if scope.key?(name)
19
+ end
20
+
21
+ @ctx.top_level_values[name]
22
+ end
23
+
24
+ def lookup_method(receiver_type, name)
25
+ method = lookup_method_local_or_imported(receiver_type, name)
26
+ return method if method
27
+
28
+ fallback_owner = specialization_lookup_owner
29
+ return nil unless fallback_owner
30
+
31
+ fallback_owner.send(:lookup_method_local_or_imported, receiver_type, name)
32
+ end
33
+
34
+ def lookup_static_method(receiver_type, name)
35
+ static_name = "static:#{name}"
36
+ method = lookup_method_local_or_imported(receiver_type, static_name)
37
+ return method if method
38
+
39
+ fallback_owner = specialization_lookup_owner
40
+ return nil unless fallback_owner
41
+
42
+ fallback_owner.send(:lookup_method_local_or_imported, receiver_type, static_name)
43
+ end
44
+
45
+ def lookup_method_local_or_imported(receiver_type, name)
46
+ dispatch_receiver_type = method_dispatch_receiver_type(receiver_type)
47
+
48
+ method = @ctx.methods.fetch(receiver_type, {})[name]
49
+ method ||= @ctx.methods.fetch(dispatch_receiver_type, {})[name] unless dispatch_receiver_type == receiver_type
50
+ return method if method
51
+
52
+ imported_candidates = []
53
+
54
+ @ctx.imports.each_value do |module_binding|
55
+ imported_method = module_binding.methods.fetch(receiver_type, {})[name]
56
+ if imported_method.nil? && dispatch_receiver_type != receiver_type
57
+ imported_method = module_binding.methods.fetch(dispatch_receiver_type, {})[name]
58
+ end
59
+
60
+ imported_candidates << [module_binding, imported_method] if imported_method
61
+ end
62
+
63
+ if imported_candidates.empty?
64
+ owner_module = reachable_module_binding_for_type(receiver_type)
65
+ return nil unless owner_module
66
+
67
+ return module_binding_method(owner_module, receiver_type, dispatch_receiver_type, name)
68
+ end
69
+
70
+ if imported_candidates.length > 1
71
+ modules = imported_candidates.map { |module_binding, _binding| module_binding.name }.join(", ")
72
+ display_name = name.delete_prefix("static:")
73
+ raise_sema_error("ambiguous imported method #{receiver_type}.#{display_name}; found in modules #{modules}")
74
+ end
75
+
76
+ imported_candidates.first.last
77
+ end
78
+
79
+ def module_binding_method(module_binding, receiver_type, dispatch_receiver_type, name)
80
+ method = module_binding.methods.fetch(receiver_type, {})[name]
81
+ method ||= module_binding.methods.fetch(dispatch_receiver_type, {})[name] unless dispatch_receiver_type == receiver_type
82
+ method
83
+ end
84
+
85
+ def reachable_module_binding_for_type(receiver_type)
86
+ module_name = receiver_type_module_name(receiver_type)
87
+ return nil unless module_name
88
+ return nil if module_name == @ctx.module_name
89
+
90
+ find_reachable_imported_module(module_name)
91
+ end
92
+
93
+ def receiver_type_module_name(receiver_type)
94
+ return receiver_type_module_name(receiver_type.base) if receiver_type.is_a?(Types::Nullable)
95
+ return receiver_type.module_name if receiver_type.respond_to?(:module_name)
96
+
97
+ nil
98
+ end
99
+
100
+ def find_reachable_imported_module(module_name)
101
+ visited = {}
102
+
103
+ @ctx.imports.each_value do |module_binding|
104
+ found = find_reachable_imported_module_from(module_binding, module_name, visited)
105
+ return found if found
106
+ end
107
+
108
+ nil
109
+ end
110
+
111
+ def find_reachable_imported_module_from(module_binding, module_name, visited)
112
+ return nil unless module_binding
113
+ return module_binding if module_binding.name == module_name
114
+ return nil if visited[module_binding.name]
115
+
116
+ visited[module_binding.name] = true
117
+ module_binding.imports.each_value do |imported_module|
118
+ found = find_reachable_imported_module_from(imported_module, module_name, visited)
119
+ return found if found
120
+ end
121
+
122
+ nil
123
+ end
124
+
125
+ def specialization_lookup_owner
126
+ return nil if @current_specialization_owner.nil?
127
+ return nil if @current_specialization_owner.equal?(self)
128
+
129
+ @current_specialization_owner
130
+ end
131
+
132
+ def resolve_interface_ref(interface_ref)
133
+ parts = interface_ref.parts
134
+
135
+ interface = if parts.length == 1
136
+ @ctx.interfaces[parts.first]
137
+ elsif parts.length == 2 && @ctx.imports.key?(parts.first)
138
+ imported_module = @ctx.imports.fetch(parts.first)
139
+ raw = imported_module.interfaces[parts.last]
140
+ if imported_module.private_interface?(parts.last)
141
+ raise_sema_error("#{parts.first}.#{parts.last} is private to module #{imported_module.name}")
142
+ end
143
+ raw
144
+ end
145
+
146
+ raise_sema_error("unknown interface #{interface_ref}", interface_ref) unless interface
147
+
148
+ if interface_ref.type_arguments.any?
149
+ raise_sema_error("interface #{interface.name} is not generic") unless interface.is_a?(GenericInterfaceBinding)
150
+
151
+ arguments = interface_ref.type_arguments.map { |arg| resolve_type_ref(arg) }
152
+ interface.instantiate(arguments)
153
+ else
154
+ raise_sema_error("generic interface #{interface.name} requires type arguments") if interface.is_a?(GenericInterfaceBinding)
155
+
156
+ interface
157
+ end
158
+ end
159
+
160
+ def interface_implementation_key(type)
161
+ return type.definition if type.is_a?(Types::StructInstance)
162
+
163
+ type
164
+ end
165
+
166
+ def type_implements_interface?(type, interface)
167
+ key = interface_implementation_key(type)
168
+ return true if @ctx.implemented_interfaces.fetch(key, []).include?(interface)
169
+
170
+ @ctx.imports.each_value do |module_binding|
171
+ return true if module_binding.implemented_interfaces.fetch(key, []).include?(interface)
172
+ end
173
+
174
+ false
175
+ end
176
+
177
+ def type_satisfies_interface_constraint?(type, interface, available_type_param_constraints: current_type_param_constraints)
178
+ if type.is_a?(Types::TypeVar)
179
+ constraint = available_type_param_constraints[type.name]
180
+ return constraint && constraint.interfaces.include?(interface)
181
+ end
182
+
183
+ type_implements_interface?(type, interface)
184
+ end
185
+
186
+ def validate_type_param_constraint_binding!(constraints, actual_type, context:, available_type_param_constraints: current_type_param_constraints)
187
+ constraints.interfaces.each do |interface|
188
+ next if type_satisfies_interface_constraint?(actual_type, interface, available_type_param_constraints:)
189
+
190
+ raise_sema_error("type #{actual_type} does not implement interface #{interface.name} for #{context}")
191
+ end
192
+ end
193
+
194
+ def validate_generic_type_param_constraints!(generic_type, arguments, context:, available_type_param_constraints: current_type_param_constraints)
195
+ return if generic_type.type_param_constraints.empty?
196
+
197
+ generic_type.type_params.zip(arguments).each do |name, actual_type|
198
+ constraints = generic_type.type_param_constraints[name]
199
+ next unless constraints
200
+
201
+ validate_type_param_constraint_binding!(constraints, actual_type, context:, available_type_param_constraints:)
202
+ end
203
+ end
204
+
205
+ def resolve_type_ref(type_ref, type_params: current_type_params, type_param_constraints: current_type_param_constraints, nested_types: nil)
206
+ base = resolve_non_nullable_type(type_ref, type_params:, type_param_constraints:, nested_types:)
207
+ return base if type_ref.is_a?(AST::FunctionType) || type_ref.is_a?(AST::ProcType) || type_ref.is_a?(AST::TupleType)
208
+
209
+ raise_sema_error("ref types are non-null and cannot be nullable", type_ref) if type_ref.nullable && ref_type?(base)
210
+
211
+ type_ref.nullable ? Types::Registry.nullable(base) : base
212
+ end
213
+
214
+ def resolve_non_nullable_type(type_ref, type_params: {}, type_param_constraints: {}, nested_types: nil)
215
+ if type_ref.is_a?(AST::FunctionType)
216
+ params = type_ref.params.map do |param|
217
+ Types::Registry.parameter(param.name, resolve_type_ref(param.type, type_params:, type_param_constraints:))
218
+ end
219
+ return Types::Registry.function(nil, params:, return_type: resolve_type_ref(type_ref.return_type, type_params:, type_param_constraints:))
220
+ end
221
+
222
+ if type_ref.is_a?(AST::ProcType)
223
+ params = type_ref.params.map do |param|
224
+ Types::Registry.parameter(param.name, resolve_type_ref(param.type, type_params:, type_param_constraints:))
225
+ end
226
+ return Types::Registry.proc(params:, return_type: resolve_type_ref(type_ref.return_type, type_params:, type_param_constraints:))
227
+ end
228
+
229
+ if type_ref.is_a?(AST::DynType)
230
+ interface = resolve_interface_ref(type_ref.interface)
231
+ raise_sema_error("generic interface #{interface.name} requires type arguments") if interface.is_a?(GenericInterfaceBinding)
232
+ type_arguments = interface.type_arguments || []
233
+ type = Types::Dyn.new(interface, type_arguments)
234
+ type = Types::Registry.nullable(type) if type_ref.nullable
235
+ return type
236
+ end
237
+
238
+ if type_ref.is_a?(AST::TupleType)
239
+ names = []
240
+ element_types = []
241
+ type_ref.element_types.each do |et|
242
+ if et.is_a?(AST::Argument)
243
+ names << et.name
244
+ element_types << resolve_type_ref(et.value, type_params:, type_param_constraints:)
245
+ else
246
+ names << nil
247
+ element_types << resolve_type_ref(et, type_params:, type_param_constraints:)
248
+ end
249
+ end
250
+ has_named = names.any?
251
+ return Types::Registry.tuple(element_types, field_names: has_named ? names : nil)
252
+ end
253
+
254
+ parts = type_ref.name.parts
255
+
256
+ if type_ref.arguments.any?
257
+ name = parts.join(".")
258
+ arguments = type_ref.arguments.map { |argument| resolve_type_argument(argument.value, type_params:, type_param_constraints:) }
259
+
260
+ if name != "ref" && arguments.any? { |argument| contains_ref_type?(argument) && !stored_ref_supported_type?(argument) }
261
+ raise_sema_error("ref types cannot be nested inside #{name}", type_ref)
262
+ end
263
+
264
+ if name == "Task"
265
+ validate_generic_type!(name, arguments)
266
+ return Types::Registry.task(arguments[0])
267
+ end
268
+
269
+ if (generic_type = resolve_named_generic_type(parts))
270
+ begin
271
+ validate_generic_type_param_constraints!(generic_type, arguments, context: "type #{generic_type}", available_type_param_constraints: type_param_constraints)
272
+ return generic_type.instantiate(arguments)
273
+ rescue ArgumentError => error
274
+ raise_sema_error(error.message)
275
+ end
276
+ end
277
+
278
+ # Handle types with lifetime params only (no type params)
279
+ if arguments.all? { |a| a.is_a?(Types::LifetimeRef) }
280
+ type = @ctx.types[name]
281
+ if type.is_a?(Types::Struct) && type.lifetime_params&.any?
282
+ lifetime_args = arguments.select { |a| a.is_a?(Types::LifetimeRef) }.map(&:name)
283
+ if lifetime_args.to_set == type.lifetime_params.to_set
284
+ return type
285
+ end
286
+ end
287
+ end
288
+
289
+ validate_generic_type!(name, arguments)
290
+ return Types::Registry.span(arguments.first) if name == "span"
291
+
292
+ return Types::Registry.soa(arguments[0], count: arguments[1].value) if name == "SoA"
293
+
294
+ arguments = [type_ref.lifetime] + arguments if name == "ref" && type_ref.lifetime
295
+ return Types::Registry.generic_instance(name, arguments)
296
+ end
297
+
298
+ if parts.length == 1 && type_ref.lifetime
299
+ raise_sema_error("lifetime annotations are only valid on ref types, got #{type_ref.name}", type_ref)
300
+ end
301
+
302
+ if parts.length == 1
303
+ return type_params.fetch(parts.first) if type_params.key?(parts.first)
304
+
305
+ if nested_types && (type = nested_types[parts.first])
306
+ return type
307
+ end
308
+
309
+ if parts.first.start_with?("@")
310
+ raise_sema_error("unknown lifetime #{parts.first}", type_ref)
311
+ end
312
+
313
+ type = @ctx.types[parts.first]
314
+ unless type
315
+ type_names = @ctx.types.keys
316
+ suggestion = suggest_name(parts.first, type_names)
317
+ unless suggestion
318
+ suggestion = import_suggestion_for_type(parts.first)
319
+ end
320
+ raise_sema_error("unknown type #{parts.first}", type_ref, suggestion: suggestion ? "did you mean '#{suggestion}'?" : nil)
321
+ end
322
+ raise_sema_error("generic type #{parts.first} requires type arguments", type_ref) if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
323
+
324
+ return type
325
+ end
326
+
327
+ if parts.length >= 2
328
+ type = resolve_nested_type_ref(parts)
329
+ return type if type
330
+ end
331
+
332
+ if parts.length == 2 && @ctx.imports.key?(parts.first)
333
+ imported_module = @ctx.imports.fetch(parts.first)
334
+ type = imported_module.types[parts.last]
335
+ if imported_module.private_type?(parts.last)
336
+ raise_sema_error("#{parts.first}.#{parts.last} is private to module #{imported_module.name}", type_ref)
337
+ end
338
+ raise_sema_error("unknown type #{type_ref.name}", type_ref) unless type
339
+ raise_sema_error("generic type #{type_ref.name} requires type arguments", type_ref) if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
340
+
341
+ return type
342
+ end
343
+
344
+ if @compile_time_depth&.positive? && (ct_type = resolve_compile_time_type_ref(type_ref))
345
+ return ct_type
346
+ end
347
+
348
+ raise_sema_error("unknown type #{type_ref.name}", type_ref, suggestion: import_suggestion_for_type(type_ref.name))
349
+ end
350
+
351
+ # Resolves a bare dotted reflection type expression such as `field.type`
352
+ # (where `field` is a compile-time `field_handle` bound in scope) to the
353
+ # concrete `Types::Base` it denotes. Returns nil when the type_ref is not a
354
+ # compile-time type expression resolvable in the current scopes. Only the
355
+ # plain `<local>.member` form is supported (no calls/indexing/type args).
356
+ def resolve_compile_time_type_ref(type_ref)
357
+ return nil unless @type_resolution_scopes
358
+ return nil if type_ref.arguments.any? || type_ref.nullable
359
+
360
+ parts = type_ref.name.parts
361
+ return nil unless parts.length >= 2
362
+
363
+ binding = lookup_value(parts.first, @type_resolution_scopes)
364
+ return nil unless binding && !binding.const_value.nil?
365
+
366
+ expression = AST.build_chain_from_parts(parts)
367
+ return nil unless expression
368
+
369
+ value = evaluate_compile_time_const_value(expression, scopes: @type_resolution_scopes)
370
+ value.is_a?(Types::Base) ? value : nil
371
+ end
372
+
373
+ def resolve_type_argument(argument, type_params: current_type_params, type_param_constraints: current_type_param_constraints)
374
+ case argument
375
+ when AST::TypeRef
376
+ resolve_type_argument_ref(argument, type_params:, type_param_constraints:)
377
+ when AST::FunctionType, AST::ProcType
378
+ resolve_type_ref(argument, type_params:, type_param_constraints:)
379
+ when AST::IntegerLiteral, AST::FloatLiteral
380
+ Types::LiteralTypeArg.new(argument.value)
381
+ else
382
+ raise_sema_error("unsupported type argument #{argument.class.name}")
383
+ end
384
+ end
385
+
386
+ def resolve_type_argument_ref(type_ref, type_params:, type_param_constraints:)
387
+ return resolve_type_ref(type_ref, type_params:, type_param_constraints:) unless literal_type_argument_name_candidate?(type_ref)
388
+
389
+ resolve_type_ref(type_ref, type_params:, type_param_constraints:)
390
+ rescue SemanticError => error
391
+ literal_type_argument = resolve_named_literal_type_argument(type_ref)
392
+ return literal_type_argument if literal_type_argument
393
+
394
+ raise error
395
+ end
396
+
397
+ def literal_type_argument_name_candidate?(type_ref)
398
+ type_ref.arguments.empty? && !type_ref.nullable
399
+ end
400
+
401
+ def resolve_named_literal_type_argument(type_ref)
402
+ value = case type_ref.name.parts.length
403
+ when 1
404
+ resolve_current_module_const_value(type_ref.name.parts.first)
405
+ when 2
406
+ resolve_imported_module_const_value(type_ref.name.parts.first, type_ref.name.parts.last)
407
+ end
408
+
409
+ return unless value.is_a?(Integer) || value.is_a?(Float)
410
+
411
+ Types::LiteralTypeArg.new(value)
412
+ end
413
+
414
+ def resolve_current_module_const_value(name)
415
+ binding = @ctx.top_level_values[name]
416
+ return unless binding&.kind == :const
417
+
418
+ evaluate_top_level_const_value(name)
419
+ end
420
+
421
+ def top_level_function(name)
422
+ @ctx.top_level_functions[name]
423
+ end
424
+
425
+ def resolve_imported_module_const_value(import_name, value_name)
426
+ imported_module = @ctx.imports[import_name]
427
+ return unless imported_module
428
+ if imported_module.private_value?(value_name)
429
+ raise_sema_error("#{import_name}.#{value_name} is private to module #{imported_module.name}")
430
+ end
431
+
432
+ binding = imported_module.values[value_name]
433
+ return unless binding&.kind == :const
434
+
435
+ binding.const_value
436
+ end
437
+
438
+ def resolve_enum_member_const_value(receiver_type, member_name, local_enum_type: nil, local_member_values: nil)
439
+ return unless receiver_type.is_a?(Types::EnumBase)
440
+ return unless receiver_type.member(member_name)
441
+
442
+ if local_enum_type && receiver_type == local_enum_type && local_member_values&.key?(member_name)
443
+ return local_member_values[member_name]
444
+ end
445
+
446
+ receiver_type.member_value(member_name)
447
+ end
448
+
449
+ def ensure_assignable!(actual_type, expected_type, message, expression: nil, scopes: nil, external_numeric: false, external_pointer_null: false, contextual_int_to_float: false, line: nil, column: nil)
450
+ line ||= source_line(expression)
451
+ column ||= source_column(expression)
452
+
453
+ unless types_compatible?(actual_type, expected_type, expression:, scopes:, external_numeric:, external_pointer_null:, contextual_int_to_float:)
454
+ suggestion = explicit_cast_suggestion(actual_type, expected_type)
455
+ raise SemanticError.new(message, line:, column:, path: @path, suggestion:)
456
+ end
457
+ end
458
+
459
+ def explicit_cast_suggestion(actual_type, expected_type)
460
+ if expected_type.is_a?(Types::Span) && array_type?(actual_type) &&
461
+ array_element_type(actual_type) == expected_type.element_type
462
+ return "a span is a mutable view; the array must be a mutable addressable value — bind it with `var` (a `let` array does not coerce)"
463
+ end
464
+
465
+ if castable_primitive?(actual_type) && castable_primitive?(expected_type)
466
+ return nil if actual_type == expected_type
467
+ "use an explicit cast: `#{expected_type}<-(value)`"
468
+ end
469
+
470
+ if actual_type.is_a?(Types::Nullable) && expected_type.is_a?(Types::Nullable)
471
+ explicit_cast_suggestion(actual_type.base, expected_type.base)
472
+ else
473
+ nil
474
+ end
475
+ end
476
+
477
+ def castable_primitive?(type)
478
+ return castable_primitive?(type.base) if type.is_a?(Types::Nullable)
479
+
480
+ type.is_a?(Types::Primitive) || type.is_a?(Types::Enum) || type.is_a?(Types::Flags)
481
+ end
482
+
483
+ def ensure_argument_assignable!(actual_type, expected_type, external:, message:, expression: nil, scopes: nil)
484
+ line = source_line(expression)
485
+ column = source_column(expression)
486
+ unless argument_types_compatible?(actual_type, expected_type, external:, expression:, scopes:)
487
+ suggestion = explicit_cast_suggestion(actual_type, expected_type)
488
+ raise SemanticError.new(message, line:, column:, path: @path, suggestion:)
489
+ end
490
+ end
491
+
492
+ def with_error_node(node)
493
+ @error_node_stack << node
494
+ yield
495
+ ensure
496
+ @error_node_stack.pop
497
+ end
498
+
499
+ def current_error_node
500
+ @error_node_stack.reverse_each.find { |node| !node.nil? }
501
+ end
502
+
503
+ def raise_sema_error(message, node = nil, line: nil, column: nil, length: nil, suggestion: nil)
504
+ target = node || current_error_node
505
+ line ||= source_line(target)
506
+ column ||= source_column(target)
507
+ length ||= source_length(target)
508
+ raise SemanticError.new(message, line:, column:, length:, path: @path, suggestion:)
509
+ end
510
+
511
+ def source_line(node)
512
+ return nil unless node
513
+ return node.line if node.respond_to?(:line) && node.line
514
+
515
+ case node
516
+ when AST::MemberAccess then source_line(node.receiver)
517
+ when AST::IndexAccess then source_line(node.receiver) || source_line(node.index)
518
+ when AST::Specialization then source_line(node.callee)
519
+ when AST::Call then source_line(node.callee) || node.arguments.filter_map { |argument| source_line(argument.value) }.first
520
+ when AST::Argument then source_line(node.value)
521
+ when AST::UnaryOp then source_line(node.operand)
522
+ when AST::BinaryOp then source_line(node.left) || source_line(node.right)
523
+ when AST::IfExpr then source_line(node.condition) || source_line(node.then_expression) || source_line(node.else_expression)
524
+ when AST::MatchExpr then source_line(node.expression) || node.arms.filter_map { |arm| source_line(arm.pattern) || source_line(arm.value) }.first
525
+ when AST::AwaitExpr then source_line(node.expression)
526
+ when AST::FormatExprPart then source_line(node.expression)
527
+ when AST::PrefixCast then source_line(node.target_type)
528
+ else nil
529
+ end
530
+ end
531
+
532
+ def source_length(node)
533
+ return nil unless node
534
+ return node.length if node.respond_to?(:length) && node.length
535
+ return node.name.to_s.length if node.respond_to?(:name) && node.name
536
+
537
+ case node
538
+ when AST::Identifier then node.name.to_s.length
539
+ when AST::MemberAccess then node.member.to_s.length
540
+ when AST::Assignment then source_length(node.target) || source_length(node.value)
541
+ when AST::ExpressionStmt then source_length(node.expression)
542
+ when AST::StaticAssert then source_length(node.condition)
543
+ when AST::IfStmt
544
+ node.branches.filter_map { |branch| branch.length || source_length(branch.condition) }.first
545
+ else
546
+ nil
547
+ end
548
+ end
549
+
550
+ def source_column(node)
551
+ return nil unless node
552
+ return node.column if node.respond_to?(:column) && node.column
553
+
554
+ case node
555
+ when AST::MemberAccess then source_column(node.receiver)
556
+ when AST::IndexAccess then source_column(node.receiver) || source_column(node.index)
557
+ when AST::Specialization then source_column(node.callee)
558
+ when AST::Call then source_column(node.callee) || node.arguments.filter_map { |argument| source_column(argument.value) }.first
559
+ when AST::Argument then source_column(node.value)
560
+ when AST::UnaryOp then source_column(node.operand)
561
+ when AST::BinaryOp then source_column(node.left) || source_column(node.right)
562
+ when AST::IfExpr then source_column(node.condition) || source_column(node.then_expression) || source_column(node.else_expression)
563
+ when AST::MatchExpr then source_column(node.expression) || node.arms.filter_map { |arm| source_column(arm.pattern) || source_column(arm.value) }.first
564
+ when AST::AwaitExpr then source_column(node.expression)
565
+ when AST::FormatExprPart then source_column(node.expression)
566
+ when AST::PrefixCast then source_column(node.target_type)
567
+ when AST::Assignment then source_column(node.target) || source_column(node.value)
568
+ when AST::ExpressionStmt then source_column(node.expression)
569
+ when AST::StaticAssert then source_column(node.condition)
570
+ when AST::IfStmt then node.branches.filter_map { |branch| branch.column || source_column(branch.condition) }.first || node.else_column
571
+ else nil
572
+ end
573
+ end
574
+
575
+
576
+ def span_type?(type)
577
+ type.is_a?(Types::Span)
578
+ end
579
+
580
+ def string_view_type?(type)
581
+ type.is_a?(Types::StringView)
582
+ end
583
+
584
+ def infer_layout_query_type(type_ref, context:)
585
+ type = resolve_type_ref(type_ref)
586
+ return type if sized_layout_type?(type)
587
+
588
+ raise_sema_error("#{context} requires a concrete sized type, got #{type_ref}")
589
+ end
590
+
591
+ def check_layout_type_via_ct(type_ref, context:, scopes:)
592
+ return false unless scopes && type_ref.name.parts.length >= 1
593
+
594
+ first_part = type_ref.name.parts.first
595
+ binding = lookup_value(first_part, scopes)
596
+ return false unless binding && !binding.const_value.nil?
597
+
598
+ expression = AST.build_chain_from_parts(type_ref.name.parts)
599
+ return false unless expression
600
+
601
+ ct_value = evaluate_compile_time_const_value(expression, scopes:)
602
+ if ct_value.is_a?(Types::Struct) || ct_value.is_a?(Types::Primitive) ||
603
+ ct_value.is_a?(Types::Union) || ct_value.is_a?(Types::Nullable) ||
604
+ ct_value.is_a?(Types::StructInstance)
605
+ if sized_layout_type?(ct_value)
606
+ return true
607
+ end
608
+ end
609
+
610
+ false
611
+ end
612
+
613
+
614
+
615
+
616
+ def resolve_and_store_offset(expression, scopes:)
617
+ type = resolve_type_ref(expression.type)
618
+ return unless layout_aggregate_type?(type)
619
+
620
+ binding = lookup_value(expression.field, scopes)
621
+ return unless binding && binding.const_value.is_a?(Types::FieldHandle)
622
+
623
+ offset = CompileTime::Layout.offset_of(type, binding.const_value.field_name)
624
+ return unless offset
625
+
626
+ @const_values[@ctx.ast.node_ids[expression.object_id]] = offset
627
+ end
628
+
629
+ def infer_offsetof_type(type_ref, field_name, scopes: nil)
630
+ type = resolve_type_ref(type_ref)
631
+ unless layout_aggregate_type?(type)
632
+ raise_sema_error("offset_of requires a struct, union, span, or str type, got #{type}")
633
+ end
634
+
635
+ field_type = type.field(field_name)
636
+ return type if field_type
637
+
638
+ if scopes
639
+ binding = lookup_value(field_name, scopes)
640
+ if binding && binding.storage_type.is_a?(Types::ReflectionHandleType) && binding.storage_type.name == "field_handle"
641
+ return type
642
+ end
643
+ end
644
+
645
+ raise_sema_error("unknown field #{type}.#{field_name}")
646
+ end
647
+
648
+ def sized_layout_type?(type)
649
+ case type
650
+ when Types::Primitive, Types::Struct, Types::StructInstance, Types::Union, Types::Enum, Types::Flags, Types::Variant, Types::Span, Types::StringView, Types::Task, Types::Event, Types::Subscription
651
+ true
652
+ when Types::Nullable
653
+ true
654
+ when Types::GenericInstance
655
+ pointer_type?(type) || array_type?(type) || str_buffer_type?(type)
656
+ else
657
+ false
658
+ end
659
+ end
660
+
661
+ def reinterpretable_type?(type)
662
+ return false if array_type?(type)
663
+ return false if type.is_a?(Types::Primitive) && type.void?
664
+
665
+ sized_layout_type?(type)
666
+ end
667
+
668
+ def zero_initializable_type?(type, operation: "zero")
669
+ return true if type.is_a?(Types::Primitive) && !type.void?
670
+ return true if type.is_a?(Types::Nullable)
671
+ return true if type.is_a?(Types::EnumBase)
672
+ return true if span_type?(type)
673
+ return true if string_view_type?(type)
674
+ return true if task_type?(type)
675
+ return true if event_type?(type)
676
+ return true if subscription_type?(type)
677
+ return true if type.is_a?(Types::Struct)
678
+ return true if type.is_a?(Types::Variant)
679
+ return true if pointer_type?(type)
680
+ return true if type.is_a?(Types::Opaque) && !type.external
681
+ return true if array_type?(type)
682
+ return true if str_buffer_type?(type)
683
+ return true if vector_type?(type)
684
+ return true if matrix_type?(type)
685
+ return true if quaternion_type?(type)
686
+ return true if soa_type?(type)
687
+ return true if atomic_type?(type)
688
+
689
+ raise_sema_error("#{operation} does not support type #{type}")
690
+ end
691
+
692
+ def layout_aggregate_type?(type)
693
+ type.respond_to?(:field) && !type.is_a?(Types::Opaque) && !type.is_a?(Types::EnumBase)
694
+ end
695
+
696
+ def power_of_two?(value)
697
+ (value & (value - 1)).zero?
698
+ end
699
+
700
+ def aggregate_type?(type)
701
+ type.is_a?(Types::Struct) || type.is_a?(Types::Tuple) || span_type?(type) || string_view_type?(type) || task_type?(type) || vector_type?(type) || matrix_type?(type) || quaternion_type?(type)
702
+ end
703
+
704
+ def vector_type?(type)
705
+ type.is_a?(Types::Vector)
706
+ end
707
+
708
+ def matrix_type?(type)
709
+ type.is_a?(Types::Matrix)
710
+ end
711
+
712
+ def quaternion_type?(type)
713
+ type.is_a?(Types::Quaternion)
714
+ end
715
+
716
+ def soa_type?(type)
717
+ type.is_a?(Types::SoA)
718
+ end
719
+
720
+ def array_type?(type)
721
+ type.is_a?(Types::GenericInstance) && type.name == "array" && type.arguments.length == 2 &&
722
+ !type.arguments.first.is_a?(Types::LiteralTypeArg) && type.arguments[1].is_a?(Types::LiteralTypeArg)
723
+ end
724
+
725
+ def array_element_type(type)
726
+ return unless array_type?(type)
727
+
728
+ type.arguments.first
729
+ end
730
+
731
+ def array_length(type)
732
+ return unless array_type?(type)
733
+
734
+ type.arguments[1].value
735
+ end
736
+
737
+ def char_array_text_type?(type)
738
+ array_type?(type) && array_element_type(type) == @ctx.types.fetch("char")
739
+ end
740
+
741
+ def str_buffer_type?(type)
742
+ type.is_a?(Types::GenericInstance) && type.name == "str_buffer" && type.arguments.length == 1 &&
743
+ generic_integer_type_argument?(type.arguments.first)
744
+ end
745
+
746
+ def event_type?(type)
747
+ type.is_a?(Types::Event)
748
+ end
749
+
750
+ def atomic_type?(type)
751
+ type.is_a?(Types::GenericInstance) && type.name == "atomic" && type.arguments.length == 1
752
+ end
753
+
754
+ def atomic_element_type(type)
755
+ type.arguments.first
756
+ end
757
+
758
+ def subscription_type?(type)
759
+ type.is_a?(Types::Subscription)
760
+ end
761
+
762
+ def event_carrier_type?(type)
763
+ case type
764
+ when Types::StructInstance
765
+ type.definition.respond_to?(:has_events?) && type.definition.has_events?
766
+ when Types::Struct
767
+ type.respond_to?(:has_events?) && type.has_events?
768
+ else
769
+ false
770
+ end
771
+ end
772
+
773
+ def noncopyable_event_storage_type?(type)
774
+ event_type?(type) || event_carrier_type?(type)
775
+ end
776
+
777
+ def str_buffer_capacity(type)
778
+ type.arguments.first.value
779
+ end
780
+
781
+ def integer_type_argument?(argument)
782
+ argument.is_a?(Types::LiteralTypeArg) && argument.value.is_a?(Integer)
783
+ end
784
+
785
+ def generic_integer_type_argument?(argument)
786
+ integer_type_argument?(argument) || argument.is_a?(Types::TypeVar)
787
+ end
788
+
789
+ def pointer_to(type)
790
+ Types.pointer_to(type)
791
+ end
792
+
793
+ def contains_type_var?(type)
794
+ super
795
+ end
796
+
797
+ def resolve_nested_type_ref(parts)
798
+ current = @ctx.types[parts.first]
799
+ return nil unless current.is_a?(Types::Struct) || current.is_a?(Types::GenericStructDefinition)
800
+ parts[1..].each do |part|
801
+ nested = current.respond_to?(:nested_types) ? current.nested_types[part] : nil
802
+ return nil unless nested
803
+ current = nested
804
+ end
805
+ current
806
+ end
807
+
808
+ def resolve_named_generic_type(parts)
809
+ if parts.length == 1
810
+ type = @ctx.types[parts.first]
811
+ return type if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
812
+ elsif parts.length >= 2
813
+ type = resolve_nested_type_ref(parts)
814
+ return type if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
815
+ if @ctx.imports.key?(parts.first)
816
+ type = @ctx.imports.fetch(parts.first).types[parts.last]
817
+ return type if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
818
+ end
819
+ end
820
+
821
+ nil
822
+ end
823
+
824
+
825
+
826
+ def aggregate_display_name(type)
827
+ type.is_a?(Types::StructInstance) ? type.to_s : type.name
828
+ end
829
+
830
+ def validate_generic_type!(name, arguments)
831
+ super(name, arguments) { |msg| raise_sema_error(msg) }
832
+ end
833
+
834
+ def integer_type?(type)
835
+ type.is_a?(Types::Primitive) && type.integer?
836
+ end
837
+
838
+ def struct_instance_type?(type)
839
+ type.is_a?(Types::Struct) || type.is_a?(Types::Variant)
840
+ end
841
+
842
+ def c_natively_equality_comparable_type?(type)
843
+ return true if type.is_a?(Types::Primitive)
844
+ return true if type.is_a?(Types::EnumBase)
845
+ return true if type.is_a?(Types::Opaque)
846
+ return true if type.is_a?(Types::Nullable)
847
+ return true if type.is_a?(Types::Null)
848
+ return true if type.is_a?(Types::Function)
849
+ return true if type.is_a?(Types::Error)
850
+ return true if type.is_a?(Types::StringView)
851
+ return true if pointer_type?(type)
852
+ return true if ref_type?(type)
853
+ return true if type.is_a?(Types::Variant)
854
+ return true if type.is_a?(Types::VariantArmPayload)
855
+
856
+ false
857
+ end
858
+
859
+ def collection_loop_type(type)
860
+ super
861
+ end
862
+
863
+ def collection_loop_binding_type(iterable_type, element_type)
864
+ super
865
+ end
866
+
867
+ def collection_loop_ref_element_type?(type)
868
+ super
869
+ end
870
+
871
+ def iterator_loop_type(type)
872
+ type = referenced_type(type) if ref_type?(type)
873
+ iter_method = lookup_method(type, "iter")
874
+ return nil unless iter_method
875
+
876
+ iter_method = instantiate_function_binding_with_receiver(iter_method, [], receiver_type: type) if iter_method.type_params.any?
877
+
878
+ unless iter_method.type.params.empty?
879
+ raise_sema_error("for iterator #{type}.iter expects 0 arguments")
880
+ end
881
+ if iter_method.type.receiver_editable
882
+ raise_sema_error("for iterator #{type}.iter cannot be an editable method")
883
+ end
884
+
885
+ iterator_type = iter_method.type.return_type
886
+ next_method = lookup_method(iterator_type, "next")
887
+ raise_sema_error("for iterator #{iterator_type} must define next()") unless next_method
888
+ next_method = instantiate_function_binding_with_receiver(next_method, [], receiver_type: iterator_type) if next_method.type_params.any?
889
+ unless next_method.type.params.empty?
890
+ raise_sema_error("for iterator #{iterator_type}.next expects 0 arguments")
891
+ end
892
+
893
+ next_type = next_method.type.return_type
894
+ if next_type.is_a?(Types::Nullable) && typed_null_target_type?(next_type.base)
895
+ return next_type.base
896
+ end
897
+
898
+ if next_type == @ctx.types.fetch("bool")
899
+ current_method = lookup_method(iterator_type, "current")
900
+ raise_sema_error("for iterator #{iterator_type} must define current() when next() returns bool") unless current_method
901
+ current_method = instantiate_function_binding_with_receiver(current_method, [], receiver_type: iterator_type) if current_method.type_params.any?
902
+ unless current_method.type.params.empty?
903
+ raise_sema_error("for iterator #{iterator_type}.current expects 0 arguments")
904
+ end
905
+ raise_sema_error("for iterator #{iterator_type}.current cannot return void") if current_method.type.return_type == @ctx.types.fetch("void")
906
+
907
+ return current_method.type.return_type
908
+ end
909
+
910
+ raise_sema_error("for iterator #{iterator_type}.next must return bool or a nullable pointer-like item, got #{next_type}")
911
+ end
912
+
913
+ def string_like_type?(type)
914
+ type == @ctx.types.fetch("str") || type == @ctx.types.fetch("cstr")
915
+ end
916
+
917
+ def infer_index_result_type(receiver_type, index_type)
918
+ raise_sema_error("index must be an integer type, got #{index_type}") unless integer_type?(index_type)
919
+
920
+ if array_type?(receiver_type)
921
+ return array_element_type(receiver_type)
922
+ end
923
+
924
+ if span_type?(receiver_type)
925
+ return receiver_type.element_type
926
+ end
927
+
928
+ if soa_type?(receiver_type)
929
+ return receiver_type.element_type
930
+ end
931
+
932
+ if pointer_type?(receiver_type)
933
+ require_unsafe!("pointer indexing requires unsafe") unless own_type?(receiver_type)
934
+
935
+ return pointee_type(receiver_type)
936
+ end
937
+
938
+ raise_sema_error("cannot index #{receiver_type}")
939
+ end
940
+
941
+ def addressable_storage_expression?(expression, scopes:)
942
+ case expression
943
+ when AST::Identifier
944
+ true
945
+ when AST::MemberAccess, AST::IndexAccess
946
+ addressable_storage_expression?(expression.receiver, scopes:)
947
+ when AST::Call
948
+ return false unless expression.arguments.length == 1 && expression.arguments.first.name.nil?
949
+
950
+ read_call?(expression) && ref_type?(infer_expression(expression.arguments.first.value, scopes:))
951
+ else
952
+ false
953
+ end
954
+ end
955
+
956
+ def match_member_name(expression, enum_type)
957
+ return unless expression.is_a?(AST::MemberAccess)
958
+
959
+ receiver_type = resolve_type_expression(expression.receiver)
960
+ return unless receiver_type == enum_type
961
+ return expression.member if enum_type.member(expression.member)
962
+
963
+ nil
964
+ end
965
+
966
+ def resolve_type_expression(expression)
967
+ case expression
968
+ when AST::Identifier
969
+ return current_type_params[expression.name] if current_type_params.key?(expression.name)
970
+
971
+ @ctx.types[expression.name]
972
+ when AST::MemberAccess
973
+ return nil unless expression.receiver.is_a?(AST::Identifier)
974
+
975
+ if @ctx.imports.key?(expression.receiver.name)
976
+ imported_module = @ctx.imports.fetch(expression.receiver.name)
977
+ if imported_module.private_type?(expression.member)
978
+ raise_sema_error("#{expression.receiver.name}.#{expression.member} is private to module #{imported_module.name}")
979
+ end
980
+
981
+ return imported_module.types[expression.member]
982
+ end
983
+
984
+ parent_type = @ctx.types[expression.receiver.name]
985
+ return parent_type.nested_types[expression.member] if parent_type.respond_to?(:nested_types) && parent_type.nested_types.key?(expression.member)
986
+
987
+ nil
988
+ when AST::Specialization
989
+ type_ref = type_ref_from_specialization(expression)
990
+ return nil unless type_ref
991
+
992
+ resolve_type_ref(type_ref)
993
+ end
994
+ end
995
+
996
+ def imported_module_with_private_method(receiver_type, method_name)
997
+ imported_module = imported_module_with_private_method_local(receiver_type, method_name)
998
+ return imported_module if imported_module
999
+
1000
+ fallback_owner = specialization_lookup_owner
1001
+ return nil unless fallback_owner
1002
+
1003
+ fallback_owner.send(:imported_module_with_private_method_local, receiver_type, method_name)
1004
+ end
1005
+
1006
+ def imported_module_with_private_method_local(receiver_type, method_name)
1007
+ @ctx.imports.each_value do |module_binding|
1008
+ return module_binding if module_binding.private_method?(receiver_type, method_name)
1009
+ end
1010
+
1011
+ nil
1012
+ end
1013
+
1014
+
1015
+
1016
+ def resolve_methods_receiver_target(type_ref)
1017
+ if type_ref.is_a?(AST::TypeRef)
1018
+ generic_type = resolve_named_generic_type(type_ref.name.parts)
1019
+ if generic_type.is_a?(Types::GenericStructDefinition) || generic_type.is_a?(Types::GenericVariantDefinition)
1020
+ receiver_type_param_names = validate_methods_receiver_type_arguments!(type_ref, generic_type)
1021
+ receiver_type_params = receiver_type_param_names.to_h { |name| [name, Types::TypeVar.new(name)] }
1022
+ receiver_type_param_constraints = generic_type.respond_to?(:type_param_constraints) ? generic_type.type_param_constraints : {}
1023
+ receiver_type = resolve_type_ref(type_ref, type_params: receiver_type_params, type_param_constraints: receiver_type_param_constraints)
1024
+ return [generic_type, receiver_type, receiver_type_param_names, receiver_type_param_constraints]
1025
+ end
1026
+
1027
+ begin
1028
+ receiver_type = resolve_type_ref(type_ref)
1029
+ unless receiver_type.is_a?(Types::Struct) || receiver_type.is_a?(Types::StructInstance) || receiver_type.is_a?(Types::Opaque) || receiver_type.is_a?(Types::GenericInstance) || receiver_type.is_a?(Types::Nullable) || receiver_type.is_a?(Types::StringView) || receiver_type.is_a?(Types::Primitive) || receiver_type.is_a?(Types::Variant) || receiver_type.is_a?(Types::VariantInstance) || vector_type?(receiver_type) || matrix_type?(receiver_type) || quaternion_type?(receiver_type)
1030
+ raise_sema_error("extending target #{type_ref} must be a struct, opaque, nullable/generic receiver, variant, or str")
1031
+ end
1032
+
1033
+ return [receiver_type, receiver_type, [], {}]
1034
+ rescue MilkTea::SemanticError => error
1035
+ receiver_type_param_names = methods_receiver_type_argument_names!(type_ref)
1036
+ raise error if receiver_type_param_names.empty?
1037
+
1038
+ receiver_type_params = receiver_type_param_names.to_h { |name| [name, Types::TypeVar.new(name)] }
1039
+ receiver_type = resolve_type_ref(type_ref, type_params: receiver_type_params)
1040
+ return [method_dispatch_receiver_type(receiver_type), receiver_type, receiver_type_param_names, {}]
1041
+ end
1042
+ end
1043
+
1044
+ receiver_type = resolve_type_ref(type_ref)
1045
+ unless receiver_type.is_a?(Types::Struct) || receiver_type.is_a?(Types::StructInstance) || receiver_type.is_a?(Types::Opaque) || receiver_type.is_a?(Types::GenericInstance) || receiver_type.is_a?(Types::Nullable) || receiver_type.is_a?(Types::StringView) || receiver_type.is_a?(Types::Primitive) || receiver_type.is_a?(Types::Variant) || receiver_type.is_a?(Types::VariantInstance) || vector_type?(receiver_type) || matrix_type?(receiver_type) || quaternion_type?(receiver_type)
1046
+ raise_sema_error("extending target #{type_ref} must be a struct, opaque, nullable/generic receiver, variant, or str")
1047
+ end
1048
+
1049
+ [receiver_type, receiver_type, [], {}]
1050
+ end
1051
+
1052
+ def methods_receiver_type_argument_names!(type_ref)
1053
+ names = type_ref.arguments.map do |argument|
1054
+ value = argument.value
1055
+ next unless value.is_a?(AST::TypeRef)
1056
+ next unless value.arguments.empty? && !value.nullable && value.name.parts.length == 1
1057
+
1058
+ value.name.parts.first
1059
+ end
1060
+
1061
+ raise_sema_error("extending target #{type_ref} must use the receiver type parameters directly") if names.any?(&:nil?)
1062
+
1063
+ names
1064
+ end
1065
+
1066
+ def validate_methods_receiver_type_arguments!(type_ref, generic_type)
1067
+ names = type_ref.arguments.map do |argument|
1068
+ value = argument.value
1069
+ next unless value.is_a?(AST::TypeRef)
1070
+ next unless value.arguments.empty? && !value.nullable && value.name.parts.length == 1
1071
+
1072
+ value.name.parts.first
1073
+ end
1074
+
1075
+ expected_names = generic_type.type_params
1076
+ unless names == expected_names
1077
+ raise_sema_error("extending target #{type_ref} must use the receiver type parameters directly")
1078
+ end
1079
+
1080
+ expected_names
1081
+ end
1082
+
1083
+ def proc_type_compatible?(actual_type, expected_type)
1084
+ return true unless expected_type
1085
+ if proc_type?(expected_type)
1086
+ return true if expected_type.is_a?(Types::Proc) && actual_type.is_a?(Types::Proc) &&
1087
+ contains_type_var?(expected_type)
1088
+ return actual_type == expected_type
1089
+ end
1090
+
1091
+ false
1092
+ end
1093
+
1094
+
1095
+ def freeze_scope_bindings(scope)
1096
+ frozen_scope = scope.is_a?(FlowScope) ? FlowScope.new : {}
1097
+ scope.each do |name, binding|
1098
+ frozen_scope[name] = ValueBinding.new(
1099
+ id: binding.id,
1100
+ name: binding.name,
1101
+ storage_type: binding.storage_type,
1102
+ flow_type: binding.flow_type,
1103
+ mutable: false,
1104
+ kind: binding.kind,
1105
+ const_value: binding.const_value,
1106
+ )
1107
+ end
1108
+ frozen_scope
1109
+ end
1110
+
1111
+ def validate_stored_ref_type!(type, context, allow_lifetimes: [])
1112
+ return unless contains_ref_type?(type, allow_lifetimes:)
1113
+ return if stored_ref_supported_type?(type, allow_lifetimes:)
1114
+
1115
+ if callable_type?(type) || contains_callable_ref_type?(type)
1116
+ raise_sema_error("#{context} cannot store ref types outside callable parameter positions")
1117
+ end
1118
+
1119
+ if context.start_with?("field ")
1120
+ raise_sema_error("#{context} cannot store ref types; declare a lifetime on the struct and use ref[@lt, T] (e.g. struct MyStruct[@a]: field: ref[@a, SomeType])")
1121
+ end
1122
+
1123
+ raise_sema_error("#{context} cannot store ref types")
1124
+ end
1125
+
1126
+ def stored_ref_supported_type?(type, visited = {}, allow_lifetimes: [])
1127
+ visitor = StoredRefSupportedVisitor.new(allow_lifetimes:)
1128
+ visitor.visit(type)
1129
+ visitor.result?
1130
+ end
1131
+
1132
+ def contains_callable_ref_type?(type, visited = {})
1133
+ visitor = ContainsCallableRefTypeVisitor.new
1134
+ visitor.visit(type)
1135
+ visitor.found?
1136
+ end
1137
+
1138
+ def contains_proc_type?(type, visited = {})
1139
+ visitor = ContainsProcTypeVisitor.new
1140
+ visitor.visit(type)
1141
+ visitor.found?
1142
+ end
1143
+
1144
+ def proc_storage_supported_type?(type, visited = {})
1145
+ return true unless contains_proc_type?(type)
1146
+ visitor = ProcStorageSupportedVisitor.new
1147
+ visitor.visit(type)
1148
+ visitor.result?
1149
+ end
1150
+
1151
+ def validate_parameter_ref_type!(type, function_name:, parameter_name:, external:)
1152
+ if ref_type?(type)
1153
+ raise_sema_error("external function #{function_name} cannot take ref parameters") if external
1154
+
1155
+ return
1156
+ end
1157
+
1158
+ return if callable_param_ref_supported?(type)
1159
+
1160
+ raise_sema_error("parameter #{parameter_name} of #{function_name} cannot nest ref types") if contains_ref_type?(type)
1161
+ end
1162
+
1163
+ def validate_parameter_proc_type!(type, function_name:, parameter_name:, external:, foreign:)
1164
+ if contains_proc_type?(type)
1165
+ raise_sema_error("external function #{function_name} cannot take proc parameters") if external
1166
+ raise_sema_error("foreign function #{function_name} cannot take proc parameters") if foreign
1167
+ raise_sema_error("parameter #{parameter_name} of #{function_name} uses unsupported proc nesting") unless proc_storage_supported_type?(type)
1168
+ end
1169
+ end
1170
+
1171
+ def validate_return_ref_type!(type, function_name:)
1172
+ if contains_ref_type?(type)
1173
+ if (type.is_a?(Types::Struct) || type.is_a?(Types::StructInstance)) && type.fields.any?
1174
+ raise_sema_error("function #{function_name} cannot return non-owning struct #{type.name} (contains borrowed ref)")
1175
+ end
1176
+ raise_sema_error("function #{function_name} cannot return ref types")
1177
+ end
1178
+ end
1179
+
1180
+ def validate_return_proc_type!(type, function_name:)
1181
+ if contains_proc_type?(type)
1182
+ raise_sema_error("function #{function_name} uses unsupported proc nesting in return type") unless proc_storage_supported_type?(type)
1183
+ end
1184
+ end
1185
+
1186
+ def validate_local_ref_type!(type, local_name)
1187
+ return if ref_type?(type)
1188
+ return if (type.is_a?(Types::Struct) || type.is_a?(Types::StructInstance)) && type.fields.any? && contains_ref_type?(type)
1189
+ return if stored_ref_supported_type?(type)
1190
+
1191
+ if contains_ref_type?(type)
1192
+ if callable_type?(type) || contains_callable_ref_type?(type)
1193
+ raise_sema_error("local #{local_name} cannot store ref types outside callable parameter positions")
1194
+ end
1195
+
1196
+ raise_sema_error("local #{local_name} cannot store nested ref types")
1197
+ end
1198
+ end
1199
+
1200
+ def validate_local_proc_type!(type, local_name, initializer:)
1201
+ return unless contains_proc_type?(type)
1202
+
1203
+ raise_sema_error("local #{local_name} uses unsupported proc nesting") unless proc_storage_supported_type?(type)
1204
+ end
1205
+
1206
+ def preassigned_local_binding_id_for(node)
1207
+ @preassigned_local_binding_ids[node.object_id] ||= allocate_binding_id
1208
+ end
1209
+
1210
+ def error_type?(type)
1211
+ type.is_a?(Types::Error)
1212
+ end
1213
+
1214
+ def array_to_span_call_argument_compatible?(actual_type, expected_type, expression:, scopes:)
1215
+ return false unless expected_type.is_a?(Types::Span)
1216
+
1217
+ if array_type?(actual_type)
1218
+ return false unless array_element_type(actual_type) == expected_type.element_type
1219
+
1220
+ infer_addr_source_type(expression, scopes:)
1221
+ record_mutable_lvalue_argument_identifier(expression)
1222
+ return true
1223
+ end
1224
+
1225
+ if str_buffer_type?(actual_type)
1226
+ return false unless expected_type.element_type == @ctx.types.fetch("char")
1227
+
1228
+ infer_addr_source_type(expression, scopes:)
1229
+ record_mutable_lvalue_argument_identifier(expression)
1230
+ return true
1231
+ end
1232
+
1233
+ false
1234
+ rescue SemanticError
1235
+ false
1236
+ end
1237
+
1238
+ def safe_reference_source_expression?(expression, scopes:)
1239
+ case expression
1240
+ when AST::Identifier
1241
+ true
1242
+ when AST::MemberAccess, AST::IndexAccess
1243
+ safe_reference_source_expression?(expression.receiver, scopes:)
1244
+ when AST::BinaryOp
1245
+ unsafe_context?
1246
+ when AST::Call
1247
+ return false unless expression.arguments.length == 1 && expression.arguments.first.name.nil?
1248
+
1249
+ if read_call?(expression)
1250
+ argument_type = infer_expression(expression.arguments.first.value, scopes:)
1251
+ ref_type?(argument_type) || pointer_type?(argument_type)
1252
+ else
1253
+ false
1254
+ end
1255
+ else
1256
+ false
1257
+ end
1258
+ end
1259
+
1260
+ def infer_ro_addr_source_type(expression, scopes:)
1261
+ raise_sema_error("const_ptr_of requires a safe lvalue source") unless safe_reference_source_expression?(expression, scopes:)
1262
+
1263
+ source_type = infer_expression(expression, scopes:)
1264
+ if contains_ref_type?(source_type)
1265
+ unless (source_type.is_a?(Types::Struct) || source_type.is_a?(Types::StructInstance)) && source_type.lifetime_params&.any?
1266
+ raise_sema_error("const_ptr_of cannot target ref values")
1267
+ end
1268
+ end
1269
+
1270
+ source_type
1271
+ end
1272
+
1273
+ def infer_addr_source_type(expression, scopes:)
1274
+ raise_sema_error("ref_of requires a mutable safe lvalue source") unless safe_reference_source_expression?(expression, scopes:)
1275
+
1276
+ source_type = infer_lvalue(expression, scopes:)
1277
+ if contains_ref_type?(source_type)
1278
+ unless (source_type.is_a?(Types::Struct) || source_type.is_a?(Types::StructInstance)) && source_type.lifetime_params&.any?
1279
+ raise_sema_error("ref_of cannot target ref values")
1280
+ end
1281
+ end
1282
+
1283
+ source_type
1284
+ end
1285
+
1286
+ def validate_read_call_arguments!(arguments)
1287
+ raise_sema_error("read does not support named arguments") if arguments.any?(&:name)
1288
+ raise_sema_error("read expects 1 argument, got #{arguments.length}") unless arguments.length == 1
1289
+ end
1290
+
1291
+ def infer_reference_value_type(handle_expression, scopes:)
1292
+ handle_type = infer_expression(handle_expression, scopes:)
1293
+ return referenced_type(handle_type) if ref_type?(handle_type)
1294
+
1295
+ pointee = pointee_type(handle_type)
1296
+ if pointee
1297
+ require_unsafe!("raw pointer dereference requires unsafe") unless own_type?(handle_type)
1298
+
1299
+ return pointee
1300
+ end
1301
+
1302
+ raise_sema_error("read expects ref[...] or ptr[...], got #{handle_type}")
1303
+ end
1304
+
1305
+ def infer_method_receiver_type(receiver_expression, scopes:, member_name: nil)
1306
+ receiver_type = infer_expression(receiver_expression, scopes:)
1307
+ project_method_receiver_type(receiver_type, member_name:)
1308
+ end
1309
+
1310
+ def infer_field_receiver_type(receiver_expression, scopes:, require_mutable_pointer: false)
1311
+ receiver_type = infer_expression(receiver_expression, scopes:)
1312
+ project_field_receiver_type(receiver_type, require_mutable_pointer:)
1313
+ end
1314
+
1315
+ def project_field_receiver_type(receiver_type, require_mutable_pointer: false)
1316
+ return referenced_type(receiver_type) if ref_type?(receiver_type)
1317
+ return receiver_type unless pointer_type?(receiver_type)
1318
+
1319
+ require_unsafe!("raw pointer dereference requires unsafe") unless own_type?(receiver_type)
1320
+ if require_mutable_pointer && const_pointer_type?(receiver_type)
1321
+ raise_sema_error("cannot assign through read-only raw pointer #{receiver_type}")
1322
+ end
1323
+
1324
+ pointee_type(receiver_type)
1325
+ end
1326
+
1327
+ def project_method_receiver_type(receiver_type, member_name: nil)
1328
+ receiver_type = referenced_type(receiver_type) if ref_type?(receiver_type)
1329
+ return receiver_type unless pointer_type?(receiver_type)
1330
+
1331
+ return receiver_type if member_name && lookup_method(receiver_type, member_name)
1332
+
1333
+ require_unsafe!("raw pointer dereference requires unsafe") unless own_type?(receiver_type)
1334
+
1335
+ pointee_type(receiver_type)
1336
+ end
1337
+
1338
+ def read_call?(expression)
1339
+ expression.is_a?(AST::Call) && expression.callee.is_a?(AST::Identifier) && expression.callee.name == "read"
1340
+ end
1341
+
1342
+ def raw_module?
1343
+ @ctx.module_kind == :raw_module
1344
+ end
1345
+
1346
+ def assignable_receiver?(receiver_expression, scopes)
1347
+ infer_lvalue_receiver(receiver_expression, scopes:, allow_ref_identifier: true, allow_pointer_identifier: true, require_mutable_pointer: true)
1348
+ true
1349
+ rescue SemanticError
1350
+ false
1351
+ end
1352
+
1353
+ def value_binding(name:, type:, mutable:, kind:, flow_type: nil, const_value: nil, id: nil)
1354
+ id ||= allocate_binding_id
1355
+ @binding_name_by_id[id] = name
1356
+ @binding_type_by_id[id] = flow_type == type ? type : (flow_type || type)
1357
+ ValueBinding.new(id:, name:, storage_type: type, flow_type: flow_type == type ? nil : flow_type, mutable:, kind:, const_value:)
1358
+ end
1359
+
1360
+ def binding_resolution_snapshot
1361
+ BindingResolution.new(
1362
+ identifier_binding_ids: @identifier_binding_ids.dup.freeze,
1363
+ declaration_binding_ids: @declaration_binding_ids.dup.freeze,
1364
+ mutating_argument_identifier_ids: @mutating_argument_identifier_ids.dup.freeze,
1365
+ editable_receiver_expression_ids: @editable_receiver_expression_ids.dup.freeze,
1366
+ mutable_lvalue_argument_identifier_ids: @mutable_lvalue_argument_identifier_ids.dup.freeze,
1367
+ binding_types: @binding_type_by_id.dup.freeze,
1368
+ )
1369
+ end
1370
+
1371
+ def allocate_binding_id
1372
+ id = @next_binding_id
1373
+ @next_binding_id += 1
1374
+ id
1375
+ end
1376
+
1377
+ def record_identifier_binding(expression, binding)
1378
+ return unless expression.is_a?(AST::Identifier)
1379
+ return unless binding&.id
1380
+
1381
+ @identifier_binding_ids[expression.object_id] = binding.id
1382
+ end
1383
+
1384
+ def record_callable_value_identifier_site(expression)
1385
+ return unless expression.is_a?(AST::Identifier)
1386
+ return unless expression.line && expression.column
1387
+
1388
+ @callable_value_identifier_sites[[expression.line, expression.column]] = true
1389
+ end
1390
+
1391
+ def record_callable_value_expression_site(expression)
1392
+ case expression
1393
+ when AST::Identifier
1394
+ record_callable_value_identifier_site(expression)
1395
+ when AST::MemberAccess
1396
+ record_callable_value_member_access_site(expression)
1397
+ end
1398
+ end
1399
+
1400
+ def record_callable_value_member_access_site(expression)
1401
+ return unless expression.is_a?(AST::MemberAccess)
1402
+ return unless expression.receiver.is_a?(AST::Identifier)
1403
+ return unless expression.receiver.line && expression.receiver.column
1404
+
1405
+ @callable_value_member_access_sites[
1406
+ [expression.receiver.name, expression.receiver.line, expression.receiver.column, expression.member]
1407
+ ] = true
1408
+ end
1409
+
1410
+ def record_declaration_binding(node, binding)
1411
+ return unless node
1412
+ return unless binding&.id
1413
+
1414
+ @declaration_binding_ids[node.object_id] = binding.id
1415
+ end
1416
+
1417
+ def import_suggestion_for_type(type_name)
1418
+ return nil if @ctx.global_import_index.nil? || @ctx.global_import_index.empty?
1419
+
1420
+ type_str = type_name.to_s
1421
+ return nil if type_str.empty?
1422
+
1423
+ if @ctx.global_import_index.key?(type_str)
1424
+ entry = @ctx.global_import_index[type_str]
1425
+ return nil if entry.nil?
1426
+ module_path = entry.is_a?(Array) ? entry.first : entry
1427
+ if module_path && !@ctx.imports.key?(module_path.to_s.split(".").first) && !@ctx.imports.key?(module_path.to_s)
1428
+ return "type '#{type_str}' is available via 'import #{module_path}'"
1429
+ end
1430
+ end
1431
+
1432
+ nil
1433
+ end
1434
+
1435
+
1436
+ end
1437
+ end
1438
+ end