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,383 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MilkTea
4
+ class SemanticAnalyzer::Checker
5
+ private
6
+
7
+ def infer_receiver_type_substitutions(binding, receiver_type)
8
+ declared_receiver_type = binding.declared_receiver_type
9
+ return {} unless declared_receiver_type
10
+ case declared_receiver_type
11
+ when Types::Nullable
12
+ unless receiver_type.is_a?(Types::Nullable)
13
+ raise_sema_error("cannot use method #{binding.name} with receiver #{receiver_type}")
14
+ end
15
+
16
+ infer_receiver_type_substitutions(
17
+ binding.with(declared_receiver_type: declared_receiver_type.base),
18
+ receiver_type.base,
19
+ )
20
+ when Types::StructInstance
21
+ return {} unless declared_receiver_type.definition.is_a?(Types::GenericStructDefinition)
22
+
23
+ unless receiver_type.is_a?(Types::StructInstance) && receiver_type.definition == declared_receiver_type.definition
24
+ raise_sema_error("cannot use method #{binding.name} with receiver #{receiver_type}")
25
+ end
26
+
27
+ declared_receiver_type.definition.type_params.zip(receiver_type.arguments).to_h
28
+ when Types::VariantInstance
29
+ return {} unless declared_receiver_type.definition.is_a?(Types::GenericVariantDefinition)
30
+
31
+ unless receiver_type.is_a?(Types::VariantInstance) && receiver_type.definition == declared_receiver_type.definition
32
+ raise_sema_error("cannot use method #{binding.name} with receiver #{receiver_type}")
33
+ end
34
+
35
+ declared_receiver_type.definition.type_params.zip(receiver_type.arguments).to_h
36
+ when Types::GenericInstance
37
+ unless receiver_type.is_a?(Types::GenericInstance) && receiver_type.name == declared_receiver_type.name && receiver_type.arguments.length == declared_receiver_type.arguments.length
38
+ raise_sema_error("cannot use method #{binding.name} with receiver #{receiver_type}")
39
+ end
40
+
41
+ declared_receiver_type.arguments.zip(receiver_type.arguments).each_with_object({}) do |(declared_argument, actual_argument), substitutions|
42
+ if declared_argument.is_a?(Types::TypeVar)
43
+ substitutions[declared_argument.name] = actual_argument
44
+ elsif declared_argument != actual_argument
45
+ raise_sema_error("cannot use method #{binding.name} with receiver #{receiver_type}")
46
+ end
47
+ end
48
+ else
49
+ {}
50
+ end
51
+ end
52
+
53
+ def callable_receiver_type_for_specialization(callee, scopes:)
54
+ return unless callee.is_a?(AST::MemberAccess)
55
+
56
+ resolve_type_expression(callee.receiver)
57
+ end
58
+
59
+ def resolve_type_member(type, name)
60
+ case type
61
+ when Types::Enum, Types::Flags
62
+ type.member(name)
63
+ when Types::Variant
64
+ return type if type.arm_names.include?(name) && !type.has_payload?(name)
65
+
66
+ nil
67
+ end
68
+ end
69
+
70
+ def function_type_for_name(name)
71
+ @ctx.top_level_functions.fetch(name).type
72
+ end
73
+
74
+ def resolve_specialized_callable_binding(expression, scopes:)
75
+ callable_kind = :function
76
+ receiver = nil
77
+ receiver_type = nil
78
+ binding = case expression.callee
79
+ when AST::Identifier
80
+ @ctx.top_level_functions[expression.callee.name]
81
+ when AST::MemberAccess
82
+ if expression.callee.receiver.is_a?(AST::Identifier) && @ctx.imports.key?(expression.callee.receiver.name)
83
+ imported_module = @ctx.imports.fetch(expression.callee.receiver.name)
84
+ imported_function = imported_module.functions[expression.callee.member]
85
+ if imported_function.nil? && imported_module.private_function?(expression.callee.member)
86
+ raise_sema_error("#{expression.callee.receiver.name}.#{expression.callee.member} is private to module #{imported_module.name}")
87
+ end
88
+
89
+ imported_function
90
+ elsif (type_expr = resolve_type_expression(expression.callee.receiver))
91
+ associated_function = lookup_method(type_expr, expression.callee.member)
92
+ if associated_function&.type&.receiver_type.nil?
93
+ receiver_type = type_expr
94
+ associated_function
95
+ else
96
+ if (imported_module = imported_module_with_private_method(type_expr, expression.callee.member))
97
+ raise_sema_error("#{type_expr}.#{expression.callee.member} is private to module #{imported_module.name}")
98
+ end
99
+
100
+ nil
101
+ end
102
+ else
103
+ receiver_type = infer_method_receiver_type(expression.callee.receiver, scopes:, member_name: expression.callee.member)
104
+ method = lookup_method(receiver_type, expression.callee.member)
105
+ if method
106
+ callable_kind = :method
107
+ receiver = expression.callee.receiver
108
+ method
109
+ else
110
+ if (imported_module = imported_module_with_private_method(receiver_type, expression.callee.member))
111
+ raise_sema_error("#{receiver_type}.#{expression.callee.member} is private to module #{imported_module.name}")
112
+ end
113
+
114
+ nil
115
+ end
116
+ end
117
+ end
118
+ return nil unless binding
119
+
120
+ type_arguments = resolve_specialization_type_arguments(expression)
121
+ [callable_kind, instantiate_function_binding_with_receiver(binding, type_arguments, receiver_type:), receiver]
122
+ end
123
+
124
+ def resolve_specialization_type_arguments(expression)
125
+ expression.arguments.map do |argument|
126
+ resolve_type_argument(argument.value, type_params: current_type_params)
127
+ end
128
+ end
129
+
130
+ def specialize_function_binding(binding, arguments, scopes:, receiver_type: nil)
131
+ return binding if binding.type_params.empty?
132
+
133
+ type_arguments = infer_function_type_arguments(binding, arguments, scopes:, receiver_type:)
134
+ instantiate_function_binding(binding, type_arguments)
135
+ end
136
+
137
+ def instantiate_function_binding_with_receiver(binding, explicit_type_arguments, receiver_type: nil)
138
+ if binding.type_params.empty?
139
+ raise_sema_error("function #{binding.name} is not generic and cannot be specialized")
140
+ end
141
+
142
+ receiver_substitutions = infer_receiver_type_substitutions(binding, receiver_type)
143
+ remaining_type_params = binding.type_params.reject { |name| receiver_substitutions.key?(name) }
144
+ unless remaining_type_params.length == explicit_type_arguments.length
145
+ raise_sema_error("function #{binding.name} expects #{remaining_type_params.length} type arguments, got #{explicit_type_arguments.length}")
146
+ end
147
+
148
+ substitutions = receiver_substitutions.dup
149
+ remaining_type_params.zip(explicit_type_arguments).each do |name, type_argument|
150
+ raise_sema_error("generic function #{binding.name} cannot be instantiated with ref types") if contains_ref_type?(type_argument)
151
+
152
+ substitutions[name] = type_argument
153
+ end
154
+
155
+ type_arguments = binding.type_params.map do |name|
156
+ inferred = substitutions[name]
157
+ raise_sema_error("cannot infer type argument #{name} for function #{binding.name}") unless inferred
158
+
159
+ inferred
160
+ end
161
+
162
+ instantiate_function_binding(binding, type_arguments)
163
+ end
164
+
165
+ def instantiate_function_binding(binding, type_arguments)
166
+ if binding.type_params.empty?
167
+ raise_sema_error("function #{binding.name} is not generic and cannot be specialized")
168
+ end
169
+
170
+ unless binding.type_params.length == type_arguments.length
171
+ raise_sema_error("function #{binding.name} expects #{binding.type_params.length} type arguments, got #{type_arguments.length}")
172
+ end
173
+
174
+ if type_arguments.any? { |type_argument| contains_ref_type?(type_argument) }
175
+ raise_sema_error("generic function #{binding.name} cannot be instantiated with ref types")
176
+ end
177
+
178
+ key = type_arguments.freeze
179
+ return binding.instances.fetch(key) if binding.instances.key?(key)
180
+
181
+ substitutions = binding.type_params.zip(type_arguments).to_h
182
+ validate_function_type_param_constraints!(binding, substitutions)
183
+ type = substitute_type(binding.type, substitutions)
184
+ body_params = binding.body_params.map { |param| substitute_value_binding(param, substitutions) }
185
+ validate_specialized_function_binding!(binding.name, type, body_params)
186
+
187
+ instance = FunctionBinding.new(
188
+ name: binding.name,
189
+ type:,
190
+ body_params:,
191
+ body_return_type: substitute_type(binding.body_return_type, substitutions),
192
+ ast: binding.ast,
193
+ external: binding.external,
194
+ async: binding.async,
195
+ type_params: [].freeze,
196
+ type_param_constraints: {}.freeze,
197
+ instances: {},
198
+ type_arguments: key,
199
+ owner: binding.owner,
200
+ specialization_owner: @current_specialization_owner || (binding.owner == self ? nil : self),
201
+ type_substitutions: substitutions.freeze,
202
+ declared_receiver_type: binding.declared_receiver_type ? substitute_type(binding.declared_receiver_type, substitutions) : nil,
203
+ )
204
+ binding.instances[key] = instance
205
+ end
206
+
207
+ def validate_function_type_param_constraints!(binding, substitutions)
208
+ binding.type_param_constraints.each do |name, constraints|
209
+ actual_type = substitutions[name]
210
+ raise_sema_error("cannot infer type argument #{name} for function #{binding.name}") unless actual_type
211
+
212
+ validate_type_param_constraint_binding!(constraints, actual_type, context: "function #{binding.name}")
213
+ end
214
+ end
215
+
216
+ def infer_function_type_arguments(binding, arguments, scopes:, receiver_type: nil)
217
+ expected_params = binding.type.params
218
+ unless call_arity_matches?(binding.type, arguments.length)
219
+ raise_sema_error(arity_error_message(binding.type, binding.name, arguments.length))
220
+ end
221
+
222
+ substitutions = infer_receiver_type_substitutions(binding, receiver_type)
223
+ expected_params.each_with_index do |parameter, index|
224
+ argument = arguments.fetch(index)
225
+ candidate_type = substitute_type(parameter.type, substitutions)
226
+ expected_argument_type = if callable_type?(candidate_type)
227
+ candidate_type
228
+ elsif contains_type_var?(candidate_type)
229
+ nil
230
+ else
231
+ candidate_type
232
+ end
233
+ actual_type = foreign_argument_actual_type(parameter, argument, scopes:, function_name: binding.name, expected_type: expected_argument_type)
234
+ collect_type_substitutions(parameter.type, actual_type, substitutions, binding.name)
235
+ end
236
+
237
+ binding.type_params.map do |name|
238
+ inferred = substitutions[name]
239
+ raise_sema_error("cannot infer type argument #{name} for function #{binding.name}") unless inferred
240
+
241
+ raise_sema_error("generic function #{binding.name} cannot be instantiated with ref types") if contains_ref_type?(inferred)
242
+
243
+ inferred
244
+ end
245
+ end
246
+
247
+ def collect_type_substitutions(pattern_type, actual_type, substitutions, function_name)
248
+ case pattern_type
249
+ when Types::TypeVar
250
+ existing = substitutions[pattern_type.name]
251
+ if existing && existing != actual_type
252
+ raise_sema_error("conflicting type argument #{pattern_type.name} for function #{function_name}: got #{existing} and #{actual_type}")
253
+ end
254
+
255
+ substitutions[pattern_type.name] ||= actual_type
256
+ when Types::Nullable
257
+ candidate = actual_type.is_a?(Types::Nullable) ? actual_type.base : actual_type
258
+ collect_type_substitutions(pattern_type.base, candidate, substitutions, function_name)
259
+ when Types::GenericInstance
260
+ if ref_type?(pattern_type) && !ref_type?(actual_type)
261
+ collect_type_substitutions(referenced_type(pattern_type), actual_type, substitutions, function_name)
262
+ return
263
+ end
264
+
265
+ if own_type?(actual_type) && (mutable_pointer_type?(pattern_type) || const_pointer_type?(pattern_type))
266
+ collect_type_substitutions(pointee_type(pattern_type), owned_referent_type(actual_type), substitutions, function_name)
267
+ return
268
+ end
269
+
270
+ return unless actual_type.is_a?(Types::GenericInstance)
271
+ return unless actual_type.name == pattern_type.name && actual_type.arguments.length == pattern_type.arguments.length
272
+
273
+ pattern_type.arguments.zip(actual_type.arguments).each do |expected_argument, actual_argument|
274
+ next if expected_argument.is_a?(Types::LiteralTypeArg)
275
+
276
+ collect_type_substitutions(expected_argument, actual_argument, substitutions, function_name)
277
+ end
278
+ when Types::VariantInstance
279
+ return unless actual_type.is_a?(Types::VariantInstance)
280
+ return unless actual_type.definition == pattern_type.definition || (actual_type.name == pattern_type.name && actual_type.arguments.length == pattern_type.arguments.length)
281
+
282
+ pattern_type.arguments.zip(actual_type.arguments).each do |expected_argument, actual_argument|
283
+ next if expected_argument.is_a?(Types::LiteralTypeArg)
284
+
285
+ collect_type_substitutions(expected_argument, actual_argument, substitutions, function_name)
286
+ end
287
+ when Types::Span
288
+ return unless actual_type.is_a?(Types::Span)
289
+
290
+ collect_type_substitutions(pattern_type.element_type, actual_type.element_type, substitutions, function_name)
291
+ when Types::Task
292
+ return unless actual_type.is_a?(Types::Task)
293
+
294
+ collect_type_substitutions(pattern_type.result_type, actual_type.result_type, substitutions, function_name)
295
+ when Types::Proc
296
+ if task_root_proc_type?(pattern_type) && actual_type.is_a?(Types::Task)
297
+ collect_type_substitutions(pattern_type.return_type, actual_type, substitutions, function_name)
298
+ return
299
+ end
300
+
301
+ actual_params = case actual_type
302
+ when Types::Proc
303
+ return unless actual_type.params.length == pattern_type.params.length
304
+
305
+ actual_type.params
306
+ when Types::Function
307
+ return if actual_type.receiver_type || actual_type.variadic
308
+ return unless actual_type.params.length == pattern_type.params.length
309
+
310
+ actual_type.params
311
+ else
312
+ return
313
+ end
314
+
315
+ pattern_type.params.zip(actual_params).each do |expected_param, actual_param|
316
+ collect_type_substitutions(expected_param.type, actual_param.type, substitutions, function_name)
317
+ end
318
+ collect_type_substitutions(pattern_type.return_type, actual_type.return_type, substitutions, function_name)
319
+ when Types::StructInstance
320
+ return unless actual_type.is_a?(Types::StructInstance)
321
+ return unless actual_type.definition == pattern_type.definition && actual_type.arguments.length == pattern_type.arguments.length
322
+
323
+ pattern_type.arguments.zip(actual_type.arguments).each do |expected_argument, actual_argument|
324
+ collect_type_substitutions(expected_argument, actual_argument, substitutions, function_name)
325
+ end
326
+ when Types::Function
327
+ return unless actual_type.is_a?(Types::Function)
328
+ return unless actual_type.params.length == pattern_type.params.length
329
+
330
+ pattern_type.params.zip(actual_type.params).each do |expected_param, actual_param|
331
+ collect_type_substitutions(expected_param.type, actual_param.type, substitutions, function_name)
332
+ end
333
+ collect_type_substitutions(pattern_type.return_type, actual_type.return_type, substitutions, function_name)
334
+ end
335
+ end
336
+
337
+ def substitute_value_binding(binding, substitutions)
338
+ ValueBinding.new(
339
+ id: binding.id,
340
+ name: binding.name,
341
+ storage_type: substitute_type(binding.storage_type, substitutions),
342
+ flow_type: binding.flow_type ? substitute_type(binding.flow_type, substitutions) : nil,
343
+ mutable: binding.mutable,
344
+ kind: binding.kind,
345
+ const_value: binding.const_value,
346
+ )
347
+ end
348
+
349
+ def validate_specialized_function_binding!(function_name, function_type, body_params)
350
+ function_type.params.each do |param|
351
+ validate_specialized_function_type!(param.type, function_name:, context: "parameter #{param.name}")
352
+ validate_specialized_function_type!(param.boundary_type, function_name:, context: "boundary parameter #{param.name}") if param.boundary_type
353
+ end
354
+ validate_specialized_function_type!(function_type.return_type, function_name:, context: "return type")
355
+ validate_specialized_function_type!(function_type.receiver_type, function_name:, context: "receiver type") if function_type.receiver_type
356
+
357
+ body_params.each do |param|
358
+ validate_specialized_function_type!(param.type, function_name:, context: "body parameter #{param.name}")
359
+ end
360
+ end
361
+
362
+ def validate_specialized_function_type!(type, function_name:, context:)
363
+ ValidateSpecializedTypeVisitor.new(
364
+ function_name:,
365
+ context:,
366
+ on_error: ->(msg) { raise_sema_error(msg) },
367
+ on_generic_instance: ->(name, args) { validate_generic_type!(name, args) },
368
+ ).visit(type)
369
+ end
370
+
371
+ def substitute_type(type, substitutions)
372
+ SubstituteTypeVisitor.new(substitutions).apply(type)
373
+ end
374
+
375
+ def bitwise_type?(type)
376
+ type.respond_to?(:bitwise?) && type.bitwise?
377
+ end
378
+
379
+ def callable_type?(type)
380
+ type.is_a?(Types::Function) || type.is_a?(Types::Proc)
381
+ end
382
+ end
383
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MilkTea
4
+ class SemanticAnalyzer
5
+ class Checker
6
+ private
7
+
8
+ def check_interface_conformances
9
+ expanded_declarations.each do |decl|
10
+ with_error_node(decl) do
11
+ next unless decl.is_a?(AST::StructDecl) || decl.is_a?(AST::OpaqueDecl)
12
+ next if decl.implements.empty?
13
+
14
+ receiver_type = @ctx.types.fetch(decl.name)
15
+ resolved_interfaces = []
16
+ seen = {}
17
+
18
+ decl.implements.each do |interface_ref|
19
+ interface = resolve_interface_ref(interface_ref)
20
+ raise_sema_error("duplicate interface #{decl.name} implements #{interface.name}") if seen.key?(interface)
21
+
22
+ seen[interface] = true
23
+ resolved_interfaces << interface
24
+ check_interface_conformance!(receiver_type, interface)
25
+ end
26
+
27
+ @ctx.implemented_interfaces[interface_implementation_key(receiver_type)] = resolved_interfaces.freeze
28
+ end
29
+ end
30
+ end
31
+
32
+ def check_interface_conformance!(receiver_type, interface)
33
+ interface.methods.each_value do |interface_method|
34
+ method = lookup_local_method_for_interface(receiver_type, interface_method.name)
35
+ raise_sema_error("type #{receiver_type} implements interface #{interface.name} but is missing method #{interface_method.name}") unless method
36
+
37
+ check_interface_method_match!(receiver_type, interface, interface_method, method)
38
+ end
39
+ end
40
+
41
+ def lookup_local_method_for_interface(receiver_type, name)
42
+ dispatch_receiver_type = method_dispatch_receiver_type(receiver_type)
43
+
44
+ method = @ctx.methods.fetch(receiver_type, {})[name]
45
+ method ||= @ctx.methods.fetch(dispatch_receiver_type, {})[name] unless dispatch_receiver_type == receiver_type
46
+ static_name = "static:#{name}"
47
+ method ||= @ctx.methods.fetch(receiver_type, {})[static_name]
48
+ method ||= @ctx.methods.fetch(dispatch_receiver_type, {})[static_name] unless dispatch_receiver_type == receiver_type
49
+ method
50
+ end
51
+
52
+ def check_interface_method_match!(receiver_type, interface, interface_method, method)
53
+ if method.ast.is_a?(AST::MethodDef) && method.ast.type_params.any?
54
+ raise_sema_error("type #{receiver_type} method #{method.name} does not satisfy interface #{interface.name}: interface methods cannot be implemented by generic methods")
55
+ end
56
+
57
+ if interface_method.kind == :static
58
+ raise_sema_error("type #{receiver_type} method #{method.name} does not satisfy interface #{interface.name}: method kind does not match") unless method.type.receiver_type.nil?
59
+ else
60
+ raise_sema_error("type #{receiver_type} method #{method.name} does not satisfy interface #{interface.name}: method kind does not match") if method.type.receiver_type.nil?
61
+
62
+ expected_editable = interface_method.kind == :editable
63
+ actual_editable = method.type.receiver_editable
64
+ if actual_editable != expected_editable
65
+ raise_sema_error("type #{receiver_type} method #{method.name} does not satisfy interface #{interface.name}: receiver editability does not match")
66
+ end
67
+ end
68
+
69
+ method_params = method.type.params.map(&:type)
70
+ interface_params = interface_method.params.map(&:type)
71
+ unless method_params == interface_params && method.type.return_type == interface_method.return_type && method.async == interface_method.async
72
+ raise_sema_error("type #{receiver_type} method #{method.name} does not satisfy interface #{interface.name}: signature does not match")
73
+ end
74
+ end
75
+
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MilkTea
4
+ class SemanticAnalyzer
5
+ class ModuleContext
6
+ attr_accessor :ast, :module_name, :module_kind
7
+ attr_accessor :imported_modules, :global_import_index
8
+ attr_accessor :const_declarations
9
+ attr_accessor :types, :interfaces, :attributes
10
+ attr_accessor :top_level_values, :top_level_functions
11
+ attr_accessor :imports, :methods, :implemented_interfaces
12
+ attr_accessor :resolved_attribute_applications, :validated_attribute_arguments, :attribute_application_bindings
13
+
14
+ def initialize(ast:, module_name:, module_kind:, imported_modules:, global_import_index:, const_declarations:)
15
+ @ast = ast
16
+ @module_name = module_name
17
+ @module_kind = module_kind
18
+ @imported_modules = imported_modules
19
+ @global_import_index = global_import_index
20
+ @const_declarations = const_declarations
21
+ @types = {}
22
+ @interfaces = {}
23
+ @attributes = {}
24
+ @top_level_values = {}
25
+ @top_level_functions = {}
26
+ @imports = {}
27
+ @methods = Hash.new { |hash, key| hash[key] = {} }
28
+ @implemented_interfaces = Hash.new { |hash, key| hash[key] = [] }
29
+ @resolved_attribute_applications = {}
30
+ @validated_attribute_arguments = {}
31
+ @attribute_application_bindings = {}
32
+ end
33
+ end
34
+ end
35
+ end