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,354 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MilkTea
4
+ class SemanticAnalyzer
5
+ class Checker
6
+ private
7
+
8
+ def declare_functions
9
+ expanded_declarations.each do |decl|
10
+ with_error_node(decl) do
11
+ case decl
12
+ when AST::FunctionDef
13
+ ensure_available_value_name!(decl.name, kind_label: "function", line: decl.line, column: decl.respond_to?(:column) ? decl.column : nil)
14
+ @ctx.top_level_functions[decl.name] = declare_function_binding(decl)
15
+ when AST::ExternFunctionDecl
16
+ ensure_available_value_name!(decl.name, kind_label: "function", line: decl.line, column: decl.respond_to?(:column) ? decl.column : nil)
17
+ if decl.mapping && !decl.mapping.is_a?(AST::StringLiteral)
18
+ raise_sema_error("external function #{decl.name} mapping must be a c-string literal")
19
+ end
20
+ @ctx.top_level_functions[decl.name] = declare_function_binding(decl, external: true)
21
+ when AST::ForeignFunctionDecl
22
+ ensure_available_value_name!(decl.name, kind_label: "function", line: decl.line, column: decl.respond_to?(:column) ? decl.column : nil)
23
+ @ctx.top_level_functions[decl.name] = declare_function_binding(decl)
24
+ when AST::ExtendingBlock
25
+ dispatch_receiver_type, receiver_type, receiver_type_param_names, receiver_type_param_constraints = resolve_methods_receiver_target(decl.type_name)
26
+
27
+ decl.methods.each do |method|
28
+ begin
29
+ binding = with_error_node(method) do
30
+ declare_function_binding(
31
+ method,
32
+ receiver_type:,
33
+ declared_receiver_type: receiver_type,
34
+ receiver_type_param_names:,
35
+ receiver_type_param_constraints:,
36
+ )
37
+ end
38
+ instance_method = receiver_type && method.kind != :static
39
+ method_key = instance_method ? binding.name : "static:#{binding.name}"
40
+ raise_sema_error("duplicate method #{decl.type_name}.#{binding.name}") if @ctx.methods[dispatch_receiver_type].key?(method_key)
41
+
42
+ @ctx.methods[dispatch_receiver_type][method_key] = binding
43
+ rescue SemanticError => e
44
+ collect_structural_error(e)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ rescue SemanticError => e
50
+ collect_structural_error(e)
51
+ end
52
+ end
53
+
54
+ def declare_function_binding(decl, receiver_type: nil, declared_receiver_type: nil, receiver_type_param_names: [], receiver_type_param_constraints: {}, external: false)
55
+ foreign = decl.is_a?(AST::ForeignFunctionDecl)
56
+ async_function = decl.respond_to?(:async) ? decl.async : false
57
+ if decl.is_a?(AST::MethodDef)
58
+ ensure_non_reserved_primitive_name!(decl.name, kind_label: "function", line: decl.line, column: decl.column)
59
+ end
60
+ type_param_names = receiver_type_param_names + decl.type_params.map(&:name)
61
+ type_param_constraints = receiver_type_param_constraints.merge(resolve_type_param_constraints(decl.type_params))
62
+ raise_sema_error("external function #{decl.name} cannot be generic") if external && type_param_names.any?
63
+ raise_sema_error("main cannot be generic") if decl.name == "main" && type_param_names.any?
64
+ raise_sema_error("external function #{decl.name} cannot be async") if external && async_function
65
+ raise_sema_error("foreign function #{decl.name} cannot be async") if foreign && async_function
66
+
67
+ method_kind = decl.is_a?(AST::MethodDef) ? decl.kind : nil
68
+ instance_method = receiver_type && method_kind != :static
69
+
70
+ type_params = {}
71
+ type_param_names.each do |name|
72
+ raise_sema_error("duplicate type parameter #{decl.name}[#{name}]") if type_params.key?(name)
73
+
74
+ type_params[name] = Types::TypeVar.new(name)
75
+ end
76
+
77
+ body_params = []
78
+ if instance_method
79
+ body_params << value_binding(
80
+ name: "this",
81
+ type: receiver_type,
82
+ mutable: method_kind == :editable,
83
+ kind: :param,
84
+ )
85
+ end
86
+
87
+ public_params = []
88
+ decl.params.each do |param|
89
+ begin
90
+ ensure_non_reserved_primitive_name!(param.name, kind_label: "parameter", line: param.respond_to?(:line) ? param.line : decl.line, column: param.respond_to?(:column) ? param.column : nil)
91
+ type = resolve_type_ref(param.type, type_params:, type_param_constraints:)
92
+ validate_parameter_ref_type!(type, function_name: decl.name, parameter_name: param.name, external:)
93
+ reject_foreign_nullable_value_type!(type, function_name: decl.name, parameter_name: param.name) if foreign || external
94
+ validate_parameter_proc_type!(type, function_name: decl.name, parameter_name: param.name, external:, foreign:)
95
+ raise_sema_error("parameter #{param.name} of #{decl.name} must pass event storage through ref[...] or pointers, got #{type}") if noncopyable_event_storage_type?(type)
96
+
97
+ if external && array_type?(type)
98
+ raise_sema_error("external function #{decl.name} cannot take array parameters")
99
+ end
100
+
101
+ if param.is_a?(AST::ForeignParam)
102
+ if external
103
+ raise_sema_error("external parameter #{param.name} of #{decl.name} cannot use `as`") if param.boundary_type
104
+ unless %i[plain out inout].include?(param.mode)
105
+ raise_sema_error("external parameter #{param.name} of #{decl.name} cannot use `#{param.mode}`")
106
+ end
107
+ elsif foreign
108
+ raise_sema_error("foreign parameter #{param.name} cannot use `as` with #{param.mode}") if ![:plain, :in].include?(param.mode) && param.boundary_type
109
+ validate_consuming_foreign_parameter!(type, function_name: decl.name, parameter_name: param.name) if param.mode == :consuming
110
+ end
111
+
112
+ boundary_type = foreign_parameter_boundary_type(param, type, type_params:, type_param_constraints:)
113
+ validate_foreign_boundary_type!(type, boundary_type, function_name: decl.name, parameter_name: param.name) if foreign && param.boundary_type && param.mode != :in
114
+ validate_in_foreign_parameter!(type, boundary_type, function_name: decl.name, parameter_name: param.name) if foreign && param.mode == :in
115
+ param_binding = value_binding(name: param.name, type: boundary_type || type, mutable: false, kind: :param)
116
+ body_params << param_binding
117
+ record_declaration_binding(param, param_binding)
118
+ if foreign && param.boundary_type
119
+ body_params << value_binding(
120
+ name: foreign_mapping_public_alias_name(param.name),
121
+ type:,
122
+ mutable: false,
123
+ kind: :param,
124
+ )
125
+ end
126
+ public_params << Types::Registry.parameter(param.name, type, passing_mode: param.mode, boundary_type: boundary_type)
127
+ else
128
+ param_binding = value_binding(name: param.name, type:, mutable: false, kind: :param)
129
+ body_params << param_binding
130
+ record_declaration_binding(param, param_binding)
131
+ public_params << Types::Registry.parameter(param.name, type) if external
132
+ end
133
+ rescue SemanticError => e
134
+ collect_structural_error(e)
135
+ param_binding = value_binding(name: param.name, type: @error_type, mutable: false, kind: :param)
136
+ body_params << param_binding
137
+ end
138
+ end
139
+
140
+ receiver_editable = false
141
+ call_params = body_params
142
+ function_receiver_type = nil
143
+ if instance_method
144
+ receiver_editable = method_kind == :editable
145
+ call_params = body_params.drop(1)
146
+ function_receiver_type = receiver_type
147
+ end
148
+
149
+ call_params = public_params if foreign || external
150
+
151
+ seen = {}
152
+ body_params.each do |param|
153
+ raise_sema_error("duplicate parameter #{param.name} in #{decl.name}") if seen.key?(param.name)
154
+
155
+ seen[param.name] = true
156
+ end
157
+
158
+ body_return_type = decl.return_type ? resolve_type_ref(decl.return_type, type_params:, type_param_constraints:) : @ctx.types.fetch("void")
159
+ validate_return_ref_type!(body_return_type, function_name: decl.name)
160
+ reject_foreign_nullable_value_type!(body_return_type, function_name: decl.name, parameter_name: nil) if foreign || external
161
+ validate_return_proc_type!(body_return_type, function_name: decl.name)
162
+ raise_sema_error("function #{decl.name} cannot return event storage type #{body_return_type}") if noncopyable_event_storage_type?(body_return_type)
163
+ if decl.name == "main" && async_function && body_return_type != @ctx.types.fetch("int") && body_return_type != @ctx.types.fetch("void")
164
+ raise_sema_error("async main must return int or void")
165
+ end
166
+ if foreign && public_params.any? { |param| param.passing_mode == :consuming } && body_return_type != @ctx.types.fetch("void")
167
+ raise_sema_error("foreign function #{decl.name} with consuming parameters must return void")
168
+ end
169
+ if external && array_type?(body_return_type)
170
+ raise_sema_error("external function #{decl.name} cannot return arrays")
171
+ end
172
+ function_return_type = async_function ? Types::Registry.task(body_return_type) : body_return_type
173
+
174
+ function_type = Types::Registry.function(
175
+ decl.name,
176
+ params: (foreign || external) ? call_params : call_params.map { |param| Types::Registry.parameter(param.name, param.type) },
177
+ return_type: function_return_type,
178
+ receiver_type: function_receiver_type,
179
+ receiver_editable:,
180
+ variadic: decl.respond_to?(:variadic) ? decl.variadic : false,
181
+ external:,
182
+ )
183
+
184
+ FunctionBinding.new(
185
+ name: decl.name,
186
+ type: function_type,
187
+ body_params:,
188
+ body_return_type: body_return_type,
189
+ ast: decl,
190
+ external:,
191
+ async: async_function,
192
+ type_params: type_param_names.freeze,
193
+ type_param_constraints: type_param_constraints.freeze,
194
+ instances: {},
195
+ type_arguments: [].freeze,
196
+ owner: self,
197
+ specialization_owner: nil,
198
+ type_substitutions: {}.freeze,
199
+ declared_receiver_type: declared_receiver_type,
200
+ )
201
+ end
202
+
203
+ def resolve_type_param_constraints(type_params)
204
+ type_params.each_with_object({}) do |type_param, constraints|
205
+ if type_param.is_a?(AST::ValueTypeParam)
206
+ ensure_non_reserved_type_binding_name!(
207
+ type_param.name,
208
+ kind_label: "type parameter",
209
+ line: type_param.line,
210
+ column: type_param.column,
211
+ length: type_param.length,
212
+ )
213
+ next
214
+ end
215
+
216
+ ensure_non_reserved_type_binding_name!(
217
+ type_param.name,
218
+ kind_label: "type parameter",
219
+ line: type_param.line,
220
+ column: type_param.column,
221
+ length: type_param.length,
222
+ )
223
+ next if type_param.constraints.empty?
224
+
225
+ resolved_interfaces = []
226
+ seen_interfaces = {}
227
+
228
+ type_param.constraints.each do |constraint|
229
+ case constraint.kind
230
+ when :interface
231
+ interface = resolve_interface_ref(constraint.interface_ref)
232
+ raise_sema_error("duplicate interface constraint #{type_param.name} implements #{interface.name}") if seen_interfaces.key?(interface)
233
+
234
+ seen_interfaces[interface] = true
235
+ resolved_interfaces << interface
236
+ else
237
+ raise_sema_error("unsupported type parameter constraint #{constraint.kind}")
238
+ end
239
+ end
240
+
241
+ constraints[type_param.name] = TypeParamConstraintBinding.new(
242
+ interfaces: resolved_interfaces.freeze,
243
+ )
244
+ end
245
+ end
246
+
247
+ def check_functions
248
+ @ctx.top_level_functions.each_value do |binding|
249
+ check_function(binding)
250
+ end
251
+
252
+ @ctx.methods.each_value do |method_map|
253
+ method_map.each_value do |binding|
254
+ check_function(binding)
255
+ end
256
+ end
257
+ end
258
+
259
+ # Per-function error collection used by check_collecting_errors.
260
+ # Continues past individual function failures, accumulating SemanticErrors.
261
+ def check_functions_collecting(errors)
262
+ @ctx.top_level_functions.each_value do |binding|
263
+ next if @checked_function_bindings[binding.object_id]
264
+
265
+ prev_count = @structural_errors.length
266
+ begin
267
+ check_function(binding)
268
+ rescue SemanticError => e
269
+ errors << e
270
+ end
271
+ errors.concat(@structural_errors[prev_count..].to_a)
272
+ end
273
+
274
+ @ctx.methods.each_value do |method_map|
275
+ method_map.each_value do |binding|
276
+ next if @checked_function_bindings[binding.object_id]
277
+
278
+ prev_count = @structural_errors.length
279
+ begin
280
+ check_function(binding)
281
+ rescue SemanticError => e
282
+ errors << e
283
+ end
284
+ errors.concat(@structural_errors[prev_count..].to_a)
285
+ end
286
+ end
287
+ end
288
+
289
+ def check_function(binding)
290
+ @local_completion_frames = @local_completion_frames.dup if @local_completion_frames.frozen?
291
+
292
+ previous_type_substitutions = @current_type_substitutions
293
+ previous_specialization_owner = @current_specialization_owner
294
+ started_check = false
295
+ return if binding.external || binding.type_params.any?
296
+ return if @checked_function_bindings[binding.object_id]
297
+ return if @checking_function_bindings[binding.object_id]
298
+
299
+ @checking_function_bindings[binding.object_id] = true
300
+ started_check = true
301
+ @current_type_substitutions = binding.type_substitutions
302
+ @current_specialization_owner = binding.specialization_owner
303
+ with_error_node(binding.ast) do
304
+ with_scope(binding.body_params) do |scopes|
305
+ start_local_completion_frame(binding, scopes)
306
+ if binding.ast.is_a?(AST::ForeignFunctionDecl)
307
+ record_callable_value_expression_site(binding.ast.mapping) unless binding.ast.mapping.is_a?(AST::Call)
308
+ expression = foreign_mapping_expression(binding.ast)
309
+ actual_type = with_foreign_mapping_context do
310
+ infer_expression(expression, scopes:, expected_type: binding.type.return_type)
311
+ end
312
+ unless types_compatible?(actual_type, binding.type.return_type, expression:) || foreign_identity_projection_compatible?(actual_type, binding.type.return_type)
313
+ raise_sema_error("foreign mapping #{binding.name} expects #{binding.type.return_type}, got #{actual_type}")
314
+ end
315
+ else
316
+ validate_async_function_body!(binding.ast.body) if binding.async
317
+ preassign_local_binding_ids(binding.ast.body)
318
+ run_nullability_pre_pass(binding, scopes)
319
+ if binding.ast.respond_to?(:const) && binding.ast.const
320
+ with_compile_time do
321
+ if binding.async
322
+ with_async_function do
323
+ check_block(binding.ast.body, scopes:, return_type: binding.body_return_type)
324
+ end
325
+ else
326
+ check_block(binding.ast.body, scopes:, return_type: binding.type.return_type)
327
+ end
328
+ end
329
+ elsif binding.async
330
+ with_async_function do
331
+ check_block(binding.ast.body, scopes:, return_type: binding.body_return_type)
332
+ end
333
+ else
334
+ check_block(binding.ast.body, scopes:, return_type: binding.type.return_type)
335
+ end
336
+ check_definite_assignment(binding)
337
+ end
338
+ end
339
+ end
340
+ @checked_function_bindings[binding.object_id] = true
341
+ ensure
342
+ return unless started_check
343
+
344
+ finish_local_completion_frame(binding)
345
+ @preassigned_local_binding_ids = {}
346
+ @nullability_flow_result = nil
347
+ @current_type_substitutions = previous_type_substitutions
348
+ @current_specialization_owner = previous_specialization_owner
349
+ @checking_function_bindings.delete(binding.object_id)
350
+ end
351
+
352
+ end
353
+ end
354
+ end