mt-lang 0.3.9 → 0.3.10

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 (200) hide show
  1. checksums.yaml +4 -4
  2. data/lib/milk_tea/base.rb +1 -2
  3. data/lib/milk_tea/bindings/bindgen/ast_parser.rb +0 -2
  4. data/lib/milk_tea/bindings/bindgen/declaration.rb +0 -2
  5. data/lib/milk_tea/bindings/bindgen/emitter.rb +0 -2
  6. data/lib/milk_tea/bindings/bindgen/overrides.rb +0 -2
  7. data/lib/milk_tea/bindings/bindgen/type_mapper.rb +51 -53
  8. data/lib/milk_tea/bindings/imported_bindings/generator.rb +7 -9
  9. data/lib/milk_tea/bindings/imported_bindings/method_source.rb +0 -2
  10. data/lib/milk_tea/bindings/imported_bindings/naming.rb +6 -8
  11. data/lib/milk_tea/bindings/imported_bindings.rb +0 -2
  12. data/lib/milk_tea/bindings/opengl_registry.rb +3 -7
  13. data/lib/milk_tea/bindings/steamworks.rb +12 -16
  14. data/lib/milk_tea/bindings/upstream_sources.rb +10 -14
  15. data/lib/milk_tea/bindings/vendored_box2d.rb +10 -12
  16. data/lib/milk_tea/bindings/vendored_cjson.rb +6 -8
  17. data/lib/milk_tea/bindings/vendored_flecs.rb +10 -12
  18. data/lib/milk_tea/bindings/vendored_glfw.rb +11 -13
  19. data/lib/milk_tea/bindings/vendored_libuv.rb +11 -13
  20. data/lib/milk_tea/bindings/vendored_pcre2.rb +11 -13
  21. data/lib/milk_tea/bindings/vendored_raylib.rb +6 -10
  22. data/lib/milk_tea/bindings/vendored_sdl3.rb +11 -13
  23. data/lib/milk_tea/bindings/vendored_steamworks.rb +1 -5
  24. data/lib/milk_tea/core/ast.rb +103 -45
  25. data/lib/milk_tea/core/async_runtime_installer.rb +0 -2
  26. data/lib/milk_tea/core/bindings/attribute_binding.rb +1 -3
  27. data/lib/milk_tea/core/c_backend/aggregate_utils.rb +147 -84
  28. data/lib/milk_tea/core/c_backend/control_flow_emission.rb +394 -396
  29. data/lib/milk_tea/core/c_backend/expressions.rb +489 -476
  30. data/lib/milk_tea/core/c_backend/feature_detection.rb +446 -437
  31. data/lib/milk_tea/core/c_backend/format_helpers.rb +0 -2
  32. data/lib/milk_tea/core/c_backend/reachability.rb +339 -341
  33. data/lib/milk_tea/core/c_backend/reinterpret.rb +231 -217
  34. data/lib/milk_tea/core/c_backend/runtime_helpers.rb +531 -526
  35. data/lib/milk_tea/core/c_backend/statements.rb +528 -530
  36. data/lib/milk_tea/core/c_backend/type_collectors.rb +1344 -1346
  37. data/lib/milk_tea/core/c_backend/type_declaration.rb +215 -213
  38. data/lib/milk_tea/core/c_backend/type_system.rb +347 -349
  39. data/lib/milk_tea/core/c_backend.rb +17 -9
  40. data/lib/milk_tea/core/compatibility_helpers.rb +0 -2
  41. data/lib/milk_tea/core/compile_time/const_eval.rb +7 -12
  42. data/lib/milk_tea/core/compile_time.rb +32 -38
  43. data/lib/milk_tea/core/control_flow/builder.rb +3 -5
  44. data/lib/milk_tea/core/control_flow/constant_propagation.rb +14 -17
  45. data/lib/milk_tea/core/control_flow/definite_assignment.rb +0 -1
  46. data/lib/milk_tea/core/ir.rb +10 -10
  47. data/lib/milk_tea/core/lexer/character_classes.rb +5 -7
  48. data/lib/milk_tea/core/lexer/format_strings.rb +7 -9
  49. data/lib/milk_tea/core/lexer/heredocs.rb +22 -22
  50. data/lib/milk_tea/core/lexer/indentation.rb +0 -2
  51. data/lib/milk_tea/core/lexer/numbers.rb +0 -2
  52. data/lib/milk_tea/core/lexer/recovery.rb +0 -2
  53. data/lib/milk_tea/core/lexer/strings.rb +0 -2
  54. data/lib/milk_tea/core/lexer/symbols.rb +0 -2
  55. data/lib/milk_tea/core/lexer/trivia.rb +0 -2
  56. data/lib/milk_tea/core/lexer.rb +0 -2
  57. data/lib/milk_tea/core/lowering/async/analysis.rb +0 -2
  58. data/lib/milk_tea/core/lowering/async/lowering.rb +1264 -1265
  59. data/lib/milk_tea/core/lowering/async/normalization.rb +0 -2
  60. data/lib/milk_tea/core/lowering/async.rb +627 -630
  61. data/lib/milk_tea/core/lowering/block.rb +413 -416
  62. data/lib/milk_tea/core/lowering/calls.rb +1381 -1384
  63. data/lib/milk_tea/core/lowering/declarations.rb +180 -183
  64. data/lib/milk_tea/core/lowering/dyn.rb +48 -50
  65. data/lib/milk_tea/core/lowering/events.rb +983 -985
  66. data/lib/milk_tea/core/lowering/expressions.rb +1513 -1518
  67. data/lib/milk_tea/core/lowering/foreign_cstr.rb +181 -184
  68. data/lib/milk_tea/core/lowering/functions.rb +185 -188
  69. data/lib/milk_tea/core/lowering/loops.rb +1028 -1031
  70. data/lib/milk_tea/core/lowering/proc.rb +363 -366
  71. data/lib/milk_tea/core/lowering/resolve.rb +2133 -2135
  72. data/lib/milk_tea/core/lowering/scans.rb +179 -181
  73. data/lib/milk_tea/core/lowering/str_buffer.rb +102 -105
  74. data/lib/milk_tea/core/lowering/utils.rb +1040 -1044
  75. data/lib/milk_tea/core/lowering.rb +5 -7
  76. data/lib/milk_tea/core/module_binder.rb +0 -2
  77. data/lib/milk_tea/core/module_loader/errors.rb +4 -2
  78. data/lib/milk_tea/core/module_loader.rb +113 -20
  79. data/lib/milk_tea/core/module_path_resolver.rb +0 -2
  80. data/lib/milk_tea/core/module_roots.rb +6 -8
  81. data/lib/milk_tea/core/parser/attributes.rb +0 -2
  82. data/lib/milk_tea/core/parser/blocks.rb +0 -2
  83. data/lib/milk_tea/core/parser/declarations.rb +0 -2
  84. data/lib/milk_tea/core/parser/expressions.rb +8 -9
  85. data/lib/milk_tea/core/parser/recovery.rb +0 -2
  86. data/lib/milk_tea/core/parser/statements.rb +0 -2
  87. data/lib/milk_tea/core/parser/types.rb +8 -10
  88. data/lib/milk_tea/core/parser.rb +0 -2
  89. data/lib/milk_tea/core/pretty_printer/ast_formatter.rb +31 -33
  90. data/lib/milk_tea/core/pretty_printer/base_formatter.rb +0 -2
  91. data/lib/milk_tea/core/pretty_printer/ir_formatter.rb +0 -2
  92. data/lib/milk_tea/core/semantic_analyzer/analysis_context.rb +0 -2
  93. data/lib/milk_tea/core/semantic_analyzer/attributes.rb +14 -16
  94. data/lib/milk_tea/core/semantic_analyzer/calls.rb +0 -2
  95. data/lib/milk_tea/core/semantic_analyzer/expressions.rb +1 -14
  96. data/lib/milk_tea/core/semantic_analyzer/flow_refinement.rb +18 -21
  97. data/lib/milk_tea/core/semantic_analyzer/foreign_functions.rb +0 -3
  98. data/lib/milk_tea/core/semantic_analyzer/function_binding.rb +12 -15
  99. data/lib/milk_tea/core/semantic_analyzer/generics.rb +57 -59
  100. data/lib/milk_tea/core/semantic_analyzer/interface_conformance.rb +0 -2
  101. data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +5 -9
  102. data/lib/milk_tea/core/semantic_analyzer/nullability.rb +0 -3
  103. data/lib/milk_tea/core/semantic_analyzer/statements.rb +35 -40
  104. data/lib/milk_tea/core/semantic_analyzer/top_level.rb +10 -12
  105. data/lib/milk_tea/core/semantic_analyzer/type_compatibility.rb +0 -6
  106. data/lib/milk_tea/core/semantic_analyzer/type_declaration.rb +102 -105
  107. data/lib/milk_tea/core/semantic_analyzer.rb +17 -8
  108. data/lib/milk_tea/core/types/layout.rb +21 -22
  109. data/lib/milk_tea/core/types/predicates.rb +0 -2
  110. data/lib/milk_tea/core/types/registry.rb +16 -18
  111. data/lib/milk_tea/core/types/visitor.rb +0 -4
  112. data/lib/milk_tea/dap/backends/lldb_dap.rb +0 -2
  113. data/lib/milk_tea/dap/protocol.rb +1 -1
  114. data/lib/milk_tea/dap/server/breakpoints.rb +0 -2
  115. data/lib/milk_tea/dap/server/debug_map.rb +0 -2
  116. data/lib/milk_tea/dap/server/handlers.rb +0 -2
  117. data/lib/milk_tea/dap/server/launch.rb +0 -2
  118. data/lib/milk_tea/dap/server/lldb_backend.rb +8 -10
  119. data/lib/milk_tea/dap/server/pause_diagnostics.rb +14 -16
  120. data/lib/milk_tea/dap/server/utilities.rb +0 -2
  121. data/lib/milk_tea/dap/server/wire.rb +0 -2
  122. data/lib/milk_tea/dap/server.rb +0 -2
  123. data/lib/milk_tea/lsp/diagnostics.rb +16 -16
  124. data/lib/milk_tea/lsp/server/call_hierarchy.rb +11 -12
  125. data/lib/milk_tea/lsp/server/code_actions.rb +355 -357
  126. data/lib/milk_tea/lsp/server/code_lens.rb +23 -25
  127. data/lib/milk_tea/lsp/server/completion.rb +873 -875
  128. data/lib/milk_tea/lsp/server/configuration.rb +129 -131
  129. data/lib/milk_tea/lsp/server/debug_info.rb +0 -2
  130. data/lib/milk_tea/lsp/server/definition.rb +564 -565
  131. data/lib/milk_tea/lsp/server/diagnostics_scheduling.rb +191 -193
  132. data/lib/milk_tea/lsp/server/execute_command.rb +0 -2
  133. data/lib/milk_tea/lsp/server/folding_range.rb +0 -4
  134. data/lib/milk_tea/lsp/server/formatting.rb +478 -480
  135. data/lib/milk_tea/lsp/server/hover.rb +1282 -1284
  136. data/lib/milk_tea/lsp/server/inlay_hints.rb +179 -181
  137. data/lib/milk_tea/lsp/server/lifecycle.rb +192 -194
  138. data/lib/milk_tea/lsp/server/linked_editing_range.rb +0 -2
  139. data/lib/milk_tea/lsp/server/on_type_formatting.rb +0 -2
  140. data/lib/milk_tea/lsp/server/progress.rb +0 -2
  141. data/lib/milk_tea/lsp/server/references.rb +316 -318
  142. data/lib/milk_tea/lsp/server/rename.rb +445 -447
  143. data/lib/milk_tea/lsp/server/selection_range.rb +0 -4
  144. data/lib/milk_tea/lsp/server/semantic_tokens.rb +1318 -1320
  145. data/lib/milk_tea/lsp/server/signature_help.rb +146 -148
  146. data/lib/milk_tea/lsp/server/text_documents.rb +99 -101
  147. data/lib/milk_tea/lsp/server/type_hierarchy.rb +2 -4
  148. data/lib/milk_tea/lsp/server/utilities.rb +397 -399
  149. data/lib/milk_tea/lsp/server.rb +0 -3
  150. data/lib/milk_tea/lsp/workspace/analysis.rb +40 -42
  151. data/lib/milk_tea/lsp/workspace/dependency_graph.rb +4 -10
  152. data/lib/milk_tea/lsp/workspace/utilities.rb +19 -19
  153. data/lib/milk_tea/packages/atomic_write.rb +4 -5
  154. data/lib/milk_tea/packages/dependency_solver.rb +15 -15
  155. data/lib/milk_tea/packages/lock.rb +4 -4
  156. data/lib/milk_tea/packages/manager_cli.rb +1 -1
  157. data/lib/milk_tea/packages/manifest.rb +3 -3
  158. data/lib/milk_tea/packages/registry_store.rb +4 -6
  159. data/lib/milk_tea/packages/services.rb +16 -16
  160. data/lib/milk_tea/packages/source_cache.rb +4 -6
  161. data/lib/milk_tea/packages/source_resolver.rb +44 -44
  162. data/lib/milk_tea/packages/version.rb +8 -8
  163. data/lib/milk_tea/tooling/build.rb +3 -7
  164. data/lib/milk_tea/tooling/build_cache.rb +0 -2
  165. data/lib/milk_tea/tooling/debug_info_formatter.rb +31 -33
  166. data/lib/milk_tea/tooling/debug_map.rb +8 -10
  167. data/lib/milk_tea/tooling/docs_app.rb +0 -2
  168. data/lib/milk_tea/tooling/linter/doc_tags.rb +25 -27
  169. data/lib/milk_tea/tooling/linter/fix_engine.rb +87 -24
  170. data/lib/milk_tea/tooling/linter/flow_rules.rb +44 -46
  171. data/lib/milk_tea/tooling/linter/imports_platform.rb +14 -16
  172. data/lib/milk_tea/tooling/linter/release_rules.rb +3 -5
  173. data/lib/milk_tea/tooling/linter/reserved_names.rb +23 -25
  174. data/lib/milk_tea/tooling/linter/rules.rb +87 -89
  175. data/lib/milk_tea/tooling/linter/source_helpers.rb +40 -42
  176. data/lib/milk_tea/tooling/linter/trailing_comma.rb +17 -19
  177. data/lib/milk_tea/tooling/linter/visitors.rb +112 -54
  178. data/lib/milk_tea/tooling/linter.rb +0 -2
  179. data/lib/milk_tea/tooling/project_scaffold.rb +0 -2
  180. data/lib/milk_tea/tooling/run.rb +0 -2
  181. data/lib/milk_tea/tooling/toolchain_cli.rb +0 -2
  182. data/std/cli.mt +13 -32
  183. data/std/color.mt +28 -28
  184. data/std/encoding.mt +4 -4
  185. data/std/graph.mt +1 -2
  186. data/std/hash.mt +14 -14
  187. data/std/http/server.mt +3 -3
  188. data/std/input.mt +1 -1
  189. data/std/json.mt +1 -1
  190. data/std/linear_algebra.mt +6 -6
  191. data/std/net/mux.mt +1 -1
  192. data/std/noise.mt +23 -23
  193. data/std/parse.mt +2 -2
  194. data/std/process.mt +3 -4
  195. data/std/sparse_set.mt +1 -1
  196. data/std/steering.mt +5 -5
  197. data/std/str.mt +1 -1
  198. data/std/tween.mt +4 -4
  199. data/std/utility.mt +3 -3
  200. metadata +2 -2
@@ -2,8 +2,6 @@
2
2
 
3
3
  module MilkTea
4
4
  module LowererResolve
5
- private
6
-
7
5
  PASS_THROUGH_BUILTINS = {
8
6
  "fatal" => :fatal,
9
7
  "ref_of" => :ref_of,
@@ -18,2577 +16,2577 @@ module MilkTea
18
16
  ].freeze
19
17
 
20
18
 
21
- def direct_function_to_proc_contextual_compatibility?(expression, actual_type, env:, expected_type:)
22
- return false unless actual_type.is_a?(Types::Function) && proc_type?(expected_type)
23
- return false unless direct_function_identity_expression?(expression, env)
19
+ def direct_function_to_proc_contextual_compatibility?(expression, actual_type, env:, expected_type:)
20
+ return false unless actual_type.is_a?(Types::Function) && proc_type?(expected_type)
21
+ return false unless direct_function_identity_expression?(expression, env)
24
22
 
25
- function_type_matches_proc_type?(actual_type, expected_type)
26
- end
23
+ function_type_matches_proc_type?(actual_type, expected_type)
24
+ end
27
25
 
28
- def direct_function_identity_expression?(expression, env)
29
- case expression
30
- when AST::Identifier
31
- return false if lookup_value(expression.name, env)
32
- return false unless @ctx.functions.key?(expression.name)
26
+ def direct_function_identity_expression?(expression, env)
27
+ case expression
28
+ when AST::Identifier
29
+ return false if lookup_value(expression.name, env)
30
+ return false unless @ctx.functions.key?(expression.name)
33
31
 
34
- binding = @ctx.functions.fetch(expression.name)
35
- !binding.type_params.any? && !foreign_function_binding?(binding)
36
- when AST::MemberAccess
37
- return false unless expression.receiver.is_a?(AST::Identifier) && @ctx.imports.key?(expression.receiver.name)
32
+ binding = @ctx.functions.fetch(expression.name)
33
+ !binding.type_params.any? && !foreign_function_binding?(binding)
34
+ when AST::MemberAccess
35
+ return false unless expression.receiver.is_a?(AST::Identifier) && @ctx.imports.key?(expression.receiver.name)
38
36
 
39
- imported_module = @ctx.imports.fetch(expression.receiver.name)
40
- return false unless imported_module.functions.key?(expression.member)
37
+ imported_module = @ctx.imports.fetch(expression.receiver.name)
38
+ return false unless imported_module.functions.key?(expression.member)
41
39
 
42
- binding = imported_module.functions.fetch(expression.member)
43
- !binding.type_params.any? && !foreign_function_binding?(binding)
44
- when AST::Specialization
45
- callable_resolution = resolve_specialized_callable_binding(expression, env:)
46
- return false unless callable_resolution
40
+ binding = imported_module.functions.fetch(expression.member)
41
+ !binding.type_params.any? && !foreign_function_binding?(binding)
42
+ when AST::Specialization
43
+ callable_resolution = resolve_specialized_callable_binding(expression, env:)
44
+ return false unless callable_resolution
47
45
 
48
- callable_kind, binding, = callable_resolution
49
- callable_kind == :function && !foreign_function_binding?(binding)
46
+ callable_kind, binding, = callable_resolution
47
+ callable_kind == :function && !foreign_function_binding?(binding)
48
+ else
49
+ false
50
+ end
51
+ end
52
+
53
+ def lower_direct_function_to_proc_expression(source_expression, source_function, env:, expected_type:)
54
+ raise LoweringError.new("function-to-proc coercion requires a direct function name", line: 0, column: 0, path: @ctx.current_analysis_path) unless source_function.is_a?(IR::Name)
55
+
56
+ proc_id = fresh_proc_symbol
57
+ invoke_c_name = "#{@ctx.module_prefix}__proc_#{proc_id}__invoke"
58
+ release_linkage_name = "#{@ctx.module_prefix}__proc_#{proc_id}__release"
59
+ retain_c_name = "#{@ctx.module_prefix}__proc_#{proc_id}__retain"
60
+
61
+ @artifacts.synthetic_functions << build_direct_function_proc_invoke_function(source_expression, source_function.name, source_function.type, expected_type, invoke_c_name)
62
+ @artifacts.synthetic_functions << build_proc_noop_release_function(release_linkage_name)
63
+ @artifacts.synthetic_functions << build_proc_noop_retain_function(retain_c_name)
64
+
65
+ IR::AggregateLiteral.new(
66
+ type: expected_type,
67
+ fields: [
68
+ IR::AggregateField.new(name: "env", value: IR::NullLiteral.new(type: proc_env_pointer_type)),
69
+ IR::AggregateField.new(name: "invoke", value: IR::Name.new(name: invoke_c_name, type: proc_invoke_function_type(expected_type), pointer: false)),
70
+ IR::AggregateField.new(name: "release", value: IR::Name.new(name: release_linkage_name, type: proc_release_function_type, pointer: false)),
71
+ IR::AggregateField.new(name: "retain", value: IR::Name.new(name: retain_c_name, type: proc_retain_function_type, pointer: false)),
72
+ ],
73
+ )
74
+ end
75
+
76
+ def build_direct_function_proc_invoke_function(source_expression, function_c_name, function_type, proc_type, invoke_c_name)
77
+ env = empty_env
78
+ params = [IR::Param.new(name: "env", linkage_name: "__mt_proc_env", type: proc_env_pointer_type, pointer: false)]
79
+ parameter_setup = []
80
+ call_arguments = []
81
+
82
+ proc_type.params.each_with_index do |param, index|
83
+ linkage_name = c_local_name(param.name || "arg#{index}")
84
+ if array_type?(param.type)
85
+ input_linkage_name = "#{linkage_name}_input"
86
+ params << IR::Param.new(name: param.name || "arg#{index}", linkage_name: input_linkage_name, type: param.type, pointer: false)
87
+ env[:scopes].last[param.name || "arg#{index}"] = local_binding(type: param.type, linkage_name:, mutable: param.mutable, pointer: false)
88
+ parameter_setup << IR::LocalDecl.new(
89
+ name: param.name || "arg#{index}",
90
+ linkage_name:,
91
+ type: param.type,
92
+ value: IR::Name.new(name: input_linkage_name, type: param.type, pointer: false),
93
+ )
94
+ call_arguments << IR::Name.new(name: linkage_name, type: param.type, pointer: false)
50
95
  else
51
- false
96
+ env[:scopes].last[param.name || "arg#{index}"] = local_binding(type: param.type, linkage_name:, mutable: param.mutable, pointer: false)
97
+ params << IR::Param.new(name: param.name || "arg#{index}", linkage_name:, type: param.type, pointer: false)
98
+ call_arguments << IR::Name.new(name: linkage_name, type: param.type, pointer: false)
52
99
  end
53
100
  end
54
101
 
55
- def lower_direct_function_to_proc_expression(source_expression, source_function, env:, expected_type:)
56
- raise LoweringError.new("function-to-proc coercion requires a direct function name", line: 0, column: 0, path: @ctx.current_analysis_path) unless source_function.is_a?(IR::Name)
57
-
58
- proc_id = fresh_proc_symbol
59
- invoke_c_name = "#{@ctx.module_prefix}__proc_#{proc_id}__invoke"
60
- release_linkage_name = "#{@ctx.module_prefix}__proc_#{proc_id}__release"
61
- retain_c_name = "#{@ctx.module_prefix}__proc_#{proc_id}__retain"
62
-
63
- @artifacts.synthetic_functions << build_direct_function_proc_invoke_function(source_expression, source_function.name, source_function.type, expected_type, invoke_c_name)
64
- @artifacts.synthetic_functions << build_proc_noop_release_function(release_linkage_name)
65
- @artifacts.synthetic_functions << build_proc_noop_retain_function(retain_c_name)
66
-
67
- IR::AggregateLiteral.new(
68
- type: expected_type,
69
- fields: [
70
- IR::AggregateField.new(name: "env", value: IR::NullLiteral.new(type: proc_env_pointer_type)),
71
- IR::AggregateField.new(name: "invoke", value: IR::Name.new(name: invoke_c_name, type: proc_invoke_function_type(expected_type), pointer: false)),
72
- IR::AggregateField.new(name: "release", value: IR::Name.new(name: release_linkage_name, type: proc_release_function_type, pointer: false)),
73
- IR::AggregateField.new(name: "retain", value: IR::Name.new(name: retain_c_name, type: proc_retain_function_type, pointer: false)),
74
- ],
75
- )
76
- end
77
-
78
- def build_direct_function_proc_invoke_function(source_expression, function_c_name, function_type, proc_type, invoke_c_name)
79
- env = empty_env
80
- params = [IR::Param.new(name: "env", linkage_name: "__mt_proc_env", type: proc_env_pointer_type, pointer: false)]
81
- parameter_setup = []
82
- call_arguments = []
83
-
84
- proc_type.params.each_with_index do |param, index|
85
- linkage_name = c_local_name(param.name || "arg#{index}")
86
- if array_type?(param.type)
87
- input_linkage_name = "#{linkage_name}_input"
88
- params << IR::Param.new(name: param.name || "arg#{index}", linkage_name: input_linkage_name, type: param.type, pointer: false)
89
- env[:scopes].last[param.name || "arg#{index}"] = local_binding(type: param.type, linkage_name:, mutable: param.mutable, pointer: false)
90
- parameter_setup << IR::LocalDecl.new(
91
- name: param.name || "arg#{index}",
92
- linkage_name:,
93
- type: param.type,
94
- value: IR::Name.new(name: input_linkage_name, type: param.type, pointer: false),
95
- )
96
- call_arguments << IR::Name.new(name: linkage_name, type: param.type, pointer: false)
97
- else
98
- env[:scopes].last[param.name || "arg#{index}"] = local_binding(type: param.type, linkage_name:, mutable: param.mutable, pointer: false)
99
- params << IR::Param.new(name: param.name || "arg#{index}", linkage_name:, type: param.type, pointer: false)
100
- call_arguments << IR::Name.new(name: linkage_name, type: param.type, pointer: false)
101
- end
102
- end
103
-
104
- call = IR::Call.new(callee: function_c_name, arguments: call_arguments, type: proc_type.return_type)
105
- body = if proc_type.return_type == @ctx.types.fetch("void")
106
- parameter_setup + [IR::ExpressionStmt.new(expression: call), IR::ReturnStmt.new(value: nil)]
107
- else
108
- parameter_setup + [IR::ReturnStmt.new(value: call)]
109
- end
110
-
111
- IR::Function.new(name: invoke_c_name, linkage_name: invoke_c_name, params:, return_type: proc_type.return_type, body:, entry_point: false)
112
- end
113
-
114
- def lower_array_to_span_expression(expression, target_type)
115
- array_type = expression.type
116
- array_type = referenced_type(array_type) if ref_type?(array_type)
117
-
118
- IR::AggregateLiteral.new(
119
- type: target_type,
120
- fields: [
121
- IR::AggregateField.new(
122
- name: "data",
123
- value: IR::AddressOf.new(
124
- expression: IR::Index.new(
125
- receiver: expression,
126
- index: IR::IntegerLiteral.new(value: 0, type: @ctx.types.fetch("ptr_uint")),
127
- type: target_type.element_type,
128
- ),
129
- type: pointer_to(target_type.element_type),
130
- ),
131
- ),
132
- IR::AggregateField.new(
133
- name: "len",
134
- value: IR::IntegerLiteral.new(value: array_length(array_type), type: @ctx.types.fetch("ptr_uint")),
135
- ),
136
- ],
137
- )
138
- end
102
+ call = IR::Call.new(callee: function_c_name, arguments: call_arguments, type: proc_type.return_type)
103
+ body = if proc_type.return_type == @ctx.types.fetch("void")
104
+ parameter_setup + [IR::ExpressionStmt.new(expression: call), IR::ReturnStmt.new(value: nil)]
105
+ else
106
+ parameter_setup + [IR::ReturnStmt.new(value: call)]
107
+ end
139
108
 
140
- def lower_str_buffer_to_span_expression(expression, target_type)
141
- IR::AggregateLiteral.new(
142
- type: target_type,
143
- fields: [
144
- IR::AggregateField.new(
145
- name: "data",
146
- value: IR::Call.new(
147
- callee: "mt_str_buffer_prepare_write",
148
- arguments: [
149
- lower_str_buffer_data_pointer_from_lowered(expression),
150
- IR::IntegerLiteral.new(value: str_buffer_capacity(expression.type), type: @ctx.types.fetch("ptr_uint")),
151
- lower_str_buffer_dirty_pointer_from_lowered(expression),
152
- ],
153
- type: pointer_to(target_type.element_type),
109
+ IR::Function.new(name: invoke_c_name, linkage_name: invoke_c_name, params:, return_type: proc_type.return_type, body:, entry_point: false)
110
+ end
111
+
112
+ def lower_array_to_span_expression(expression, target_type)
113
+ array_type = expression.type
114
+ array_type = referenced_type(array_type) if ref_type?(array_type)
115
+
116
+ IR::AggregateLiteral.new(
117
+ type: target_type,
118
+ fields: [
119
+ IR::AggregateField.new(
120
+ name: "data",
121
+ value: IR::AddressOf.new(
122
+ expression: IR::Index.new(
123
+ receiver: expression,
124
+ index: IR::IntegerLiteral.new(value: 0, type: @ctx.types.fetch("ptr_uint")),
125
+ type: target_type.element_type,
154
126
  ),
127
+ type: pointer_to(target_type.element_type),
155
128
  ),
156
- IR::AggregateField.new(
157
- name: "len",
158
- value: IR::IntegerLiteral.new(value: str_buffer_storage_capacity(expression.type), type: @ctx.types.fetch("ptr_uint")),
129
+ ),
130
+ IR::AggregateField.new(
131
+ name: "len",
132
+ value: IR::IntegerLiteral.new(value: array_length(array_type), type: @ctx.types.fetch("ptr_uint")),
133
+ ),
134
+ ],
135
+ )
136
+ end
137
+
138
+ def lower_str_buffer_to_span_expression(expression, target_type)
139
+ IR::AggregateLiteral.new(
140
+ type: target_type,
141
+ fields: [
142
+ IR::AggregateField.new(
143
+ name: "data",
144
+ value: IR::Call.new(
145
+ callee: "mt_str_buffer_prepare_write",
146
+ arguments: [
147
+ lower_str_buffer_data_pointer_from_lowered(expression),
148
+ IR::IntegerLiteral.new(value: str_buffer_capacity(expression.type), type: @ctx.types.fetch("ptr_uint")),
149
+ lower_str_buffer_dirty_pointer_from_lowered(expression),
150
+ ],
151
+ type: pointer_to(target_type.element_type),
159
152
  ),
160
- ],
161
- )
162
- end
163
-
164
- def contextual_numeric_compatibility?(expression, actual_type, expected_type, env:, external_numeric: false, contextual_int_to_float: false)
165
- return true if exact_compile_time_numeric_compatibility?(actual_type, expression, expected_type, env:)
166
- return true if integer_to_char_compatibility?(actual_type, expected_type)
167
- return true if external_numeric && external_numeric_compatibility?(actual_type, expected_type)
168
- return true if contextual_int_to_float && contextual_int_to_float_compatibility?(actual_type, expected_type)
169
-
153
+ ),
154
+ IR::AggregateField.new(
155
+ name: "len",
156
+ value: IR::IntegerLiteral.new(value: str_buffer_storage_capacity(expression.type), type: @ctx.types.fetch("ptr_uint")),
157
+ ),
158
+ ],
159
+ )
160
+ end
161
+
162
+ def contextual_numeric_compatibility?(expression, actual_type, expected_type, env:, external_numeric: false, contextual_int_to_float: false)
163
+ return true if exact_compile_time_numeric_compatibility?(actual_type, expression, expected_type, env:)
164
+ return true if integer_to_char_compatibility?(actual_type, expected_type)
165
+ return true if external_numeric && external_numeric_compatibility?(actual_type, expected_type)
166
+ return true if contextual_int_to_float && contextual_int_to_float_compatibility?(actual_type, expected_type)
167
+
168
+ false
169
+ end
170
+
171
+ def cstr_backed_expression?(expression, env)
172
+ return true if infer_expression_type(expression, env:) == @ctx.types.fetch("cstr")
173
+
174
+ case expression
175
+ when AST::StringLiteral
176
+ true
177
+ when AST::Identifier
178
+ binding_cstr_backed?(lookup_value(expression.name, env))
179
+ when AST::IfExpr
180
+ then_env = env_with_refinements(env, flow_refinements(expression.condition, truthy: true, env:))
181
+ else_env = env_with_refinements(env, flow_refinements(expression.condition, truthy: false, env:))
182
+ cstr_backed_expression?(expression.then_expression, then_env) &&
183
+ cstr_backed_expression?(expression.else_expression, else_env)
184
+ when AST::UnsafeExpr
185
+ cstr_backed_expression?(expression.expression, env)
186
+ else
170
187
  false
171
188
  end
172
-
173
- def cstr_backed_expression?(expression, env)
174
- return true if infer_expression_type(expression, env:) == @ctx.types.fetch("cstr")
175
-
176
- case expression
177
- when AST::StringLiteral
178
- true
179
- when AST::Identifier
180
- binding_cstr_backed?(lookup_value(expression.name, env))
181
- when AST::IfExpr
182
- then_env = env_with_refinements(env, flow_refinements(expression.condition, truthy: true, env:))
183
- else_env = env_with_refinements(env, flow_refinements(expression.condition, truthy: false, env:))
184
- cstr_backed_expression?(expression.then_expression, then_env) &&
185
- cstr_backed_expression?(expression.else_expression, else_env)
186
- when AST::UnsafeExpr
187
- cstr_backed_expression?(expression.expression, env)
188
- else
189
- false
190
- end
191
- rescue LoweringError
189
+ rescue LoweringError
190
+ false
191
+ end
192
+
193
+ def cstr_list_backed_expression?(expression, env)
194
+ actual_type = infer_expression_type(expression, env:)
195
+ return false unless array_type?(actual_type)
196
+
197
+ element_type = array_element_type(actual_type)
198
+ return false unless element_type == @ctx.types.fetch("str") || element_type == @ctx.types.fetch("cstr")
199
+
200
+ case expression
201
+ when AST::Identifier
202
+ binding_cstr_list_backed?(lookup_value(expression.name, env))
203
+ when AST::Call
204
+ expression.arguments.all? { |argument| cstr_backed_expression?(argument.value, env) }
205
+ when AST::IfExpr
206
+ then_env = env_with_refinements(env, flow_refinements(expression.condition, truthy: true, env:))
207
+ else_env = env_with_refinements(env, flow_refinements(expression.condition, truthy: false, env:))
208
+ cstr_list_backed_expression?(expression.then_expression, then_env) &&
209
+ cstr_list_backed_expression?(expression.else_expression, else_env)
210
+ when AST::UnsafeExpr
211
+ cstr_list_backed_expression?(expression.expression, env)
212
+ else
192
213
  false
193
214
  end
215
+ rescue LoweringError
216
+ false
217
+ end
194
218
 
195
- def cstr_list_backed_expression?(expression, env)
196
- actual_type = infer_expression_type(expression, env:)
197
- return false unless array_type?(actual_type)
198
-
199
- element_type = array_element_type(actual_type)
200
- return false unless element_type == @ctx.types.fetch("str") || element_type == @ctx.types.fetch("cstr")
201
-
202
- case expression
203
- when AST::Identifier
204
- binding_cstr_list_backed?(lookup_value(expression.name, env))
205
- when AST::Call
206
- expression.arguments.all? { |argument| cstr_backed_expression?(argument.value, env) }
207
- when AST::IfExpr
208
- then_env = env_with_refinements(env, flow_refinements(expression.condition, truthy: true, env:))
209
- else_env = env_with_refinements(env, flow_refinements(expression.condition, truthy: false, env:))
210
- cstr_list_backed_expression?(expression.then_expression, then_env) &&
211
- cstr_list_backed_expression?(expression.else_expression, else_env)
212
- when AST::UnsafeExpr
213
- cstr_list_backed_expression?(expression.expression, env)
214
- else
215
- false
216
- end
217
- rescue LoweringError
218
- false
219
- end
219
+ def cstr_backed_storage_value?(type, expression, env)
220
+ return false unless expression
221
+ return true if type == @ctx.types.fetch("cstr")
222
+ return false unless type == @ctx.types.fetch("str")
220
223
 
221
- def cstr_backed_storage_value?(type, expression, env)
222
- return false unless expression
223
- return true if type == @ctx.types.fetch("cstr")
224
- return false unless type == @ctx.types.fetch("str")
224
+ cstr_backed_expression?(expression, env)
225
+ end
225
226
 
226
- cstr_backed_expression?(expression, env)
227
- end
227
+ def cstr_list_backed_storage_value?(type, expression, env)
228
+ return false unless expression
229
+ return false unless cstr_list_trackable_type?(type)
230
+
231
+ cstr_list_backed_expression?(expression, env)
232
+ end
228
233
 
229
- def cstr_list_backed_storage_value?(type, expression, env)
230
- return false unless expression
231
- return false unless cstr_list_trackable_type?(type)
234
+ def update_cstr_metadata_for_assignment!(statement, prepared_value, env)
235
+ if statement.target.is_a?(AST::Identifier)
236
+ binding = lookup_value(statement.target.name, env)
237
+ return unless binding
232
238
 
233
- cstr_list_backed_expression?(expression, env)
239
+ replace_binding_cstr_metadata!(
240
+ statement.target.name,
241
+ env,
242
+ cstr_backed: statement.operator == "=" ? cstr_backed_storage_value?(binding[:type], prepared_value, env) : false,
243
+ cstr_list_backed: statement.operator == "=" ? cstr_list_backed_storage_value?(binding[:type], prepared_value, env) : false,
244
+ )
245
+ return
234
246
  end
235
247
 
236
- def update_cstr_metadata_for_assignment!(statement, prepared_value, env)
237
- if statement.target.is_a?(AST::Identifier)
238
- binding = lookup_value(statement.target.name, env)
239
- return unless binding
248
+ return unless statement.target.is_a?(AST::IndexAccess) && statement.target.receiver.is_a?(AST::Identifier)
240
249
 
241
- replace_binding_cstr_metadata!(
242
- statement.target.name,
243
- env,
244
- cstr_backed: statement.operator == "=" ? cstr_backed_storage_value?(binding[:type], prepared_value, env) : false,
245
- cstr_list_backed: statement.operator == "=" ? cstr_list_backed_storage_value?(binding[:type], prepared_value, env) : false,
246
- )
247
- return
248
- end
250
+ binding = lookup_value(statement.target.receiver.name, env)
251
+ return unless binding && cstr_list_trackable_type?(binding[:type])
252
+
253
+ replace_binding_cstr_metadata!(statement.target.receiver.name, env, cstr_backed: binding_cstr_backed?(binding), cstr_list_backed: false)
254
+ end
249
255
 
250
- return unless statement.target.is_a?(AST::IndexAccess) && statement.target.receiver.is_a?(AST::Identifier)
256
+ def merge_cstr_metadata_after_if_statement!(statement, env)
257
+ exit_envs = cstr_metadata_exit_envs_for_if_statement(statement, env)
258
+ return if exit_envs.empty?
251
259
 
252
- binding = lookup_value(statement.target.receiver.name, env)
253
- return unless binding && cstr_list_trackable_type?(binding[:type])
260
+ trackable_binding_names(env).each do |name|
261
+ binding = lookup_value(name, env)
262
+ next unless binding
254
263
 
255
- replace_binding_cstr_metadata!(statement.target.receiver.name, env, cstr_backed: binding_cstr_backed?(binding), cstr_list_backed: false)
264
+ replace_binding_cstr_metadata!(
265
+ name,
266
+ env,
267
+ cstr_backed: cstr_trackable_type?(binding[:type]) && exit_envs.all? { |exit_env| binding_cstr_backed?(lookup_value(name, exit_env)) },
268
+ cstr_list_backed: cstr_list_trackable_type?(binding[:type]) && exit_envs.all? { |exit_env| binding_cstr_list_backed?(lookup_value(name, exit_env)) },
269
+ )
256
270
  end
271
+ end
257
272
 
258
- def merge_cstr_metadata_after_if_statement!(statement, env)
259
- exit_envs = cstr_metadata_exit_envs_for_if_statement(statement, env)
260
- return if exit_envs.empty?
273
+ def cstr_metadata_exit_envs_for_if_statement(statement, env)
274
+ false_refinements = {}
275
+ exit_envs = []
261
276
 
262
- trackable_binding_names(env).each do |name|
263
- binding = lookup_value(name, env)
264
- next unless binding
277
+ statement.branches.each do |branch|
278
+ branch_env = env_with_refinements(env, false_refinements)
279
+ true_refinements = merge_refinements(false_refinements, flow_refinements(branch.condition, truthy: true, env: branch_env))
280
+ simulated = simulate_cstr_metadata_block(branch.body, env: env_with_refinements(env, true_refinements))
281
+ exit_envs << simulated if simulated
282
+ false_refinements = merge_refinements(false_refinements, flow_refinements(branch.condition, truthy: false, env: branch_env))
283
+ end
265
284
 
266
- replace_binding_cstr_metadata!(
267
- name,
268
- env,
269
- cstr_backed: cstr_trackable_type?(binding[:type]) && exit_envs.all? { |exit_env| binding_cstr_backed?(lookup_value(name, exit_env)) },
270
- cstr_list_backed: cstr_list_trackable_type?(binding[:type]) && exit_envs.all? { |exit_env| binding_cstr_list_backed?(lookup_value(name, exit_env)) },
271
- )
272
- end
285
+ if statement.else_body
286
+ simulated = simulate_cstr_metadata_block(statement.else_body, env: env_with_refinements(env, false_refinements))
287
+ exit_envs << simulated if simulated
288
+ else
289
+ exit_envs << env
273
290
  end
274
291
 
275
- def cstr_metadata_exit_envs_for_if_statement(statement, env)
276
- false_refinements = {}
277
- exit_envs = []
292
+ exit_envs
293
+ end
278
294
 
279
- statement.branches.each do |branch|
280
- branch_env = env_with_refinements(env, false_refinements)
281
- true_refinements = merge_refinements(false_refinements, flow_refinements(branch.condition, truthy: true, env: branch_env))
282
- simulated = simulate_cstr_metadata_block(branch.body, env: env_with_refinements(env, true_refinements))
283
- exit_envs << simulated if simulated
284
- false_refinements = merge_refinements(false_refinements, flow_refinements(branch.condition, truthy: false, env: branch_env))
285
- end
295
+ def simulate_cstr_metadata_block(statements, env:)
296
+ simulated_env = duplicate_env(env)
286
297
 
287
- if statement.else_body
288
- simulated = simulate_cstr_metadata_block(statement.else_body, env: env_with_refinements(env, false_refinements))
289
- exit_envs << simulated if simulated
290
- else
291
- exit_envs << env
292
- end
293
-
294
- exit_envs
295
- end
296
-
297
- def simulate_cstr_metadata_block(statements, env:)
298
- simulated_env = duplicate_env(env)
299
-
300
- statements.each do |statement|
301
- case statement
302
- when AST::LocalDecl
303
- storage_type = if statement.else_body
304
- infer_expression_type(statement.value, env: simulated_env)
305
- elsif statement.type
306
- resolve_type_ref(statement.type)
307
- else
308
- infer_expression_type(statement.value, env: simulated_env)
309
- end
310
- type = if statement.else_body
311
- statement.type ? resolve_type_ref(statement.type) : let_else_success_type(storage_type)
312
- else
313
- storage_type
314
- end
315
- unless let_else_discard_binding_syntax?(statement)
316
- current_actual_scope(simulated_env[:scopes])[statement.name] = local_binding(
317
- type:,
318
- storage_type:,
319
- linkage_name: c_local_name(statement.name),
320
- mutable: statement.kind == :var,
321
- pointer: false,
322
- projection: statement.else_body ? let_else_binding_projection(storage_type) : nil,
323
- cstr_backed: cstr_backed_storage_value?(storage_type, statement.value, simulated_env),
324
- cstr_list_backed: cstr_list_backed_storage_value?(storage_type, statement.value, simulated_env),
325
- const_value: statement.else_body ? nil : statement.kind == :let && statement.value ? compile_time_const_value(statement.value, env: simulated_env) : nil,
326
- )
327
- end
328
- when AST::Assignment
329
- update_cstr_metadata_for_assignment!(statement, statement.value, simulated_env)
330
- when AST::IfStmt
331
- merge_cstr_metadata_after_if_statement!(statement, simulated_env)
332
- when AST::UnsafeStmt
333
- nested_env = simulate_cstr_metadata_block(statement.body, env: simulated_env)
334
- return nil unless nested_env
335
-
336
- copy_cstr_metadata!(simulated_env, nested_env)
337
- when AST::ReturnStmt, AST::BreakStmt, AST::ContinueStmt
338
- return nil
298
+ statements.each do |statement|
299
+ case statement
300
+ when AST::LocalDecl
301
+ storage_type = if statement.else_body
302
+ infer_expression_type(statement.value, env: simulated_env)
303
+ elsif statement.type
304
+ resolve_type_ref(statement.type)
305
+ else
306
+ infer_expression_type(statement.value, env: simulated_env)
307
+ end
308
+ type = if statement.else_body
309
+ statement.type ? resolve_type_ref(statement.type) : let_else_success_type(storage_type)
310
+ else
311
+ storage_type
312
+ end
313
+ unless let_else_discard_binding_syntax?(statement)
314
+ current_actual_scope(simulated_env[:scopes])[statement.name] = local_binding(
315
+ type:,
316
+ storage_type:,
317
+ linkage_name: c_local_name(statement.name),
318
+ mutable: statement.kind == :var,
319
+ pointer: false,
320
+ projection: statement.else_body ? let_else_binding_projection(storage_type) : nil,
321
+ cstr_backed: cstr_backed_storage_value?(storage_type, statement.value, simulated_env),
322
+ cstr_list_backed: cstr_list_backed_storage_value?(storage_type, statement.value, simulated_env),
323
+ const_value: statement.else_body ? nil : statement.kind == :let && statement.value ? compile_time_const_value(statement.value, env: simulated_env) : nil,
324
+ )
339
325
  end
340
- end
326
+ when AST::Assignment
327
+ update_cstr_metadata_for_assignment!(statement, statement.value, simulated_env)
328
+ when AST::IfStmt
329
+ merge_cstr_metadata_after_if_statement!(statement, simulated_env)
330
+ when AST::UnsafeStmt
331
+ nested_env = simulate_cstr_metadata_block(statement.body, env: simulated_env)
332
+ return nil unless nested_env
341
333
 
342
- simulated_env
334
+ copy_cstr_metadata!(simulated_env, nested_env)
335
+ when AST::ReturnStmt, AST::BreakStmt, AST::ContinueStmt
336
+ return nil
337
+ end
343
338
  end
344
339
 
345
- def copy_cstr_metadata!(target_env, source_env)
346
- trackable_binding_names(target_env).each do |name|
347
- binding = lookup_value(name, target_env)
348
- source_binding = lookup_value(name, source_env)
349
- next unless binding && source_binding
340
+ simulated_env
341
+ end
350
342
 
351
- replace_binding_cstr_metadata!(
352
- name,
353
- target_env,
354
- cstr_backed: binding_cstr_backed?(source_binding),
355
- cstr_list_backed: binding_cstr_list_backed?(source_binding),
356
- )
357
- end
343
+ def copy_cstr_metadata!(target_env, source_env)
344
+ trackable_binding_names(target_env).each do |name|
345
+ binding = lookup_value(name, target_env)
346
+ source_binding = lookup_value(name, source_env)
347
+ next unless binding && source_binding
348
+
349
+ replace_binding_cstr_metadata!(
350
+ name,
351
+ target_env,
352
+ cstr_backed: binding_cstr_backed?(source_binding),
353
+ cstr_list_backed: binding_cstr_list_backed?(source_binding),
354
+ )
358
355
  end
356
+ end
359
357
 
360
- def replace_binding_cstr_metadata!(name, env, cstr_backed:, cstr_list_backed:)
361
- env[:scopes].reverse_each do |scope|
362
- next if scope.is_a?(FlowScope)
363
- next unless scope.key?(name)
358
+ def replace_binding_cstr_metadata!(name, env, cstr_backed:, cstr_list_backed:)
359
+ env[:scopes].reverse_each do |scope|
360
+ next if scope.is_a?(FlowScope)
361
+ next unless scope.key?(name)
364
362
 
365
- scope[name] = scope.fetch(name).merge(cstr_backed:, cstr_list_backed:)
366
- return
367
- end
363
+ scope[name] = scope.fetch(name).merge(cstr_backed:, cstr_list_backed:)
364
+ return
368
365
  end
366
+ end
369
367
 
370
- def trackable_binding_names(env)
371
- env[:scopes].each_with_object([]) do |scope, names|
372
- next if scope.is_a?(FlowScope)
368
+ def trackable_binding_names(env)
369
+ env[:scopes].each_with_object([]) do |scope, names|
370
+ next if scope.is_a?(FlowScope)
373
371
 
374
- scope.each do |name, binding|
375
- next unless cstr_trackable_type?(binding[:type]) || cstr_list_trackable_type?(binding[:type])
372
+ scope.each do |name, binding|
373
+ next unless cstr_trackable_type?(binding[:type]) || cstr_list_trackable_type?(binding[:type])
376
374
 
377
- names << name unless names.include?(name)
378
- end
375
+ names << name unless names.include?(name)
379
376
  end
380
377
  end
378
+ end
381
379
 
382
- def binding_cstr_backed?(binding)
383
- binding && binding[:cstr_backed]
384
- end
380
+ def binding_cstr_backed?(binding)
381
+ binding && binding[:cstr_backed]
382
+ end
385
383
 
386
- def binding_cstr_list_backed?(binding)
387
- binding && binding[:cstr_list_backed]
388
- end
384
+ def binding_cstr_list_backed?(binding)
385
+ binding && binding[:cstr_list_backed]
386
+ end
389
387
 
390
- def exact_compile_time_numeric_compatibility?(actual_type, expression, expected_type, env: nil)
391
- return false unless expected_type.is_a?(Types::Primitive) && expected_type.numeric?
392
- return false if actual_type.is_a?(Types::EnumBase)
388
+ def exact_compile_time_numeric_compatibility?(actual_type, expression, expected_type, env: nil)
389
+ return false unless expected_type.is_a?(Types::Primitive) && expected_type.numeric?
390
+ return false if actual_type.is_a?(Types::EnumBase)
393
391
 
394
- value = compile_time_const_value(expression, env:)
395
- return false unless value.is_a?(Numeric)
392
+ value = compile_time_const_value(expression, env:)
393
+ return false unless value.is_a?(Numeric)
396
394
 
397
- numeric_constant_fits_type?(value, expected_type)
398
- end
395
+ numeric_constant_fits_type?(value, expected_type)
396
+ end
399
397
 
400
- def external_numeric_assignment_target?(expression, env:)
401
- case expression
402
- when AST::MemberAccess
403
- receiver_type = infer_field_receiver_type(expression.receiver, env:)
404
- receiver_type.respond_to?(:external) && receiver_type.external
405
- else
406
- false
407
- end
398
+ def external_numeric_assignment_target?(expression, env:)
399
+ case expression
400
+ when AST::MemberAccess
401
+ receiver_type = infer_field_receiver_type(expression.receiver, env:)
402
+ receiver_type.respond_to?(:external) && receiver_type.external
403
+ else
404
+ false
408
405
  end
406
+ end
409
407
 
410
- def resolve_callee(callee, env, arguments: nil)
411
- case callee
412
- when AST::Identifier
413
- resolve_identifier_callee(callee, env, arguments)
414
- when AST::MemberAccess
415
- resolve_member_access_callee(callee, env, arguments)
416
- when AST::Specialization
417
- resolve_specialization_callee(callee, env)
418
- else
419
- resolve_expression_callee(callee, env)
420
- end
408
+ def resolve_callee(callee, env, arguments: nil)
409
+ case callee
410
+ when AST::Identifier
411
+ resolve_identifier_callee(callee, env, arguments)
412
+ when AST::MemberAccess
413
+ resolve_member_access_callee(callee, env, arguments)
414
+ when AST::Specialization
415
+ resolve_specialization_callee(callee, env)
416
+ else
417
+ resolve_expression_callee(callee, env)
421
418
  end
419
+ end
422
420
 
423
- def resolve_identifier_callee(callee, env, arguments)
424
- if (binding = lookup_value(callee.name, env))
425
- return [:callable_value, nil, nil, binding[:type], nil] if callable_type?(binding[:type])
426
-
427
- raise LoweringError.new("#{callee.name} is not callable", line: 0, column: 0, path: @ctx.current_analysis_path)
428
- end
429
-
430
- if @ctx.functions.key?(callee.name)
431
- binding = specialize_function_binding(@ctx.functions.fetch(callee.name), arguments, env)
432
- callee_name = if binding.external
433
- external_function_c_name(binding)
434
- else
435
- function_binding_c_name(binding, module_name: @ctx.module_name)
436
- end
437
- return [:function, callee_name, nil, binding.type, binding]
438
- end
421
+ def resolve_identifier_callee(callee, env, arguments)
422
+ if (binding = lookup_value(callee.name, env))
423
+ return [:callable_value, nil, nil, binding[:type], nil] if callable_type?(binding[:type])
439
424
 
440
- if (kind = PASS_THROUGH_BUILTINS[callee.name])
441
- return [kind, nil, nil, nil]
442
- end
425
+ raise LoweringError.new("#{callee.name} is not callable", line: 0, column: 0, path: @ctx.current_analysis_path)
426
+ end
443
427
 
444
- if COMPILE_TIME_BUILTINS.include?(callee.name)
445
- return [:compile_time_builtin, callee.name, nil, compile_time_builtin_function_type(callee.name, arguments, env)]
446
- end
428
+ if @ctx.functions.key?(callee.name)
429
+ binding = specialize_function_binding(@ctx.functions.fetch(callee.name), arguments, env)
430
+ callee_name = if binding.external
431
+ external_function_c_name(binding)
432
+ else
433
+ function_binding_c_name(binding, module_name: @ctx.module_name)
434
+ end
435
+ return [:function, callee_name, nil, binding.type, binding]
436
+ end
447
437
 
448
- type = @ctx.types[callee.name]
449
- if type.is_a?(Types::Struct) || type.is_a?(Types::StringView) || task_type?(type) || type.is_a?(Types::Vector) || type.is_a?(Types::Matrix) || type.is_a?(Types::Quaternion)
450
- return [:struct_literal, nil, nil, type]
451
- end
438
+ if (kind = PASS_THROUGH_BUILTINS[callee.name])
439
+ return [kind, nil, nil, nil]
440
+ end
452
441
 
453
- if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
454
- raise LoweringError.new("generic type #{callee.name} requires type arguments", line: 0, column: 0, path: @ctx.current_analysis_path)
455
- end
442
+ if COMPILE_TIME_BUILTINS.include?(callee.name)
443
+ return [:compile_time_builtin, callee.name, nil, compile_time_builtin_function_type(callee.name, arguments, env)]
444
+ end
456
445
 
457
- emit_fn = @artifacts.emitted_declarations.find { |d| d.is_a?(IR::Function) && d.name == callee.name }
458
- if emit_fn
459
- return [:function, emit_fn.linkage_name, nil, emit_fn.return_type, nil]
460
- end
446
+ type = @ctx.types[callee.name]
447
+ if type.is_a?(Types::Struct) || type.is_a?(Types::StringView) || task_type?(type) || type.is_a?(Types::Vector) || type.is_a?(Types::Matrix) || type.is_a?(Types::Quaternion)
448
+ return [:struct_literal, nil, nil, type]
449
+ end
461
450
 
462
- raise LoweringError.new("unknown callee #{callee.name}", line: 0, column: 0, path: @ctx.current_analysis_path)
451
+ if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
452
+ raise LoweringError.new("generic type #{callee.name} requires type arguments", line: 0, column: 0, path: @ctx.current_analysis_path)
463
453
  end
464
454
 
465
- def resolve_member_access_callee(callee, env, arguments)
466
- if callee.receiver.is_a?(AST::Identifier) && @ctx.imports.key?(callee.receiver.name)
467
- imported_module = @ctx.imports.fetch(callee.receiver.name)
455
+ emit_fn = @artifacts.emitted_declarations.find { |d| d.is_a?(IR::Function) && d.name == callee.name }
456
+ if emit_fn
457
+ return [:function, emit_fn.linkage_name, nil, emit_fn.return_type, nil]
458
+ end
468
459
 
469
- if imported_module.functions.key?(callee.member)
470
- binding = specialize_function_binding(imported_module.functions.fetch(callee.member), arguments, env)
471
- unless binding.owner
472
- binding = binding.with(owner: imported_module.respond_to?(:analysis) ? imported_module.analysis : imported_module)
473
- end
474
- return [:function, function_binding_c_name(binding, module_name: imported_module.name), nil, binding.type, binding] unless binding.external
460
+ raise LoweringError.new("unknown callee #{callee.name}", line: 0, column: 0, path: @ctx.current_analysis_path)
461
+ end
475
462
 
476
- return [:function, external_function_c_name(binding), nil, binding.type, binding]
477
- end
478
- imported_type = imported_module.types[callee.member]
479
- if imported_type.is_a?(Types::GenericStructDefinition) || imported_type.is_a?(Types::GenericVariantDefinition)
480
- raise LoweringError.new("generic type #{callee.receiver.name}.#{callee.member} requires type arguments", line: 0, column: 0, path: @ctx.current_analysis_path)
481
- end
463
+ def resolve_member_access_callee(callee, env, arguments)
464
+ if callee.receiver.is_a?(AST::Identifier) && @ctx.imports.key?(callee.receiver.name)
465
+ imported_module = @ctx.imports.fetch(callee.receiver.name)
482
466
 
483
- if imported_type.is_a?(Types::Struct) || imported_type.is_a?(Types::StringView) || task_type?(imported_type) || imported_type.is_a?(Types::Vector) || imported_type.is_a?(Types::Matrix) || imported_type.is_a?(Types::Quaternion)
484
- return [:struct_literal, nil, nil, imported_module.types.fetch(callee.member)]
467
+ if imported_module.functions.key?(callee.member)
468
+ binding = specialize_function_binding(imported_module.functions.fetch(callee.member), arguments, env)
469
+ unless binding.owner
470
+ binding = binding.with(owner: imported_module.respond_to?(:analysis) ? imported_module.analysis : imported_module)
485
471
  end
472
+ return [:function, function_binding_c_name(binding, module_name: imported_module.name), nil, binding.type, binding] unless binding.external
486
473
 
487
- if imported_type.is_a?(Types::Variant) && imported_type.arm_names.include?(callee.member)
488
- arm_name = callee.member
489
- return [:variant_arm_ctor, nil, nil, imported_type, [imported_type, arm_name]]
490
- end
474
+ return [:function, external_function_c_name(binding), nil, binding.type, binding]
475
+ end
476
+ imported_type = imported_module.types[callee.member]
477
+ if imported_type.is_a?(Types::GenericStructDefinition) || imported_type.is_a?(Types::GenericVariantDefinition)
478
+ raise LoweringError.new("generic type #{callee.receiver.name}.#{callee.member} requires type arguments", line: 0, column: 0, path: @ctx.current_analysis_path)
491
479
  end
492
480
 
493
- if (type_expr = resolve_type_expression(callee.receiver))
494
- if type_expr.is_a?(Types::Variant) && type_expr.arm_names.include?(callee.member)
495
- arm_name = callee.member
496
- return [:variant_arm_ctor, nil, nil, type_expr, [type_expr, arm_name]]
497
- end
498
-
499
- if type_expr.respond_to?(:nested_types) && type_expr.nested_types.key?(callee.member)
500
- return [:struct_literal, nil, nil, type_expr.nested_types[callee.member]]
501
- end
502
-
503
- dispatch_receiver_type = method_dispatch_receiver_type(type_expr)
504
- method_entry_receiver_type = type_expr
505
- method_entry = @method_definitions[[type_expr, callee.member]]
506
- method_entry ||= @method_definitions[[type_expr, "static:#{callee.member}"]]
507
- unless method_entry || dispatch_receiver_type == type_expr
508
- method_entry_receiver_type = dispatch_receiver_type
509
- method_entry = @method_definitions[[dispatch_receiver_type, callee.member]]
510
- method_entry ||= @method_definitions[[dispatch_receiver_type, "static:#{callee.member}"]]
511
- end
512
- if method_entry
513
- method_analysis, method_ast = method_entry
514
- method_binding = method_analysis.methods.fetch(method_entry_receiver_type).fetch(method_analysis_key(method_ast))
515
- if method_binding.type.receiver_type.nil?
516
- method_binding = specialize_function_binding(method_binding, arguments, env, receiver_type: type_expr) if method_binding.type_params.any?
517
- return [:associated_method, function_binding_c_name(method_binding, module_name: method_analysis.module_name, receiver_type: method_entry_receiver_type), nil, method_binding.type, method_binding]
518
- end
519
- end
481
+ if imported_type.is_a?(Types::Struct) || imported_type.is_a?(Types::StringView) || task_type?(imported_type) || imported_type.is_a?(Types::Vector) || imported_type.is_a?(Types::Matrix) || imported_type.is_a?(Types::Quaternion)
482
+ return [:struct_literal, nil, nil, imported_module.types.fetch(callee.member)]
483
+ end
520
484
 
521
- raise LoweringError.new("unknown associated function #{type_expr}.#{callee.member}", line: 0, column: 0, path: @ctx.current_analysis_path)
485
+ if imported_type.is_a?(Types::Variant) && imported_type.arm_names.include?(callee.member)
486
+ arm_name = callee.member
487
+ return [:variant_arm_ctor, nil, nil, imported_type, [imported_type, arm_name]]
522
488
  end
489
+ end
523
490
 
524
- resolved_receiver_type = infer_method_receiver_type(callee.receiver, env:, member_name: callee.member)
491
+ if (type_expr = resolve_type_expression(callee.receiver))
492
+ if type_expr.is_a?(Types::Variant) && type_expr.arm_names.include?(callee.member)
493
+ arm_name = callee.member
494
+ return [:variant_arm_ctor, nil, nil, type_expr, [type_expr, arm_name]]
495
+ end
525
496
 
526
- if dyn_type?(resolved_receiver_type)
527
- interface = resolved_receiver_type.interface_binding
528
- method_binding = interface.methods[callee.member]
529
- raise LoweringError.new("no method '#{callee.member}' on interface #{interface.name}", line: 0, column: 0, path: @ctx.current_analysis_path) unless method_binding
530
- return [:dyn_method, nil, callee.receiver, method_binding, nil]
497
+ if type_expr.respond_to?(:nested_types) && type_expr.nested_types.key?(callee.member)
498
+ return [:struct_literal, nil, nil, type_expr.nested_types[callee.member]]
531
499
  end
532
500
 
533
- dispatch_receiver_type = method_dispatch_receiver_type(resolved_receiver_type)
534
- method_entry_receiver_type = resolved_receiver_type
535
- method_entry = @method_definitions[[resolved_receiver_type, callee.member]]
536
- unless method_entry || dispatch_receiver_type == resolved_receiver_type
501
+ dispatch_receiver_type = method_dispatch_receiver_type(type_expr)
502
+ method_entry_receiver_type = type_expr
503
+ method_entry = @method_definitions[[type_expr, callee.member]]
504
+ method_entry ||= @method_definitions[[type_expr, "static:#{callee.member}"]]
505
+ unless method_entry || dispatch_receiver_type == type_expr
537
506
  method_entry_receiver_type = dispatch_receiver_type
538
507
  method_entry = @method_definitions[[dispatch_receiver_type, callee.member]]
508
+ method_entry ||= @method_definitions[[dispatch_receiver_type, "static:#{callee.member}"]]
539
509
  end
540
510
  if method_entry
541
511
  method_analysis, method_ast = method_entry
542
- method_analysis_key = method_ast.kind == :static ? "static:#{method_ast.name}" : method_ast.name
543
- method_binding = method_analysis.methods.fetch(method_entry_receiver_type).fetch(method_analysis_key)
544
- method_binding = specialize_function_binding(method_binding, arguments, env, receiver_type: resolved_receiver_type)
545
- return [
546
- :method,
547
- function_binding_c_name(method_binding, module_name: method_analysis.module_name, receiver_type: method_entry_receiver_type),
548
- callee.receiver,
549
- method_binding.type,
550
- method_binding,
551
- ]
552
- end
553
-
554
- if callee.member == "with" && struct_with_target_type?(resolved_receiver_type)
555
- return [:struct_with, nil, callee.receiver, resolved_receiver_type]
556
- end
557
-
558
- if (precomputed = @ctx.resolved_call_kinds[@ctx.ast.node_ids[callee.object_id]])
559
- case precomputed
560
- when :str_buffer_clear, :str_buffer_assign, :str_buffer_append, :str_buffer_assign_format, :str_buffer_append_format,
561
- :str_buffer_len, :str_buffer_capacity, :str_buffer_as_str, :str_buffer_as_cstr
562
- return [precomputed, nil, callee.receiver, str_buffer_method_type(precomputed, resolved_receiver_type)]
563
- when :event_subscribe, :event_subscribe_once, :event_unsubscribe, :event_emit, :event_wait
564
- event_type = infer_expression_type(callee.receiver, env:)
565
- return [precomputed, nil, callee.receiver, event_method_type(precomputed, event_type)]
566
- when :atomic_load, :atomic_store, :atomic_add, :atomic_sub, :atomic_exchange, :atomic_compare_exchange
567
- elem = atomic_element_type(resolved_receiver_type)
568
- ret = case precomputed
569
- when :atomic_load, :atomic_add, :atomic_sub, :atomic_exchange then elem
570
- when :atomic_store then @ctx.types.fetch("void")
571
- when :atomic_compare_exchange then @ctx.types.fetch("bool")
572
- end
573
- return [precomputed, nil, callee.receiver, Types::Registry.function(nil, params: [], return_type: ret)]
574
- when :simd_lane_with
575
- return [precomputed, nil, callee.receiver, Types::Registry.function(nil, params: [], return_type: resolved_receiver_type)]
512
+ method_binding = method_analysis.methods.fetch(method_entry_receiver_type).fetch(method_analysis_key(method_ast))
513
+ if method_binding.type.receiver_type.nil?
514
+ method_binding = specialize_function_binding(method_binding, arguments, env, receiver_type: type_expr) if method_binding.type_params.any?
515
+ return [:associated_method, function_binding_c_name(method_binding, module_name: method_analysis.module_name, receiver_type: method_entry_receiver_type), nil, method_binding.type, method_binding]
576
516
  end
577
517
  end
578
518
 
579
- if (str_buffer_method = str_buffer_method_kind(resolved_receiver_type, callee.member))
580
- return [str_buffer_method, nil, callee.receiver, str_buffer_method_type(str_buffer_method, resolved_receiver_type)]
581
- end
519
+ raise LoweringError.new("unknown associated function #{type_expr}.#{callee.member}", line: 0, column: 0, path: @ctx.current_analysis_path)
520
+ end
582
521
 
583
- if (event_method = event_method_kind(resolved_receiver_type, callee.member))
584
- event_type = infer_expression_type(callee.receiver, env:)
585
- return [event_method, nil, callee.receiver, event_method_type(event_method, event_type)]
586
- end
522
+ resolved_receiver_type = infer_method_receiver_type(callee.receiver, env:, member_name: callee.member)
587
523
 
588
- if (atomic_method = atomic_method_kind(resolved_receiver_type, callee.member))
524
+ if dyn_type?(resolved_receiver_type)
525
+ interface = resolved_receiver_type.interface_binding
526
+ method_binding = interface.methods[callee.member]
527
+ raise LoweringError.new("no method '#{callee.member}' on interface #{interface.name}", line: 0, column: 0, path: @ctx.current_analysis_path) unless method_binding
528
+ return [:dyn_method, nil, callee.receiver, method_binding, nil]
529
+ end
530
+
531
+ dispatch_receiver_type = method_dispatch_receiver_type(resolved_receiver_type)
532
+ method_entry_receiver_type = resolved_receiver_type
533
+ method_entry = @method_definitions[[resolved_receiver_type, callee.member]]
534
+ unless method_entry || dispatch_receiver_type == resolved_receiver_type
535
+ method_entry_receiver_type = dispatch_receiver_type
536
+ method_entry = @method_definitions[[dispatch_receiver_type, callee.member]]
537
+ end
538
+ if method_entry
539
+ method_analysis, method_ast = method_entry
540
+ method_analysis_key = method_ast.kind == :static ? "static:#{method_ast.name}" : method_ast.name
541
+ method_binding = method_analysis.methods.fetch(method_entry_receiver_type).fetch(method_analysis_key)
542
+ method_binding = specialize_function_binding(method_binding, arguments, env, receiver_type: resolved_receiver_type)
543
+ return [
544
+ :method,
545
+ function_binding_c_name(method_binding, module_name: method_analysis.module_name, receiver_type: method_entry_receiver_type),
546
+ callee.receiver,
547
+ method_binding.type,
548
+ method_binding,
549
+ ]
550
+ end
551
+
552
+ if callee.member == "with" && struct_with_target_type?(resolved_receiver_type)
553
+ return [:struct_with, nil, callee.receiver, resolved_receiver_type]
554
+ end
555
+
556
+ if (precomputed = @ctx.resolved_call_kinds[@ctx.ast.node_ids[callee.object_id]])
557
+ case precomputed
558
+ when :str_buffer_clear, :str_buffer_assign, :str_buffer_append, :str_buffer_assign_format, :str_buffer_append_format,
559
+ :str_buffer_len, :str_buffer_capacity, :str_buffer_as_str, :str_buffer_as_cstr
560
+ return [precomputed, nil, callee.receiver, str_buffer_method_type(precomputed, resolved_receiver_type)]
561
+ when :event_subscribe, :event_subscribe_once, :event_unsubscribe, :event_emit, :event_wait
562
+ event_type = infer_expression_type(callee.receiver, env:)
563
+ return [precomputed, nil, callee.receiver, event_method_type(precomputed, event_type)]
564
+ when :atomic_load, :atomic_store, :atomic_add, :atomic_sub, :atomic_exchange, :atomic_compare_exchange
589
565
  elem = atomic_element_type(resolved_receiver_type)
590
- ret = case atomic_method
566
+ ret = case precomputed
591
567
  when :atomic_load, :atomic_add, :atomic_sub, :atomic_exchange then elem
592
568
  when :atomic_store then @ctx.types.fetch("void")
593
569
  when :atomic_compare_exchange then @ctx.types.fetch("bool")
594
570
  end
595
- return [atomic_method, nil, callee.receiver, Types::Registry.function(nil, params: [], return_type: ret)]
596
- end
597
-
598
- if (simd_method = simd_method_kind(resolved_receiver_type, callee.member))
599
- ret = case simd_method
600
- when :simd_lane_with then resolved_receiver_type
601
- end
602
- return [simd_method, nil, callee.receiver, Types::Registry.function(nil, params: [], return_type: ret)]
603
- end
604
-
605
- field_receiver_type = infer_field_receiver_type(callee.receiver, env:)
606
- if array_type?(field_receiver_type) && callee.member == "as_span"
607
- return [:array_as_span, nil, callee.receiver, Types::Registry.span(array_element_type(field_receiver_type))]
608
- end
609
-
610
- member_type = field_receiver_type.respond_to?(:field) ? field_receiver_type.field(callee.member) : nil
611
- member_type = field_receiver_type.respond_to?(:field) ? field_receiver_type.field(callee.member) : nil
612
- return [:callable_value, nil, nil, member_type, nil] if callable_type?(member_type)
613
-
614
- raise LoweringError.new("unknown callee #{callee.receiver}.#{callee.member}", line: 0, column: 0, path: @ctx.current_analysis_path)
615
- end
616
-
617
- def resolve_specialization_callee(callee, env)
618
- if callee.callee.is_a?(AST::Identifier)
619
- case callee.callee.name
620
- when "reinterpret"
621
- target_type = resolve_type_ref(callee.arguments.fetch(0).value)
622
- return [:reinterpret, nil, nil, Types::Registry.function("reinterpret", params: [Types::Registry.parameter("value", target_type)], return_type: target_type)]
623
- when "array"
624
- array_type = resolve_type_ref(AST::TypeRef.new(name: AST::QualifiedName.new(parts: ["array"]), arguments: callee.arguments, nullable: false))
625
- return [:array, nil, nil, array_type]
626
- when "simd"
627
- simd_type = resolve_type_ref(AST::TypeRef.new(name: AST::QualifiedName.new(parts: ["simd"]), arguments: callee.arguments, nullable: false))
628
- return [:simd, nil, nil, simd_type]
629
- when "span"
630
- span_type = resolve_type_ref(AST::TypeRef.new(name: AST::QualifiedName.new(parts: ["span"]), arguments: callee.arguments, nullable: false))
631
- return [:struct_literal, nil, nil, span_type]
632
- when "zero"
633
- target_type = resolve_type_ref(callee.arguments.fetch(0).value)
634
- return [:zero, nil, nil, Types::Registry.function("zero", params: [], return_type: target_type)]
635
- when "hash"
636
- resolution = resolve_hash_specialization(callee, env:)
637
- return [:hash, resolution.callee_name, nil, Types::Registry.function("hash", params: [Types::Registry.parameter("value", resolution.target_type)], return_type: @ctx.types.fetch("uint")), resolution.binding]
638
- when "equal"
639
- resolution = resolve_equal_specialization(callee, env:)
640
- params = [
641
- Types::Registry.parameter("left", resolution.target_type),
642
- Types::Registry.parameter("right", resolution.target_type),
643
- ]
644
- return [:equal, resolution.callee_name, nil, Types::Registry.function("equal", params:, return_type: @ctx.types.fetch("bool")), resolution.binding]
645
- when "order"
646
- resolution = resolve_order_specialization(callee, env:)
647
- params = [
648
- Types::Registry.parameter("left", resolution.target_type),
649
- Types::Registry.parameter("right", resolution.target_type),
650
- ]
651
- return [:order, resolution.callee_name, nil, Types::Registry.function("order", params:, return_type: @ctx.types.fetch("int")), resolution.binding]
652
- when "attribute_arg"
653
- return [:compile_time_builtin, "attribute_arg", nil, compile_time_builtin_specialization_function_type(callee)]
654
- when "adapt"
655
- raise LoweringError.new("adapt requires exactly one type argument", line: 0, column: 0, path: @ctx.current_analysis_path) unless callee.arguments.length == 1
656
-
657
- type_arg = callee.arguments.first.value
658
- raise LoweringError.new("adapt type argument must be a type", line: 0, column: 0, path: @ctx.current_analysis_path) unless type_arg.is_a?(AST::TypeRef)
659
-
660
- parts = type_arg.name.parts
661
- type_args = type_arg.arguments.map { |a| a.value }
662
- interface = resolve_interface_ref(AST::QualifiedName.new(parts:, type_arguments: type_args))
663
- dyn_type = Types::Dyn.new(interface, interface.respond_to?(:type_arguments) ? (interface.type_arguments || []) : [])
664
- return [:adapt, nil, nil, dyn_type, interface]
665
- end
666
- end
667
-
668
- if (callable_resolution = resolve_specialized_callable_binding(callee, env:))
669
- callable_kind, function_binding, receiver, method_entry_receiver_type = callable_resolution
670
- if callable_kind == :method
671
- return [
672
- :method,
673
- function_binding_c_name(function_binding, module_name: function_binding.owner.module_name, receiver_type: method_entry_receiver_type),
674
- receiver,
675
- function_binding.type,
676
- function_binding,
677
- ]
678
- end
679
-
680
- if function_binding.external
681
- return [:function, external_function_c_name(function_binding), nil, function_binding.type, function_binding]
682
- end
683
-
684
- return [:function, function_binding_c_name(function_binding, module_name: function_binding.owner.module_name), nil, function_binding.type, function_binding]
571
+ return [precomputed, nil, callee.receiver, Types::Registry.function(nil, params: [], return_type: ret)]
572
+ when :simd_lane_with
573
+ return [precomputed, nil, callee.receiver, Types::Registry.function(nil, params: [], return_type: resolved_receiver_type)]
685
574
  end
686
-
687
- if (type_ref = type_ref_from_specialization(callee))
688
- specialized_type = resolve_type_ref(type_ref)
689
- return [:struct_literal, nil, nil, specialized_type] if specialized_type.is_a?(Types::Struct) || task_type?(specialized_type) || specialized_type.is_a?(Types::Vector) || specialized_type.is_a?(Types::Matrix) || specialized_type.is_a?(Types::Quaternion) || specialized_type.is_a?(Types::Simd)
690
- end
691
-
692
- raise LoweringError.new("unsupported specialization callee", line: 0, column: 0, path: @ctx.current_analysis_path)
693
575
  end
694
576
 
695
- def resolve_expression_callee(callee, env)
696
- callee_type = infer_expression_type(callee, env:)
697
- return [:callable_value, nil, nil, callee_type, nil] if callable_type?(callee_type)
698
-
699
- raise LoweringError.new("unsupported callee #{callee.class.name}", line: 0, column: 0, path: @ctx.current_analysis_path)
577
+ if (str_buffer_method = str_buffer_method_kind(resolved_receiver_type, callee.member))
578
+ return [str_buffer_method, nil, callee.receiver, str_buffer_method_type(str_buffer_method, resolved_receiver_type)]
700
579
  end
701
580
 
702
- def infer_expression_type(expression, env:, expected_type: nil)
703
- if !@bypass_sema_type_cache && expected_type.nil? && (id = @ctx.ast.node_ids[expression.object_id]) && (resolved = @ctx.resolved_expr_types[id])
704
- return resolved
705
- end
706
-
707
- case expression
708
- when AST::AwaitExpr
709
- task_type = infer_expression_type(expression.expression, env:)
710
- raise LoweringError.new("await requires a Task value, got #{task_type}", line: 0, column: 0, path: @ctx.current_analysis_path) unless task_type.is_a?(Types::Task)
711
-
712
- task_type.result_type
713
- when AST::IntegerLiteral
714
- if expected_type.is_a?(Types::Primitive) && expected_type.integer?
715
- expected_type
716
- else
717
- @ctx.types.fetch("int")
718
- end
719
- when AST::CharLiteral
720
- @ctx.types.fetch("ubyte")
721
- when AST::FloatLiteral
722
- if expression.lexeme.end_with?("f")
723
- @ctx.types.fetch("float")
724
- elsif expression.lexeme.end_with?("d")
725
- @ctx.types.fetch("double")
726
- elsif expected_type.is_a?(Types::Primitive) && expected_type.float?
727
- expected_type
728
- else
729
- @ctx.types.fetch("float")
730
- end
731
- when AST::SizeofExpr, AST::AlignofExpr, AST::OffsetofExpr
732
- @ctx.types.fetch("ptr_uint")
733
- when AST::StringLiteral
734
- @ctx.types.fetch(expression.cstring ? "cstr" : "str")
735
- when AST::FormatString
736
- @ctx.types.fetch("str")
737
- when AST::BooleanLiteral
738
- @ctx.types.fetch("bool")
739
- when AST::NullLiteral
740
- infer_null_literal_type(expression, expected_type)
741
- when AST::Identifier
742
- binding = lookup_value(expression.name, env)
743
- return binding[:type] if binding
744
- return function_type_for_name(expression.name) if @ctx.functions.key?(expression.name)
745
-
746
- raise LoweringError.new("unknown identifier #{expression.name}", line: expression.line, column: expression.column)
747
- when AST::MemberAccess
748
- if (type_expr = resolve_type_expression(expression.receiver))
749
- member_type = resolve_type_member(type_expr, expression.member)
750
- return member_type if member_type
751
-
752
- dispatch_receiver_type = method_dispatch_receiver_type(type_expr)
753
- method_entry_receiver_type = type_expr
754
- method_entry = @method_definitions[[type_expr, expression.member]]
755
- method_entry ||= @method_definitions[[type_expr, "static:#{expression.member}"]]
756
- unless method_entry || dispatch_receiver_type == type_expr
757
- method_entry_receiver_type = dispatch_receiver_type
758
- method_entry = @method_definitions[[dispatch_receiver_type, expression.member]]
759
- method_entry ||= @method_definitions[[dispatch_receiver_type, "static:#{expression.member}"]]
760
- end
761
- if method_entry
762
- method_analysis, method_ast = method_entry
763
- method_binding = method_analysis.methods.fetch(method_entry_receiver_type).fetch(method_analysis_key(method_ast))
764
- return method_binding.type if method_binding.type.receiver_type.nil?
765
- end
766
- end
767
- if expression.receiver.is_a?(AST::Identifier) && @ctx.imports.key?(expression.receiver.name)
768
- imported_module = @ctx.imports.fetch(expression.receiver.name)
769
- return imported_module.values.fetch(expression.member).type if imported_module.values.key?(expression.member)
770
- return imported_module.functions.fetch(expression.member).type if imported_module.functions.key?(expression.member)
771
- end
772
- receiver_type = infer_field_receiver_type(expression.receiver, env:)
773
- if (event_type = event_member_from_owner_type(receiver_type, expression.member))
774
- return event_type
775
- end
776
-
777
- if receiver_type == @ctx.types["field_handle"]
778
- return infer_field_handle_member_type(expression)
779
- end
780
- if receiver_type == @ctx.types["member_handle"]
781
- return infer_member_handle_member_type(expression)
782
- end
581
+ if (event_method = event_method_kind(resolved_receiver_type, callee.member))
582
+ event_type = infer_expression_type(callee.receiver, env:)
583
+ return [event_method, nil, callee.receiver, event_method_type(event_method, event_type)]
584
+ end
783
585
 
784
- return receiver_type.field(expression.member) if receiver_type.respond_to?(:field)
785
- raise LoweringError.new("unknown member #{expression.member}", line: expression.line, column: expression.column)
786
- when AST::IndexAccess
787
- receiver_type = infer_expression_type(expression.receiver, env:)
788
- index_type = infer_expression_type(expression.index, env:)
789
- infer_index_result_type(receiver_type, index_type)
790
- when AST::UnaryOp
791
- return infer_result_propagation_type(expression, env:) if expression.operator == "?"
792
-
793
- operand_type = infer_expression_type(expression.operand, env:, expected_type:)
794
- case expression.operator
795
- when "not"
796
- @ctx.types.fetch("bool")
797
- else
798
- operand_type
799
- end
800
- when AST::BinaryOp
801
- left_type, right_type = infer_binary_operand_types(expression, env:, expected_type: expected_type)
802
-
803
- case expression.operator
804
- when "and", "or", "<", "<=", ">", ">=", "==", "!="
805
- @ctx.types.fetch("bool")
806
- when "+", "-", "*", "/"
807
- aggregate_arithmetic_result_type(expression.operator, left_type, right_type) || pointer_arithmetic_result_type(expression.operator, left_type, right_type) || common_numeric_type(left_type, right_type) || left_type
808
- when "%"
809
- common_integer_type(left_type, right_type) || left_type
810
- else
811
- left_type
812
- end
813
- when AST::IfExpr
814
- then_env = env_with_refinements(env, flow_refinements(expression.condition, truthy: true, env:))
815
- else_env = env_with_refinements(env, flow_refinements(expression.condition, truthy: false, env:))
816
- then_type = infer_expression_type(expression.then_expression, env: then_env, expected_type: expected_type)
817
- else_type = infer_expression_type(expression.else_expression, env: else_env, expected_type: expected_type)
818
-
819
- if expected_type &&
820
- if_expression_branch_compatible?(then_type, expected_type) &&
821
- if_expression_branch_compatible?(else_type, expected_type)
822
- return expected_type
823
- end
586
+ if (atomic_method = atomic_method_kind(resolved_receiver_type, callee.member))
587
+ elem = atomic_element_type(resolved_receiver_type)
588
+ ret = case atomic_method
589
+ when :atomic_load, :atomic_add, :atomic_sub, :atomic_exchange then elem
590
+ when :atomic_store then @ctx.types.fetch("void")
591
+ when :atomic_compare_exchange then @ctx.types.fetch("bool")
592
+ end
593
+ return [atomic_method, nil, callee.receiver, Types::Registry.function(nil, params: [], return_type: ret)]
594
+ end
824
595
 
825
- conditional_common_type(then_type, else_type) || raise(LoweringError, "if expression branches require compatible types, got #{then_type} and #{else_type}")
826
- when AST::MatchExpr
827
- scrutinee_type = infer_expression_type(expression.expression, env:)
828
- arm_types = expression.arms.map do |arm|
829
- arm_env = duplicate_env(env)
830
- if scrutinee_type.is_a?(Types::Variant) && arm.binding_name && !wildcard_arm_pattern?(arm.pattern)
831
- arm_name = variant_match_arm_name_from_pattern(arm.pattern)
832
- if arm_name && scrutinee_type.has_payload?(arm_name)
833
- fields = scrutinee_type.arm(arm_name)
834
- payload_type = Types::VariantArmPayload.new(scrutinee_type, arm_name, fields)
835
- arm_env[:scopes].last[arm.binding_name] = local_binding(type: payload_type, linkage_name: c_local_name(arm.binding_name), mutable: false, pointer: false)
596
+ if (simd_method = simd_method_kind(resolved_receiver_type, callee.member))
597
+ ret = case simd_method
598
+ when :simd_lane_with then resolved_receiver_type
836
599
  end
837
- end
838
- infer_expression_type(arm.value, env: arm_env, expected_type: expected_type)
839
- end
600
+ return [simd_method, nil, callee.receiver, Types::Registry.function(nil, params: [], return_type: ret)]
601
+ end
602
+
603
+ field_receiver_type = infer_field_receiver_type(callee.receiver, env:)
604
+ if array_type?(field_receiver_type) && callee.member == "as_span"
605
+ return [:array_as_span, nil, callee.receiver, Types::Registry.span(array_element_type(field_receiver_type))]
606
+ end
607
+
608
+ member_type = field_receiver_type.respond_to?(:field) ? field_receiver_type.field(callee.member) : nil
609
+ member_type = field_receiver_type.respond_to?(:field) ? field_receiver_type.field(callee.member) : nil
610
+ return [:callable_value, nil, nil, member_type, nil] if callable_type?(member_type)
611
+
612
+ raise LoweringError.new("unknown callee #{callee.receiver}.#{callee.member}", line: 0, column: 0, path: @ctx.current_analysis_path)
613
+ end
614
+
615
+ def resolve_specialization_callee(callee, env)
616
+ if callee.callee.is_a?(AST::Identifier)
617
+ case callee.callee.name
618
+ when "reinterpret"
619
+ target_type = resolve_type_ref(callee.arguments.fetch(0).value)
620
+ return [:reinterpret, nil, nil, Types::Registry.function("reinterpret", params: [Types::Registry.parameter("value", target_type)], return_type: target_type)]
621
+ when "array"
622
+ array_type = resolve_type_ref(AST::TypeRef.new(name: AST::QualifiedName.new(parts: ["array"]), arguments: callee.arguments, nullable: false))
623
+ return [:array, nil, nil, array_type]
624
+ when "simd"
625
+ simd_type = resolve_type_ref(AST::TypeRef.new(name: AST::QualifiedName.new(parts: ["simd"]), arguments: callee.arguments, nullable: false))
626
+ return [:simd, nil, nil, simd_type]
627
+ when "span"
628
+ span_type = resolve_type_ref(AST::TypeRef.new(name: AST::QualifiedName.new(parts: ["span"]), arguments: callee.arguments, nullable: false))
629
+ return [:struct_literal, nil, nil, span_type]
630
+ when "zero"
631
+ target_type = resolve_type_ref(callee.arguments.fetch(0).value)
632
+ return [:zero, nil, nil, Types::Registry.function("zero", params: [], return_type: target_type)]
633
+ when "hash"
634
+ resolution = resolve_hash_specialization(callee, env:)
635
+ return [:hash, resolution.callee_name, nil, Types::Registry.function("hash", params: [Types::Registry.parameter("value", resolution.target_type)], return_type: @ctx.types.fetch("uint")), resolution.binding]
636
+ when "equal"
637
+ resolution = resolve_equal_specialization(callee, env:)
638
+ params = [
639
+ Types::Registry.parameter("left", resolution.target_type),
640
+ Types::Registry.parameter("right", resolution.target_type),
641
+ ]
642
+ return [:equal, resolution.callee_name, nil, Types::Registry.function("equal", params:, return_type: @ctx.types.fetch("bool")), resolution.binding]
643
+ when "order"
644
+ resolution = resolve_order_specialization(callee, env:)
645
+ params = [
646
+ Types::Registry.parameter("left", resolution.target_type),
647
+ Types::Registry.parameter("right", resolution.target_type),
648
+ ]
649
+ return [:order, resolution.callee_name, nil, Types::Registry.function("order", params:, return_type: @ctx.types.fetch("int")), resolution.binding]
650
+ when "attribute_arg"
651
+ return [:compile_time_builtin, "attribute_arg", nil, compile_time_builtin_specialization_function_type(callee)]
652
+ when "adapt"
653
+ raise LoweringError.new("adapt requires exactly one type argument", line: 0, column: 0, path: @ctx.current_analysis_path) unless callee.arguments.length == 1
840
654
 
841
- if expected_type && arm_types.all? { |arm_type| if_expression_branch_compatible?(arm_type, expected_type) }
842
- return expected_type
843
- end
655
+ type_arg = callee.arguments.first.value
656
+ raise LoweringError.new("adapt type argument must be a type", line: 0, column: 0, path: @ctx.current_analysis_path) unless type_arg.is_a?(AST::TypeRef)
844
657
 
845
- common_type = arm_types.first
846
- arm_types.drop(1).each do |arm_type|
847
- common_type = conditional_common_type(common_type, arm_type) || raise(LoweringError, "match expression arms require compatible types, got #{common_type} and #{arm_type}")
848
- end
849
- common_type
850
- when AST::UnsafeExpr
851
- infer_expression_type(expression.expression, env:, expected_type:)
852
- when AST::ProcExpr
853
- resolve_type_ref(AST::ProcType.new(params: expression.params, return_type: expression.return_type))
854
- when AST::Call
855
- kind, _callee_name, _receiver, callee_type = resolve_callee(expression.callee, env, arguments: expression.arguments)
856
- case kind
857
- when :function, :method, :associated_method, :callable_value,
858
- :str_buffer_clear, :str_buffer_assign, :str_buffer_append, :str_buffer_assign_format, :str_buffer_append_format,
859
- :str_buffer_len, :str_buffer_capacity, :str_buffer_as_str, :str_buffer_as_cstr,
860
- :event_subscribe, :event_subscribe_once, :event_unsubscribe, :event_emit, :event_wait,
861
- :compile_time_builtin,
862
- :reinterpret, :zero, :hash, :equal, :order,
863
- :dyn_method
864
- callee_type.return_type
865
- when :struct_literal, :struct_with, :array, :simd, :variant_arm_ctor, :adapt
866
- callee_type
867
- when :ref_of
868
- argument_type = infer_expression_type(expression.arguments.fetch(0).value, env:)
869
- Types::Registry.generic_instance("ref", [argument_type])
870
- when :const_ptr_of
871
- argument_type = infer_expression_type(expression.arguments.fetch(0).value, env:)
872
- Types::Registry.generic_instance("const_ptr", [argument_type])
873
- when :read
874
- infer_value_type(expression.arguments.fetch(0).value, env:)
875
- when :ptr_of
876
- argument_type = infer_expression_type(expression.arguments.fetch(0).value, env:)
877
- if ref_type?(argument_type)
878
- Types::Registry.generic_instance("ptr", [referenced_type(argument_type)])
879
- else
880
- Types::Registry.generic_instance("ptr", [infer_expression_type(expression.arguments.fetch(0).value, env:, expected_type: expected_type && pointer_type?(expected_type) ? pointee_type(expected_type) : nil)])
881
- end
882
- when :array_as_span
883
- callee_type
884
- when :fatal
885
- @ctx.types.fetch("void")
886
- when :get
887
- receiver_type = infer_expression_type(expression.arguments.fetch(0).value, env:)
888
- elem_type = if array_type?(receiver_type)
889
- array_element_type(receiver_type)
890
- else
891
- receiver_type.element_type
892
- end
893
- Types::Registry.nullable(Types::Registry.generic_instance("ptr", [elem_type]))
894
- when :atomic_load, :atomic_add, :atomic_sub, :atomic_exchange, :atomic_store, :atomic_compare_exchange,
895
- :simd_lane_with
896
- callee_type.return_type
897
- else
898
- raise LoweringError.new("unsupported call kind #{kind}", line: 0, column: 0, path: @ctx.current_analysis_path)
899
- end
900
- when AST::PrefixCast
901
- resolve_type_ref(expression.target_type)
902
- when AST::Specialization
903
- if expression.callee.is_a?(AST::Identifier) && expression.callee.name == "zero"
904
- _, _, _, function_type = resolve_callee(expression, env, arguments: [])
905
- function_type.return_type
906
- elsif expression.callee.is_a?(AST::Identifier) && expression.callee.name == "default"
907
- resolve_default_specialization(expression, env:).target_type
908
- elsif (callable_resolution = resolve_specialized_callable_binding(expression, env:))
909
- callable_kind, function_binding, = callable_resolution
910
- raise LoweringError.new("specialized method must be called", line: 0, column: 0, path: @ctx.current_analysis_path) if callable_kind == :method
911
-
912
- function_binding.type
913
- else
914
- raise LoweringError.new("unsupported specialization", line: 0, column: 0, path: @ctx.current_analysis_path)
915
- end
916
- when AST::RangeExpr
917
- raise LoweringError.new("range expression is not valid in this context; use it as a for-loop iterable", line: 0, column: 0, path: @ctx.current_analysis_path)
918
- when AST::ExpressionList
919
- names = []
920
- element_types = []
921
- expression.elements.each do |element|
922
- if element.is_a?(AST::Argument)
923
- names << element.name
924
- element_types << infer_expression_type(element.value, env:)
925
- else
926
- names << nil
927
- element_types << infer_expression_type(element, env:)
928
- end
929
- end
930
- has_named = names.any?
931
- Types::Registry.tuple(element_types, field_names: has_named ? names : nil)
932
- when AST::DetachExpr
933
- Types::Handle.new
934
- else
935
- raise LoweringError.new("unsupported expression type #{expression.class.name}", line: 0, column: 0, path: @ctx.current_analysis_path)
936
- end
937
- end
938
-
939
- def infer_binary_operand_types(expression, env:, expected_type: nil)
940
- propagated_type = propagating_expected_type(expression.operator, expected_type)
941
- left_type = infer_expression_type(expression.left, env:, expected_type: propagated_type)
942
- right_env = binary_right_env(expression, env)
943
- right_expected_type = case expression.operator
944
- when "<<", ">>"
945
- propagated_type || left_type
946
- when "+", "-", "*", "/", "%"
947
- propagated_type || left_type
948
- when "|", "&", "^"
949
- left_type
950
- else
951
- left_type
952
- end
953
- right_type = infer_expression_type(expression.right, env: right_env, expected_type: right_expected_type)
954
- left_type, right_type = harmonize_binary_float_literal_types(expression.left, expression.right, left_type, right_type, env: right_env)
955
- harmonize_binary_integer_literal_types(expression.left, expression.right, left_type, right_type, env: right_env)
956
- end
957
-
958
- def binary_right_env(expression, env)
959
- case expression.operator
960
- when "and"
961
- env_with_refinements(env, flow_refinements(expression.left, truthy: true, env:))
962
- when "or"
963
- env_with_refinements(env, flow_refinements(expression.left, truthy: false, env:))
964
- else
965
- env
658
+ parts = type_arg.name.parts
659
+ type_args = type_arg.arguments.map { |a| a.value }
660
+ interface = resolve_interface_ref(AST::QualifiedName.new(parts:, type_arguments: type_args))
661
+ dyn_type = Types::Dyn.new(interface, interface.respond_to?(:type_arguments) ? (interface.type_arguments || []) : [])
662
+ return [:adapt, nil, nil, dyn_type, interface]
966
663
  end
967
664
  end
968
665
 
969
- def harmonize_binary_float_literal_types(left_expression, right_expression, left_type, right_type, env:)
970
- if float_literal_expression?(left_expression) && right_type.is_a?(Types::Primitive) && right_type.float?
971
- left_type = infer_expression_type(left_expression, env:, expected_type: right_type)
666
+ if (callable_resolution = resolve_specialized_callable_binding(callee, env:))
667
+ callable_kind, function_binding, receiver, method_entry_receiver_type = callable_resolution
668
+ if callable_kind == :method
669
+ return [
670
+ :method,
671
+ function_binding_c_name(function_binding, module_name: function_binding.owner.module_name, receiver_type: method_entry_receiver_type),
672
+ receiver,
673
+ function_binding.type,
674
+ function_binding,
675
+ ]
972
676
  end
973
677
 
974
- if float_literal_expression?(right_expression) && left_type.is_a?(Types::Primitive) && left_type.float?
975
- right_type = infer_expression_type(right_expression, env:, expected_type: left_type)
678
+ if function_binding.external
679
+ return [:function, external_function_c_name(function_binding), nil, function_binding.type, function_binding]
976
680
  end
977
681
 
978
- [left_type, right_type]
682
+ return [:function, function_binding_c_name(function_binding, module_name: function_binding.owner.module_name), nil, function_binding.type, function_binding]
979
683
  end
980
684
 
981
- def float_literal_expression?(expression)
982
- expression.is_a?(AST::FloatLiteral) ||
983
- (expression.is_a?(AST::UnaryOp) && ["+", "-"].include?(expression.operator) && float_literal_expression?(expression.operand))
685
+ if (type_ref = type_ref_from_specialization(callee))
686
+ specialized_type = resolve_type_ref(type_ref)
687
+ return [:struct_literal, nil, nil, specialized_type] if specialized_type.is_a?(Types::Struct) || task_type?(specialized_type) || specialized_type.is_a?(Types::Vector) || specialized_type.is_a?(Types::Matrix) || specialized_type.is_a?(Types::Quaternion) || specialized_type.is_a?(Types::Simd)
984
688
  end
985
689
 
986
- def harmonize_binary_integer_literal_types(left_expression, right_expression, left_type, right_type, env:)
987
- if integer_literal_expression?(left_expression) && right_type.is_a?(Types::Primitive) && right_type.integer?
988
- if exact_compile_time_numeric_compatibility?(left_type, left_expression, right_type, env:)
989
- left_type = infer_expression_type(left_expression, env:, expected_type: right_type)
990
- end
991
- end
690
+ raise LoweringError.new("unsupported specialization callee", line: 0, column: 0, path: @ctx.current_analysis_path)
691
+ end
992
692
 
993
- if integer_literal_expression?(right_expression) && left_type.is_a?(Types::Primitive) && left_type.integer?
994
- if exact_compile_time_numeric_compatibility?(right_type, right_expression, left_type, env:)
995
- right_type = infer_expression_type(right_expression, env:, expected_type: left_type)
996
- end
997
- end
693
+ def resolve_expression_callee(callee, env)
694
+ callee_type = infer_expression_type(callee, env:)
695
+ return [:callable_value, nil, nil, callee_type, nil] if callable_type?(callee_type)
998
696
 
999
- [left_type, right_type]
1000
- end
697
+ raise LoweringError.new("unsupported callee #{callee.class.name}", line: 0, column: 0, path: @ctx.current_analysis_path)
698
+ end
1001
699
 
1002
- def integer_literal_expression?(expression)
1003
- expression.is_a?(AST::IntegerLiteral)
700
+ def infer_expression_type(expression, env:, expected_type: nil)
701
+ if !@bypass_sema_type_cache && expected_type.nil? && (id = @ctx.ast.node_ids[expression.object_id]) && (resolved = @ctx.resolved_expr_types[id])
702
+ return resolved
1004
703
  end
1005
704
 
1006
- def propagating_expected_type(operator, expected_type)
1007
- case operator
1008
- when "+", "-", "*", "/", "%", "<<", ">>"
1009
- return expected_type if expected_type.is_a?(Types::Primitive) && expected_type.numeric?
1010
- when "|", "&", "^"
1011
- return expected_type if expected_type.is_a?(Types::Primitive) && expected_type.integer?
1012
- return expected_type if expected_type.is_a?(Types::Flags)
1013
- end
705
+ case expression
706
+ when AST::AwaitExpr
707
+ task_type = infer_expression_type(expression.expression, env:)
708
+ raise LoweringError.new("await requires a Task value, got #{task_type}", line: 0, column: 0, path: @ctx.current_analysis_path) unless task_type.is_a?(Types::Task)
1014
709
 
1015
- nil
1016
- end
710
+ task_type.result_type
711
+ when AST::IntegerLiteral
712
+ if expected_type.is_a?(Types::Primitive) && expected_type.integer?
713
+ expected_type
714
+ else
715
+ @ctx.types.fetch("int")
716
+ end
717
+ when AST::CharLiteral
718
+ @ctx.types.fetch("ubyte")
719
+ when AST::FloatLiteral
720
+ if expression.lexeme.end_with?("f")
721
+ @ctx.types.fetch("float")
722
+ elsif expression.lexeme.end_with?("d")
723
+ @ctx.types.fetch("double")
724
+ elsif expected_type.is_a?(Types::Primitive) && expected_type.float?
725
+ expected_type
726
+ else
727
+ @ctx.types.fetch("float")
728
+ end
729
+ when AST::SizeofExpr, AST::AlignofExpr, AST::OffsetofExpr
730
+ @ctx.types.fetch("ptr_uint")
731
+ when AST::StringLiteral
732
+ @ctx.types.fetch(expression.cstring ? "cstr" : "str")
733
+ when AST::FormatString
734
+ @ctx.types.fetch("str")
735
+ when AST::BooleanLiteral
736
+ @ctx.types.fetch("bool")
737
+ when AST::NullLiteral
738
+ infer_null_literal_type(expression, expected_type)
739
+ when AST::Identifier
740
+ binding = lookup_value(expression.name, env)
741
+ return binding[:type] if binding
742
+ return function_type_for_name(expression.name) if @ctx.functions.key?(expression.name)
743
+
744
+ raise LoweringError.new("unknown identifier #{expression.name}", line: expression.line, column: expression.column)
745
+ when AST::MemberAccess
746
+ if (type_expr = resolve_type_expression(expression.receiver))
747
+ member_type = resolve_type_member(type_expr, expression.member)
748
+ return member_type if member_type
1017
749
 
1018
- def promoted_binary_operand_type(operator, left_type, right_type)
1019
- case operator
1020
- when "+", "-", "*", "/", "<", "<=", ">", ">=", "==", "!="
1021
- common_numeric_type(left_type, right_type)
1022
- when "%"
1023
- common_integer_type(left_type, right_type)
750
+ dispatch_receiver_type = method_dispatch_receiver_type(type_expr)
751
+ method_entry_receiver_type = type_expr
752
+ method_entry = @method_definitions[[type_expr, expression.member]]
753
+ method_entry ||= @method_definitions[[type_expr, "static:#{expression.member}"]]
754
+ unless method_entry || dispatch_receiver_type == type_expr
755
+ method_entry_receiver_type = dispatch_receiver_type
756
+ method_entry = @method_definitions[[dispatch_receiver_type, expression.member]]
757
+ method_entry ||= @method_definitions[[dispatch_receiver_type, "static:#{expression.member}"]]
758
+ end
759
+ if method_entry
760
+ method_analysis, method_ast = method_entry
761
+ method_binding = method_analysis.methods.fetch(method_entry_receiver_type).fetch(method_analysis_key(method_ast))
762
+ return method_binding.type if method_binding.type.receiver_type.nil?
763
+ end
764
+ end
765
+ if expression.receiver.is_a?(AST::Identifier) && @ctx.imports.key?(expression.receiver.name)
766
+ imported_module = @ctx.imports.fetch(expression.receiver.name)
767
+ return imported_module.values.fetch(expression.member).type if imported_module.values.key?(expression.member)
768
+ return imported_module.functions.fetch(expression.member).type if imported_module.functions.key?(expression.member)
769
+ end
770
+ receiver_type = infer_field_receiver_type(expression.receiver, env:)
771
+ if (event_type = event_member_from_owner_type(receiver_type, expression.member))
772
+ return event_type
1024
773
  end
1025
- end
1026
-
1027
- def cast_expression(expression, target_type)
1028
- return expression if expression.type == target_type
1029
-
1030
- IR::Cast.new(target_type:, expression:, type: target_type)
1031
- end
1032
-
1033
- def pointer_lowered_sync_method_receiver?(binding)
1034
- return false if binding.async
1035
-
1036
- pointer_lowered_method_receiver?(binding.type, binding)
1037
- end
1038
774
 
1039
- def pointer_lowered_method_receiver?(callee_type, callee_binding)
1040
- return true if callee_type.receiver_editable
775
+ if receiver_type == @ctx.types["field_handle"]
776
+ return infer_field_handle_member_type(expression)
777
+ end
778
+ if receiver_type == @ctx.types["member_handle"]
779
+ return infer_member_handle_member_type(expression)
780
+ end
1041
781
 
1042
- receiver_type_uses_pointer_lowering?(callee_type.receiver_type) && !callee_binding&.async
1043
- end
782
+ return receiver_type.field(expression.member) if receiver_type.respond_to?(:field)
783
+ raise LoweringError.new("unknown member #{expression.member}", line: expression.line, column: expression.column)
784
+ when AST::IndexAccess
785
+ receiver_type = infer_expression_type(expression.receiver, env:)
786
+ index_type = infer_expression_type(expression.index, env:)
787
+ infer_index_result_type(receiver_type, index_type)
788
+ when AST::UnaryOp
789
+ return infer_result_propagation_type(expression, env:) if expression.operator == "?"
1044
790
 
1045
- def receiver_type_uses_pointer_lowering?(type)
1046
- case type
1047
- when Types::Nullable
1048
- receiver_type_uses_pointer_lowering?(type.base)
1049
- when Types::Struct, Types::StructInstance
1050
- type_contains_array_storage?(type)
791
+ operand_type = infer_expression_type(expression.operand, env:, expected_type:)
792
+ case expression.operator
793
+ when "not"
794
+ @ctx.types.fetch("bool")
1051
795
  else
1052
- false
796
+ operand_type
1053
797
  end
1054
- end
1055
-
1056
- def type_contains_array_storage?(type, visited = Set.new)
1057
- visitor = ContainsArrayStorageVisitor.new
1058
- visitor.visit(type)
1059
- visitor.found?
1060
- end
1061
-
1062
- def reinterpret_expression(expression, target_type)
1063
- return expression if expression.type == target_type
798
+ when AST::BinaryOp
799
+ left_type, right_type = infer_binary_operand_types(expression, env:, expected_type: expected_type)
1064
800
 
1065
- IR::ReinterpretExpr.new(target_type:, source_type: expression.type, expression:, type: target_type)
801
+ case expression.operator
802
+ when "and", "or", "<", "<=", ">", ">=", "==", "!="
803
+ @ctx.types.fetch("bool")
804
+ when "+", "-", "*", "/"
805
+ aggregate_arithmetic_result_type(expression.operator, left_type, right_type) || pointer_arithmetic_result_type(expression.operator, left_type, right_type) || common_numeric_type(left_type, right_type) || left_type
806
+ when "%"
807
+ common_integer_type(left_type, right_type) || left_type
808
+ else
809
+ left_type
810
+ end
811
+ when AST::IfExpr
812
+ then_env = env_with_refinements(env, flow_refinements(expression.condition, truthy: true, env:))
813
+ else_env = env_with_refinements(env, flow_refinements(expression.condition, truthy: false, env:))
814
+ then_type = infer_expression_type(expression.then_expression, env: then_env, expected_type: expected_type)
815
+ else_type = infer_expression_type(expression.else_expression, env: else_env, expected_type: expected_type)
816
+
817
+ if expected_type &&
818
+ if_expression_branch_compatible?(then_type, expected_type) &&
819
+ if_expression_branch_compatible?(else_type, expected_type)
820
+ return expected_type
821
+ end
822
+
823
+ conditional_common_type(then_type, else_type) || raise(LoweringError, "if expression branches require compatible types, got #{then_type} and #{else_type}")
824
+ when AST::MatchExpr
825
+ scrutinee_type = infer_expression_type(expression.expression, env:)
826
+ arm_types = expression.arms.map do |arm|
827
+ arm_env = duplicate_env(env)
828
+ if scrutinee_type.is_a?(Types::Variant) && arm.binding_name && !wildcard_arm_pattern?(arm.pattern)
829
+ arm_name = variant_match_arm_name_from_pattern(arm.pattern)
830
+ if arm_name && scrutinee_type.has_payload?(arm_name)
831
+ fields = scrutinee_type.arm(arm_name)
832
+ payload_type = Types::VariantArmPayload.new(scrutinee_type, arm_name, fields)
833
+ arm_env[:scopes].last[arm.binding_name] = local_binding(type: payload_type, linkage_name: c_local_name(arm.binding_name), mutable: false, pointer: false)
834
+ end
835
+ end
836
+ infer_expression_type(arm.value, env: arm_env, expected_type: expected_type)
837
+ end
838
+
839
+ if expected_type && arm_types.all? { |arm_type| if_expression_branch_compatible?(arm_type, expected_type) }
840
+ return expected_type
841
+ end
842
+
843
+ common_type = arm_types.first
844
+ arm_types.drop(1).each do |arm_type|
845
+ common_type = conditional_common_type(common_type, arm_type) || raise(LoweringError, "match expression arms require compatible types, got #{common_type} and #{arm_type}")
846
+ end
847
+ common_type
848
+ when AST::UnsafeExpr
849
+ infer_expression_type(expression.expression, env:, expected_type:)
850
+ when AST::ProcExpr
851
+ resolve_type_ref(AST::ProcType.new(params: expression.params, return_type: expression.return_type))
852
+ when AST::Call
853
+ kind, _callee_name, _receiver, callee_type = resolve_callee(expression.callee, env, arguments: expression.arguments)
854
+ case kind
855
+ when :function, :method, :associated_method, :callable_value,
856
+ :str_buffer_clear, :str_buffer_assign, :str_buffer_append, :str_buffer_assign_format, :str_buffer_append_format,
857
+ :str_buffer_len, :str_buffer_capacity, :str_buffer_as_str, :str_buffer_as_cstr,
858
+ :event_subscribe, :event_subscribe_once, :event_unsubscribe, :event_emit, :event_wait,
859
+ :compile_time_builtin,
860
+ :reinterpret, :zero, :hash, :equal, :order,
861
+ :dyn_method
862
+ callee_type.return_type
863
+ when :struct_literal, :struct_with, :array, :simd, :variant_arm_ctor, :adapt
864
+ callee_type
865
+ when :ref_of
866
+ argument_type = infer_expression_type(expression.arguments.fetch(0).value, env:)
867
+ Types::Registry.generic_instance("ref", [argument_type])
868
+ when :const_ptr_of
869
+ argument_type = infer_expression_type(expression.arguments.fetch(0).value, env:)
870
+ Types::Registry.generic_instance("const_ptr", [argument_type])
871
+ when :read
872
+ infer_value_type(expression.arguments.fetch(0).value, env:)
873
+ when :ptr_of
874
+ argument_type = infer_expression_type(expression.arguments.fetch(0).value, env:)
875
+ if ref_type?(argument_type)
876
+ Types::Registry.generic_instance("ptr", [referenced_type(argument_type)])
877
+ else
878
+ Types::Registry.generic_instance("ptr", [infer_expression_type(expression.arguments.fetch(0).value, env:, expected_type: expected_type && pointer_type?(expected_type) ? pointee_type(expected_type) : nil)])
879
+ end
880
+ when :array_as_span
881
+ callee_type
882
+ when :fatal
883
+ @ctx.types.fetch("void")
884
+ when :get
885
+ receiver_type = infer_expression_type(expression.arguments.fetch(0).value, env:)
886
+ elem_type = if array_type?(receiver_type)
887
+ array_element_type(receiver_type)
888
+ else
889
+ receiver_type.element_type
890
+ end
891
+ Types::Registry.nullable(Types::Registry.generic_instance("ptr", [elem_type]))
892
+ when :atomic_load, :atomic_add, :atomic_sub, :atomic_exchange, :atomic_store, :atomic_compare_exchange,
893
+ :simd_lane_with
894
+ callee_type.return_type
895
+ else
896
+ raise LoweringError.new("unsupported call kind #{kind}", line: 0, column: 0, path: @ctx.current_analysis_path)
897
+ end
898
+ when AST::PrefixCast
899
+ resolve_type_ref(expression.target_type)
900
+ when AST::Specialization
901
+ if expression.callee.is_a?(AST::Identifier) && expression.callee.name == "zero"
902
+ _, _, _, function_type = resolve_callee(expression, env, arguments: [])
903
+ function_type.return_type
904
+ elsif expression.callee.is_a?(AST::Identifier) && expression.callee.name == "default"
905
+ resolve_default_specialization(expression, env:).target_type
906
+ elsif (callable_resolution = resolve_specialized_callable_binding(expression, env:))
907
+ callable_kind, function_binding, = callable_resolution
908
+ raise LoweringError.new("specialized method must be called", line: 0, column: 0, path: @ctx.current_analysis_path) if callable_kind == :method
909
+
910
+ function_binding.type
911
+ else
912
+ raise LoweringError.new("unsupported specialization", line: 0, column: 0, path: @ctx.current_analysis_path)
913
+ end
914
+ when AST::RangeExpr
915
+ raise LoweringError.new("range expression is not valid in this context; use it as a for-loop iterable", line: 0, column: 0, path: @ctx.current_analysis_path)
916
+ when AST::ExpressionList
917
+ names = []
918
+ element_types = []
919
+ expression.elements.each do |element|
920
+ if element.is_a?(AST::Argument)
921
+ names << element.name
922
+ element_types << infer_expression_type(element.value, env:)
923
+ else
924
+ names << nil
925
+ element_types << infer_expression_type(element, env:)
926
+ end
927
+ end
928
+ has_named = names.any?
929
+ Types::Registry.tuple(element_types, field_names: has_named ? names : nil)
930
+ when AST::DetachExpr
931
+ Types::Handle.new
932
+ else
933
+ raise LoweringError.new("unsupported expression type #{expression.class.name}", line: 0, column: 0, path: @ctx.current_analysis_path)
934
+ end
935
+ end
936
+
937
+ def infer_binary_operand_types(expression, env:, expected_type: nil)
938
+ propagated_type = propagating_expected_type(expression.operator, expected_type)
939
+ left_type = infer_expression_type(expression.left, env:, expected_type: propagated_type)
940
+ right_env = binary_right_env(expression, env)
941
+ right_expected_type = case expression.operator
942
+ when "<<", ">>"
943
+ propagated_type || left_type
944
+ when "+", "-", "*", "/", "%"
945
+ propagated_type || left_type
946
+ when "|", "&", "^"
947
+ left_type
948
+ else
949
+ left_type
950
+ end
951
+ right_type = infer_expression_type(expression.right, env: right_env, expected_type: right_expected_type)
952
+ left_type, right_type = harmonize_binary_float_literal_types(expression.left, expression.right, left_type, right_type, env: right_env)
953
+ harmonize_binary_integer_literal_types(expression.left, expression.right, left_type, right_type, env: right_env)
954
+ end
955
+
956
+ def binary_right_env(expression, env)
957
+ case expression.operator
958
+ when "and"
959
+ env_with_refinements(env, flow_refinements(expression.left, truthy: true, env:))
960
+ when "or"
961
+ env_with_refinements(env, flow_refinements(expression.left, truthy: false, env:))
962
+ else
963
+ env
964
+ end
965
+ end
966
+
967
+ def harmonize_binary_float_literal_types(left_expression, right_expression, left_type, right_type, env:)
968
+ if float_literal_expression?(left_expression) && right_type.is_a?(Types::Primitive) && right_type.float?
969
+ left_type = infer_expression_type(left_expression, env:, expected_type: right_type)
970
+ end
971
+
972
+ if float_literal_expression?(right_expression) && left_type.is_a?(Types::Primitive) && left_type.float?
973
+ right_type = infer_expression_type(right_expression, env:, expected_type: left_type)
974
+ end
975
+
976
+ [left_type, right_type]
977
+ end
978
+
979
+ def float_literal_expression?(expression)
980
+ expression.is_a?(AST::FloatLiteral) ||
981
+ (expression.is_a?(AST::UnaryOp) && ["+", "-"].include?(expression.operator) && float_literal_expression?(expression.operand))
982
+ end
983
+
984
+ def harmonize_binary_integer_literal_types(left_expression, right_expression, left_type, right_type, env:)
985
+ if integer_literal_expression?(left_expression) && right_type.is_a?(Types::Primitive) && right_type.integer?
986
+ if exact_compile_time_numeric_compatibility?(left_type, left_expression, right_type, env:)
987
+ left_type = infer_expression_type(left_expression, env:, expected_type: right_type)
988
+ end
1066
989
  end
1067
990
 
1068
- def foreign_identity_projection_expression(expression, target_type)
1069
- return expression if expression.type == target_type
1070
- return cast_expression(expression, target_type) if foreign_identity_projection_cast_compatible?(expression.type, target_type)
1071
-
1072
- if foreign_identity_projection_reinterpret_compatible?(expression.type, target_type)
1073
- record_external_layout_assertion(expression.type, target_type)
1074
- return reinterpret_expression(expression, target_type)
991
+ if integer_literal_expression?(right_expression) && left_type.is_a?(Types::Primitive) && left_type.integer?
992
+ if exact_compile_time_numeric_compatibility?(right_type, right_expression, left_type, env:)
993
+ right_type = infer_expression_type(right_expression, env:, expected_type: left_type)
1075
994
  end
1076
-
1077
- nil
1078
995
  end
1079
996
 
1080
- def record_external_layout_assertion(source_type, target_type)
1081
- source_root = ffi_external_layout_root_type(source_type)
1082
- target_root = ffi_external_layout_root_type(target_type)
1083
- return unless source_root && target_root
1084
- return unless source_root.external && target_root.external
1085
- return if source_root.module_name == target_root.module_name
997
+ [left_type, right_type]
998
+ end
1086
999
 
1087
- pair_key = [[source_root.module_name, source_root.name], [target_root.module_name, target_root.name]].sort.freeze
1088
- return if @artifacts.emitted_external_layout_pairs[pair_key]
1000
+ def integer_literal_expression?(expression)
1001
+ expression.is_a?(AST::IntegerLiteral)
1002
+ end
1089
1003
 
1090
- @artifacts.emitted_external_layout_pairs[pair_key] = true
1091
- @artifacts.external_layout_assertions << IR::StaticAssert.new(
1092
- condition: IR::Binary.new(
1093
- operator: "==",
1094
- left: IR::SizeofExpr.new(target_type: source_root, type: @ctx.types.fetch("ptr_uint")),
1095
- right: IR::SizeofExpr.new(target_type: target_root, type: @ctx.types.fetch("ptr_uint")),
1096
- type: @ctx.types.fetch("bool"),
1097
- ),
1098
- message: IR::StringLiteral.new(
1099
- value: "FFI layout mismatch: #{source_root} vs #{target_root}",
1100
- type: @ctx.types.fetch("str"),
1101
- cstring: false,
1102
- ),
1103
- )
1004
+ def propagating_expected_type(operator, expected_type)
1005
+ case operator
1006
+ when "+", "-", "*", "/", "%", "<<", ">>"
1007
+ return expected_type if expected_type.is_a?(Types::Primitive) && expected_type.numeric?
1008
+ when "|", "&", "^"
1009
+ return expected_type if expected_type.is_a?(Types::Primitive) && expected_type.integer?
1010
+ return expected_type if expected_type.is_a?(Types::Flags)
1104
1011
  end
1105
1012
 
1106
- def ffi_external_layout_root_type(type)
1107
- type = type.base while type.is_a?(Types::Nullable)
1108
- return pointee_type(type) if pointer_type?(type)
1013
+ nil
1014
+ end
1109
1015
 
1110
- type
1016
+ def promoted_binary_operand_type(operator, left_type, right_type)
1017
+ case operator
1018
+ when "+", "-", "*", "/", "<", "<=", ">", ">=", "==", "!="
1019
+ common_numeric_type(left_type, right_type)
1020
+ when "%"
1021
+ common_integer_type(left_type, right_type)
1111
1022
  end
1023
+ end
1112
1024
 
1113
- def infer_null_literal_type(expression, expected_type)
1114
- return Types::Null.new(resolve_type_ref(expression.type)) if expression.type
1025
+ def cast_expression(expression, target_type)
1026
+ return expression if expression.type == target_type
1115
1027
 
1116
- expected_type || null_type
1117
- end
1118
-
1119
- def common_numeric_type(left_type, right_type)
1120
- left_type = left_type.backing_type if left_type.is_a?(Types::EnumBase)
1121
- right_type = right_type.backing_type if right_type.is_a?(Types::EnumBase)
1122
- return left_type if left_type == right_type
1123
- return unless left_type.is_a?(Types::Primitive) && right_type.is_a?(Types::Primitive)
1124
- return unless left_type.numeric? && right_type.numeric?
1028
+ IR::Cast.new(target_type:, expression:, type: target_type)
1029
+ end
1125
1030
 
1126
- return common_integer_type(left_type, right_type) if left_type.integer? && right_type.integer?
1127
- return wider_float_type(left_type, right_type) if left_type.float? && right_type.float?
1031
+ def pointer_lowered_sync_method_receiver?(binding)
1032
+ return false if binding.async
1128
1033
 
1129
- float_type, integer_type = left_type.float? ? [left_type, right_type] : [right_type, left_type]
1130
- return unless integer_type.integer? && integer_type.fixed_width_integer?
1034
+ pointer_lowered_method_receiver?(binding.type, binding)
1035
+ end
1131
1036
 
1132
- float_type
1133
- end
1037
+ def pointer_lowered_method_receiver?(callee_type, callee_binding)
1038
+ return true if callee_type.receiver_editable
1134
1039
 
1135
- def common_integer_type(left_type, right_type)
1136
- left_type = left_type.backing_type if left_type.is_a?(Types::EnumBase)
1137
- right_type = right_type.backing_type if right_type.is_a?(Types::EnumBase)
1138
- return left_type if left_type == right_type
1139
- return unless left_type.is_a?(Types::Primitive) && right_type.is_a?(Types::Primitive)
1140
- return unless left_type.integer? && right_type.integer?
1141
- return unless left_type.fixed_width_integer? && right_type.fixed_width_integer?
1142
- return unless left_type.signed_integer? == right_type.signed_integer?
1040
+ receiver_type_uses_pointer_lowering?(callee_type.receiver_type) && !callee_binding&.async
1041
+ end
1143
1042
 
1144
- left_type.integer_width >= right_type.integer_width ? left_type : right_type
1043
+ def receiver_type_uses_pointer_lowering?(type)
1044
+ case type
1045
+ when Types::Nullable
1046
+ receiver_type_uses_pointer_lowering?(type.base)
1047
+ when Types::Struct, Types::StructInstance
1048
+ type_contains_array_storage?(type)
1049
+ else
1050
+ false
1145
1051
  end
1052
+ end
1053
+
1054
+ def type_contains_array_storage?(type, visited = Set.new)
1055
+ visitor = ContainsArrayStorageVisitor.new
1056
+ visitor.visit(type)
1057
+ visitor.found?
1058
+ end
1146
1059
 
1147
- def wider_float_type(left_type, right_type)
1148
- left_type.float_width >= right_type.float_width ? left_type : right_type
1149
- end
1060
+ def reinterpret_expression(expression, target_type)
1061
+ return expression if expression.type == target_type
1150
1062
 
1151
- def aggregate_arithmetic_result_type(operator, left_type, right_type)
1152
- if left_type.is_a?(Types::Vector) && right_type.is_a?(Types::Vector) && left_type.name == right_type.name
1153
- return left_type
1154
- end
1155
- if left_type.is_a?(Types::Matrix) && right_type.is_a?(Types::Matrix) && left_type.name == right_type.name
1156
- return left_type
1157
- end
1158
- if left_type.is_a?(Types::Quaternion) && right_type.is_a?(Types::Quaternion)
1159
- return left_type
1160
- end
1063
+ IR::ReinterpretExpr.new(target_type:, source_type: expression.type, expression:, type: target_type)
1064
+ end
1161
1065
 
1162
- scalar_result = aggregate_scalar_result(left_type, right_type)
1163
- return scalar_result if scalar_result
1066
+ def foreign_identity_projection_expression(expression, target_type)
1067
+ return expression if expression.type == target_type
1068
+ return cast_expression(expression, target_type) if foreign_identity_projection_cast_compatible?(expression.type, target_type)
1164
1069
 
1165
- case operator
1166
- when "+", "-"
1167
- nil
1168
- when "*", "/"
1169
- aggregate_scalar_result(right_type, left_type)
1170
- else
1171
- nil
1172
- end
1070
+ if foreign_identity_projection_reinterpret_compatible?(expression.type, target_type)
1071
+ record_external_layout_assertion(expression.type, target_type)
1072
+ return reinterpret_expression(expression, target_type)
1173
1073
  end
1174
1074
 
1175
- def aggregate_scalar_result(aggregate_type, scalar_type)
1176
- return nil unless aggregate_type.is_a?(Types::Vector) || aggregate_type.is_a?(Types::Matrix)
1177
- return nil unless scalar_type.is_a?(Types::Primitive) && scalar_type.numeric?
1075
+ nil
1076
+ end
1178
1077
 
1179
- aggregate_type
1180
- end
1078
+ def record_external_layout_assertion(source_type, target_type)
1079
+ source_root = ffi_external_layout_root_type(source_type)
1080
+ target_root = ffi_external_layout_root_type(target_type)
1081
+ return unless source_root && target_root
1082
+ return unless source_root.external && target_root.external
1083
+ return if source_root.module_name == target_root.module_name
1181
1084
 
1182
- def pointer_arithmetic_result_type(operator, left_type, right_type)
1183
- return left_type if pointer_type?(left_type) && integer_type?(right_type) && (operator == "+" || operator == "-")
1184
- return right_type if operator == "+" && integer_type?(left_type) && pointer_type?(right_type)
1085
+ pair_key = [[source_root.module_name, source_root.name], [target_root.module_name, target_root.name]].sort.freeze
1086
+ return if @artifacts.emitted_external_layout_pairs[pair_key]
1185
1087
 
1186
- nil
1187
- end
1088
+ @artifacts.emitted_external_layout_pairs[pair_key] = true
1089
+ @artifacts.external_layout_assertions << IR::StaticAssert.new(
1090
+ condition: IR::Binary.new(
1091
+ operator: "==",
1092
+ left: IR::SizeofExpr.new(target_type: source_root, type: @ctx.types.fetch("ptr_uint")),
1093
+ right: IR::SizeofExpr.new(target_type: target_root, type: @ctx.types.fetch("ptr_uint")),
1094
+ type: @ctx.types.fetch("bool"),
1095
+ ),
1096
+ message: IR::StringLiteral.new(
1097
+ value: "FFI layout mismatch: #{source_root} vs #{target_root}",
1098
+ type: @ctx.types.fetch("str"),
1099
+ cstring: false,
1100
+ ),
1101
+ )
1102
+ end
1188
1103
 
1189
- def resolve_type_expression(expression)
1190
- case expression
1191
- when AST::Identifier
1192
- return current_type_params[expression.name] if current_type_params.key?(expression.name)
1104
+ def ffi_external_layout_root_type(type)
1105
+ type = type.base while type.is_a?(Types::Nullable)
1106
+ return pointee_type(type) if pointer_type?(type)
1193
1107
 
1194
- @ctx.types[expression.name]
1195
- when AST::MemberAccess
1196
- return nil unless expression.receiver.is_a?(AST::Identifier)
1197
-
1198
- if @ctx.imports.key?(expression.receiver.name)
1199
- return @ctx.imports.fetch(expression.receiver.name).types[expression.member]
1200
- end
1108
+ type
1109
+ end
1201
1110
 
1202
- parent_type = @ctx.types[expression.receiver.name]
1203
- return parent_type.nested_types[expression.member] if parent_type.respond_to?(:nested_types) && parent_type.nested_types.key?(expression.member)
1111
+ def infer_null_literal_type(expression, expected_type)
1112
+ return Types::Null.new(resolve_type_ref(expression.type)) if expression.type
1204
1113
 
1205
- nil
1206
- when AST::Specialization
1207
- type_ref = type_ref_from_specialization(expression)
1208
- return nil unless type_ref
1114
+ expected_type || null_type
1115
+ end
1209
1116
 
1210
- resolve_type_ref(type_ref)
1211
- end
1212
- end
1117
+ def common_numeric_type(left_type, right_type)
1118
+ left_type = left_type.backing_type if left_type.is_a?(Types::EnumBase)
1119
+ right_type = right_type.backing_type if right_type.is_a?(Types::EnumBase)
1120
+ return left_type if left_type == right_type
1121
+ return unless left_type.is_a?(Types::Primitive) && right_type.is_a?(Types::Primitive)
1122
+ return unless left_type.numeric? && right_type.numeric?
1213
1123
 
1214
- def resolve_type_member(type, name)
1215
- case type
1216
- when Types::Enum, Types::Flags
1217
- type.member(name)
1218
- when Types::Variant
1219
- type if type.arm_names.include?(name)
1220
- end
1221
- end
1124
+ return common_integer_type(left_type, right_type) if left_type.integer? && right_type.integer?
1125
+ return wider_float_type(left_type, right_type) if left_type.float? && right_type.float?
1222
1126
 
1223
- def function_type_for_name(name)
1224
- binding = @ctx.functions.fetch(name)
1225
- raise LoweringError.new("generic function #{name} cannot be used as a value", line: 0, column: 0, path: @ctx.current_analysis_path) if binding.type_params.any?
1226
- raise LoweringError.new("foreign function #{name} cannot be used as a value", line: 0, column: 0, path: @ctx.current_analysis_path) if foreign_function_binding?(binding)
1127
+ float_type, integer_type = left_type.float? ? [left_type, right_type] : [right_type, left_type]
1128
+ return unless integer_type.integer? && integer_type.fixed_width_integer?
1227
1129
 
1228
- binding.type
1229
- end
1130
+ float_type
1131
+ end
1230
1132
 
1231
- def resolve_specialized_callable_binding(expression, env:)
1232
- callable_kind = :function
1233
- receiver = nil
1234
- receiver_type = nil
1235
- binding = case expression.callee
1236
- when AST::Identifier
1237
- @ctx.functions[expression.callee.name]
1238
- when AST::MemberAccess
1239
- if expression.callee.receiver.is_a?(AST::Identifier) && @ctx.imports.key?(expression.callee.receiver.name)
1240
- @ctx.imports.fetch(expression.callee.receiver.name).functions[expression.callee.member]
1241
- elsif (type_expr = resolve_type_expression(expression.callee.receiver))
1242
- dispatch_receiver_type = method_dispatch_receiver_type(type_expr)
1243
- method_entry_receiver_type = type_expr
1244
- method_entry = @method_definitions[[type_expr, expression.callee.member]]
1245
- method_entry ||= @method_definitions[[type_expr, "static:#{expression.callee.member}"]]
1246
- unless method_entry || dispatch_receiver_type == type_expr
1247
- method_entry_receiver_type = dispatch_receiver_type
1248
- method_entry = @method_definitions[[dispatch_receiver_type, expression.callee.member]]
1249
- method_entry ||= @method_definitions[[dispatch_receiver_type, "static:#{expression.callee.member}"]]
1250
- end
1251
- if method_entry
1252
- method_analysis, method_ast = method_entry
1253
- method_binding = method_analysis.methods.fetch(method_entry_receiver_type).fetch(method_analysis_key(method_ast))
1254
- if method_binding.type.receiver_type.nil?
1255
- receiver_type = type_expr
1256
- method_binding
1257
- end
1258
- end
1259
- else
1260
- resolved_receiver_type = infer_method_receiver_type(expression.callee.receiver, env:, member_name: expression.callee.member)
1261
- dispatch_receiver_type = method_dispatch_receiver_type(resolved_receiver_type)
1262
- method_entry_receiver_type = resolved_receiver_type
1263
- method_entry = @method_definitions[[resolved_receiver_type, expression.callee.member]]
1264
- unless method_entry || dispatch_receiver_type == resolved_receiver_type
1265
- method_entry_receiver_type = dispatch_receiver_type
1266
- method_entry = @method_definitions[[dispatch_receiver_type, expression.callee.member]]
1267
- end
1268
- if method_entry
1269
- method_analysis, method_ast = method_entry
1270
- callable_kind = :method
1271
- receiver = expression.callee.receiver
1272
- receiver_type = resolved_receiver_type
1273
- method_analysis.methods.fetch(method_entry_receiver_type).fetch(method_analysis_key(method_ast))
1274
- end
1275
- end
1276
- end
1277
- return nil unless binding
1133
+ def common_integer_type(left_type, right_type)
1134
+ left_type = left_type.backing_type if left_type.is_a?(Types::EnumBase)
1135
+ right_type = right_type.backing_type if right_type.is_a?(Types::EnumBase)
1136
+ return left_type if left_type == right_type
1137
+ return unless left_type.is_a?(Types::Primitive) && right_type.is_a?(Types::Primitive)
1138
+ return unless left_type.integer? && right_type.integer?
1139
+ return unless left_type.fixed_width_integer? && right_type.fixed_width_integer?
1140
+ return unless left_type.signed_integer? == right_type.signed_integer?
1278
1141
 
1279
- type_arguments = resolve_specialization_type_arguments(expression)
1280
- [callable_kind, instantiate_function_binding_with_receiver(binding, type_arguments, receiver_type:), receiver, method_entry_receiver_type]
1281
- end
1142
+ left_type.integer_width >= right_type.integer_width ? left_type : right_type
1143
+ end
1282
1144
 
1283
- def resolve_default_specialization(expression, env:)
1284
- target_type = resolve_type_ref(expression.arguments.fetch(0).value)
1145
+ def wider_float_type(left_type, right_type)
1146
+ left_type.float_width >= right_type.float_width ? left_type : right_type
1147
+ end
1285
1148
 
1286
- explicit_default = resolve_explicit_default_binding(target_type, context: "default[#{target_type}]")
1287
- raise LoweringError.new("default[#{target_type}] requires associated function #{target_type}.default()", line: 0, column: 0, path: @ctx.current_analysis_path) unless explicit_default
1288
-
1289
- DefaultResolution.new(target_type:, binding: explicit_default.binding, callee_name: explicit_default.callee_name)
1149
+ def aggregate_arithmetic_result_type(operator, left_type, right_type)
1150
+ if left_type.is_a?(Types::Vector) && right_type.is_a?(Types::Vector) && left_type.name == right_type.name
1151
+ return left_type
1152
+ end
1153
+ if left_type.is_a?(Types::Matrix) && right_type.is_a?(Types::Matrix) && left_type.name == right_type.name
1154
+ return left_type
1155
+ end
1156
+ if left_type.is_a?(Types::Quaternion) && right_type.is_a?(Types::Quaternion)
1157
+ return left_type
1290
1158
  end
1291
1159
 
1292
- def resolve_hash_specialization(expression, env:)
1293
- target_type = resolve_type_ref(expression.arguments.fetch(0).value)
1294
- explicit_hash = resolve_explicit_hash_binding(target_type, context: "hash[#{target_type}]")
1295
- raise LoweringError.new("hash[#{target_type}] requires associated function #{target_type}.hash(value: const_ptr[#{target_type}]) -> uint", line: 0, column: 0, path: @ctx.current_analysis_path) unless explicit_hash
1160
+ scalar_result = aggregate_scalar_result(left_type, right_type)
1161
+ return scalar_result if scalar_result
1296
1162
 
1297
- HashResolution.new(target_type:, binding: explicit_hash.binding, callee_name: explicit_hash.callee_name)
1163
+ case operator
1164
+ when "+", "-"
1165
+ nil
1166
+ when "*", "/"
1167
+ aggregate_scalar_result(right_type, left_type)
1168
+ else
1169
+ nil
1298
1170
  end
1171
+ end
1299
1172
 
1300
- def resolve_equal_specialization(expression, env:)
1301
- target_type = resolve_type_ref(expression.arguments.fetch(0).value)
1302
- explicit_equal = resolve_explicit_equal_binding(target_type, context: "equal[#{target_type}]")
1303
- raise LoweringError.new("equal[#{target_type}] requires associated function #{target_type}.equal(left: const_ptr[#{target_type}], right: const_ptr[#{target_type}]) -> bool", line: 0, column: 0, path: @ctx.current_analysis_path) unless explicit_equal
1173
+ def aggregate_scalar_result(aggregate_type, scalar_type)
1174
+ return nil unless aggregate_type.is_a?(Types::Vector) || aggregate_type.is_a?(Types::Matrix)
1175
+ return nil unless scalar_type.is_a?(Types::Primitive) && scalar_type.numeric?
1304
1176
 
1305
- EqualResolution.new(target_type:, binding: explicit_equal.binding, callee_name: explicit_equal.callee_name)
1306
- end
1177
+ aggregate_type
1178
+ end
1307
1179
 
1308
- def resolve_order_specialization(expression, env:)
1309
- target_type = resolve_type_ref(expression.arguments.fetch(0).value)
1310
- explicit_order = resolve_explicit_order_binding(target_type, context: "order[#{target_type}]")
1311
- raise LoweringError.new("order[#{target_type}] requires associated function #{target_type}.order(left: const_ptr[#{target_type}], right: const_ptr[#{target_type}]) -> int", line: 0, column: 0, path: @ctx.current_analysis_path) unless explicit_order
1180
+ def pointer_arithmetic_result_type(operator, left_type, right_type)
1181
+ return left_type if pointer_type?(left_type) && integer_type?(right_type) && (operator == "+" || operator == "-")
1182
+ return right_type if operator == "+" && integer_type?(left_type) && pointer_type?(right_type)
1312
1183
 
1313
- OrderResolution.new(target_type:, binding: explicit_order.binding, callee_name: explicit_order.callee_name)
1314
- end
1184
+ nil
1185
+ end
1315
1186
 
1316
- def resolve_explicit_default_binding(target_type, context:)
1317
- requirement_message = "#{context} requires associated function #{target_type}.default()"
1318
- resolve_explicit_associated_binding(target_type, "default", requirement_message:) do |method_binding, _method_analysis, _method_entry_receiver_type|
1319
- raise LoweringError.new("#{context} requires #{target_type}.default() to take 0 arguments", line: 0, column: 0, path: @ctx.current_analysis_path) unless method_binding.type.params.empty?
1320
- unless method_binding.type.return_type == target_type
1321
- raise LoweringError.new("#{context} requires #{target_type}.default() to return #{target_type}, got #{method_binding.type.return_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
1322
- end
1323
- end
1324
- end
1187
+ def resolve_type_expression(expression)
1188
+ case expression
1189
+ when AST::Identifier
1190
+ return current_type_params[expression.name] if current_type_params.key?(expression.name)
1325
1191
 
1326
- def resolve_explicit_hash_binding(target_type, context:)
1327
- requirement_message = "#{context} requires associated function #{target_type}.hash(value: const_ptr[#{target_type}]) -> uint"
1328
- resolve_explicit_associated_binding(target_type, "hash", requirement_message:) do |method_binding, _method_analysis, _method_entry_receiver_type|
1329
- unless method_binding.type.params.map(&:type) == [const_pointer_to(target_type)]
1330
- raise LoweringError.new("#{context} requires #{target_type}.hash(value: const_ptr[#{target_type}]) -> uint", line: 0, column: 0, path: @ctx.current_analysis_path)
1331
- end
1332
- unless method_binding.type.return_type == @ctx.types.fetch("uint")
1333
- raise LoweringError.new("#{context} requires #{target_type}.hash(value: const_ptr[#{target_type}]) -> uint, got #{method_binding.type.return_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
1334
- end
1335
- end
1336
- end
1192
+ @ctx.types[expression.name]
1193
+ when AST::MemberAccess
1194
+ return nil unless expression.receiver.is_a?(AST::Identifier)
1337
1195
 
1338
- def resolve_explicit_equal_binding(target_type, context:)
1339
- requirement_message = "#{context} requires associated function #{target_type}.equal(left: const_ptr[#{target_type}], right: const_ptr[#{target_type}]) -> bool"
1340
- resolve_explicit_associated_binding(target_type, "equal", requirement_message:) do |method_binding, _method_analysis, _method_entry_receiver_type|
1341
- expected_param_types = [const_pointer_to(target_type), const_pointer_to(target_type)]
1342
- unless method_binding.type.params.map(&:type) == expected_param_types
1343
- raise LoweringError.new("#{context} requires #{target_type}.equal(left: const_ptr[#{target_type}], right: const_ptr[#{target_type}]) -> bool", line: 0, column: 0, path: @ctx.current_analysis_path)
1344
- end
1345
- unless method_binding.type.return_type == @ctx.types.fetch("bool")
1346
- raise LoweringError.new("#{context} requires #{target_type}.equal(left: const_ptr[#{target_type}], right: const_ptr[#{target_type}]) -> bool, got #{method_binding.type.return_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
1347
- end
1196
+ if @ctx.imports.key?(expression.receiver.name)
1197
+ return @ctx.imports.fetch(expression.receiver.name).types[expression.member]
1348
1198
  end
1349
- end
1350
1199
 
1351
- def resolve_explicit_order_binding(target_type, context:)
1352
- requirement_message = "#{context} requires associated function #{target_type}.order(left: const_ptr[#{target_type}], right: const_ptr[#{target_type}]) -> int"
1353
- resolve_explicit_associated_binding(target_type, "order", requirement_message:) do |method_binding, _method_analysis, _method_entry_receiver_type|
1354
- expected_param_types = [const_pointer_to(target_type), const_pointer_to(target_type)]
1355
- unless method_binding.type.params.map(&:type) == expected_param_types
1356
- raise LoweringError.new("#{context} requires #{target_type}.order(left: const_ptr[#{target_type}], right: const_ptr[#{target_type}]) -> int", line: 0, column: 0, path: @ctx.current_analysis_path)
1357
- end
1358
- unless method_binding.type.return_type == @ctx.types.fetch("int")
1359
- raise LoweringError.new("#{context} requires #{target_type}.order(left: const_ptr[#{target_type}], right: const_ptr[#{target_type}]) -> int, got #{method_binding.type.return_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
1360
- end
1361
- end
1362
- end
1200
+ parent_type = @ctx.types[expression.receiver.name]
1201
+ return parent_type.nested_types[expression.member] if parent_type.respond_to?(:nested_types) && parent_type.nested_types.key?(expression.member)
1363
1202
 
1364
- def resolve_explicit_format_binding(target_type, context:)
1365
- length_binding = resolve_explicit_format_len_binding(target_type, context:)
1366
- append_binding = resolve_explicit_format_append_binding(target_type, context:)
1203
+ nil
1204
+ when AST::Specialization
1205
+ type_ref = type_ref_from_specialization(expression)
1206
+ return nil unless type_ref
1207
+
1208
+ resolve_type_ref(type_ref)
1209
+ end
1210
+ end
1211
+
1212
+ def resolve_type_member(type, name)
1213
+ case type
1214
+ when Types::Enum, Types::Flags
1215
+ type.member(name)
1216
+ when Types::Variant
1217
+ type if type.arm_names.include?(name)
1218
+ end
1219
+ end
1220
+
1221
+ def function_type_for_name(name)
1222
+ binding = @ctx.functions.fetch(name)
1223
+ raise LoweringError.new("generic function #{name} cannot be used as a value", line: 0, column: 0, path: @ctx.current_analysis_path) if binding.type_params.any?
1224
+ raise LoweringError.new("foreign function #{name} cannot be used as a value", line: 0, column: 0, path: @ctx.current_analysis_path) if foreign_function_binding?(binding)
1225
+
1226
+ binding.type
1227
+ end
1228
+
1229
+ def resolve_specialized_callable_binding(expression, env:)
1230
+ callable_kind = :function
1231
+ receiver = nil
1232
+ receiver_type = nil
1233
+ binding = case expression.callee
1234
+ when AST::Identifier
1235
+ @ctx.functions[expression.callee.name]
1236
+ when AST::MemberAccess
1237
+ if expression.callee.receiver.is_a?(AST::Identifier) && @ctx.imports.key?(expression.callee.receiver.name)
1238
+ @ctx.imports.fetch(expression.callee.receiver.name).functions[expression.callee.member]
1239
+ elsif (type_expr = resolve_type_expression(expression.callee.receiver))
1240
+ dispatch_receiver_type = method_dispatch_receiver_type(type_expr)
1241
+ method_entry_receiver_type = type_expr
1242
+ method_entry = @method_definitions[[type_expr, expression.callee.member]]
1243
+ method_entry ||= @method_definitions[[type_expr, "static:#{expression.callee.member}"]]
1244
+ unless method_entry || dispatch_receiver_type == type_expr
1245
+ method_entry_receiver_type = dispatch_receiver_type
1246
+ method_entry = @method_definitions[[dispatch_receiver_type, expression.callee.member]]
1247
+ method_entry ||= @method_definitions[[dispatch_receiver_type, "static:#{expression.callee.member}"]]
1248
+ end
1249
+ if method_entry
1250
+ method_analysis, method_ast = method_entry
1251
+ method_binding = method_analysis.methods.fetch(method_entry_receiver_type).fetch(method_analysis_key(method_ast))
1252
+ if method_binding.type.receiver_type.nil?
1253
+ receiver_type = type_expr
1254
+ method_binding
1255
+ end
1256
+ end
1257
+ else
1258
+ resolved_receiver_type = infer_method_receiver_type(expression.callee.receiver, env:, member_name: expression.callee.member)
1259
+ dispatch_receiver_type = method_dispatch_receiver_type(resolved_receiver_type)
1260
+ method_entry_receiver_type = resolved_receiver_type
1261
+ method_entry = @method_definitions[[resolved_receiver_type, expression.callee.member]]
1262
+ unless method_entry || dispatch_receiver_type == resolved_receiver_type
1263
+ method_entry_receiver_type = dispatch_receiver_type
1264
+ method_entry = @method_definitions[[dispatch_receiver_type, expression.callee.member]]
1265
+ end
1266
+ if method_entry
1267
+ method_analysis, method_ast = method_entry
1268
+ callable_kind = :method
1269
+ receiver = expression.callee.receiver
1270
+ receiver_type = resolved_receiver_type
1271
+ method_analysis.methods.fetch(method_entry_receiver_type).fetch(method_analysis_key(method_ast))
1272
+ end
1273
+ end
1274
+ end
1275
+ return nil unless binding
1367
1276
 
1368
- return ExplicitFormatBinding.new(
1369
- length_binding: length_binding.fetch(:binding),
1370
- length_callee_name: length_binding.fetch(:callee_name),
1371
- append_binding: append_binding.fetch(:binding),
1372
- append_callee_name: append_binding.fetch(:callee_name),
1373
- ) if length_binding && append_binding
1277
+ type_arguments = resolve_specialization_type_arguments(expression)
1278
+ [callable_kind, instantiate_function_binding_with_receiver(binding, type_arguments, receiver_type:), receiver, method_entry_receiver_type]
1279
+ end
1374
1280
 
1375
- if length_binding || append_binding
1376
- raise LoweringError.new("#{context} requires methods #{target_type}.format_len() -> ptr_uint and #{target_type}.append_format(output: ref[std.string.String]) -> void", line: 0, column: 0, path: @ctx.current_analysis_path)
1377
- end
1281
+ def resolve_default_specialization(expression, env:)
1282
+ target_type = resolve_type_ref(expression.arguments.fetch(0).value)
1378
1283
 
1379
- nil
1380
- end
1284
+ explicit_default = resolve_explicit_default_binding(target_type, context: "default[#{target_type}]")
1285
+ raise LoweringError.new("default[#{target_type}] requires associated function #{target_type}.default()", line: 0, column: 0, path: @ctx.current_analysis_path) unless explicit_default
1381
1286
 
1382
- def resolve_explicit_format_len_binding(target_type, context:)
1383
- requirement_message = "#{context} requires method #{target_type}.format_len() -> ptr_uint"
1384
- resolve_explicit_instance_binding(target_type, "format_len", requirement_message:) do |method_binding, _method_analysis, _method_entry_receiver_type|
1385
- raise LoweringError.new("#{context} requires #{target_type}.format_len() to take 0 arguments", line: 0, column: 0, path: @ctx.current_analysis_path) unless method_binding.type.params.empty?
1386
- raise LoweringError.new("#{context} requires #{target_type}.format_len() to be non-editable", line: 0, column: 0, path: @ctx.current_analysis_path) if method_binding.type.receiver_editable
1387
- unless method_binding.type.return_type == @ctx.types.fetch("ptr_uint")
1388
- raise LoweringError.new("#{context} requires #{target_type}.format_len() -> ptr_uint, got #{method_binding.type.return_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
1389
- end
1390
- end
1391
- end
1287
+ DefaultResolution.new(target_type:, binding: explicit_default.binding, callee_name: explicit_default.callee_name)
1288
+ end
1392
1289
 
1393
- def resolve_explicit_format_append_binding(target_type, context:)
1394
- requirement_message = "#{context} requires method #{target_type}.append_format(output: ref[std.string.String]) -> void"
1395
- resolve_explicit_instance_binding(target_type, "append_format", requirement_message:) do |method_binding, _method_analysis, _method_entry_receiver_type|
1396
- raise LoweringError.new("#{context} requires #{target_type}.append_format() to be non-editable", line: 0, column: 0, path: @ctx.current_analysis_path) if method_binding.type.receiver_editable
1397
- unless method_binding.type.params.length == 1 && string_builder_ref_type?(method_binding.type.params.first.type)
1398
- raise LoweringError.new("#{context} requires #{target_type}.append_format(output: ref[std.string.String]) -> void", line: 0, column: 0, path: @ctx.current_analysis_path)
1399
- end
1400
- unless method_binding.type.return_type == @ctx.types.fetch("void")
1401
- raise LoweringError.new("#{context} requires #{target_type}.append_format(output: ref[std.string.String]) -> void, got #{method_binding.type.return_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
1402
- end
1403
- end
1404
- end
1290
+ def resolve_hash_specialization(expression, env:)
1291
+ target_type = resolve_type_ref(expression.arguments.fetch(0).value)
1292
+ explicit_hash = resolve_explicit_hash_binding(target_type, context: "hash[#{target_type}]")
1293
+ raise LoweringError.new("hash[#{target_type}] requires associated function #{target_type}.hash(value: const_ptr[#{target_type}]) -> uint", line: 0, column: 0, path: @ctx.current_analysis_path) unless explicit_hash
1405
1294
 
1406
- def method_analysis_key(method_ast)
1407
- method_ast.kind == :static ? "static:#{method_ast.name}" : method_ast.name
1408
- end
1295
+ HashResolution.new(target_type:, binding: explicit_hash.binding, callee_name: explicit_hash.callee_name)
1296
+ end
1409
1297
 
1410
- def resolve_explicit_associated_binding(target_type, method_name, requirement_message:)
1411
- dispatch_receiver_type = method_dispatch_receiver_type(target_type)
1412
- method_entry_receiver_type = target_type
1413
- static_method_name = "static:#{method_name}"
1414
- method_entry = @method_definitions[[target_type, static_method_name]]
1415
- unless method_entry || dispatch_receiver_type == target_type
1416
- method_entry_receiver_type = dispatch_receiver_type
1417
- method_entry = @method_definitions[[dispatch_receiver_type, static_method_name]]
1418
- end
1419
- return nil unless method_entry
1298
+ def resolve_equal_specialization(expression, env:)
1299
+ target_type = resolve_type_ref(expression.arguments.fetch(0).value)
1300
+ explicit_equal = resolve_explicit_equal_binding(target_type, context: "equal[#{target_type}]")
1301
+ raise LoweringError.new("equal[#{target_type}] requires associated function #{target_type}.equal(left: const_ptr[#{target_type}], right: const_ptr[#{target_type}]) -> bool", line: 0, column: 0, path: @ctx.current_analysis_path) unless explicit_equal
1420
1302
 
1421
- method_analysis, method_ast = method_entry
1422
- method_binding = method_analysis.methods.fetch(method_entry_receiver_type).fetch(method_analysis_key(method_ast))
1423
- raise LoweringError.new(requirement_message, line: 0, column: 0, path: @ctx.current_analysis_path) unless method_binding.type.receiver_type.nil?
1303
+ EqualResolution.new(target_type:, binding: explicit_equal.binding, callee_name: explicit_equal.callee_name)
1304
+ end
1424
1305
 
1425
- method_binding = instantiate_function_binding_with_receiver(method_binding, [], receiver_type: target_type) if method_binding.type_params.any?
1426
- yield method_binding, method_analysis, method_entry_receiver_type
1306
+ def resolve_order_specialization(expression, env:)
1307
+ target_type = resolve_type_ref(expression.arguments.fetch(0).value)
1308
+ explicit_order = resolve_explicit_order_binding(target_type, context: "order[#{target_type}]")
1309
+ raise LoweringError.new("order[#{target_type}] requires associated function #{target_type}.order(left: const_ptr[#{target_type}], right: const_ptr[#{target_type}]) -> int", line: 0, column: 0, path: @ctx.current_analysis_path) unless explicit_order
1427
1310
 
1428
- callee_name = if method_binding.external
1429
- external_function_c_name(method_binding)
1430
- else
1431
- function_binding_c_name(method_binding, module_name: method_analysis.module_name, receiver_type: method_entry_receiver_type)
1432
- end
1311
+ OrderResolution.new(target_type:, binding: explicit_order.binding, callee_name: explicit_order.callee_name)
1312
+ end
1433
1313
 
1434
- case method_name
1435
- when "default"
1436
- ExplicitDefaultBinding.new(binding: method_binding, callee_name:)
1437
- when "hash"
1438
- ExplicitHashBinding.new(binding: method_binding, callee_name:)
1439
- when "equal"
1440
- ExplicitEqualBinding.new(binding: method_binding, callee_name:)
1441
- when "order"
1442
- ExplicitOrderBinding.new(binding: method_binding, callee_name:)
1443
- else
1444
- raise LoweringError.new("unsupported associated hook #{method_name}", line: 0, column: 0, path: @ctx.current_analysis_path)
1314
+ def resolve_explicit_default_binding(target_type, context:)
1315
+ requirement_message = "#{context} requires associated function #{target_type}.default()"
1316
+ resolve_explicit_associated_binding(target_type, "default", requirement_message:) do |method_binding, _method_analysis, _method_entry_receiver_type|
1317
+ raise LoweringError.new("#{context} requires #{target_type}.default() to take 0 arguments", line: 0, column: 0, path: @ctx.current_analysis_path) unless method_binding.type.params.empty?
1318
+ unless method_binding.type.return_type == target_type
1319
+ raise LoweringError.new("#{context} requires #{target_type}.default() to return #{target_type}, got #{method_binding.type.return_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
1445
1320
  end
1446
1321
  end
1322
+ end
1447
1323
 
1448
- def resolve_explicit_instance_binding(target_type, method_name, requirement_message:)
1449
- dispatch_receiver_type = method_dispatch_receiver_type(target_type)
1450
- method_entry_receiver_type = target_type
1451
- method_entry = @method_definitions[[target_type, method_name]]
1452
- unless method_entry || dispatch_receiver_type == target_type
1453
- method_entry_receiver_type = dispatch_receiver_type
1454
- method_entry = @method_definitions[[dispatch_receiver_type, method_name]]
1324
+ def resolve_explicit_hash_binding(target_type, context:)
1325
+ requirement_message = "#{context} requires associated function #{target_type}.hash(value: const_ptr[#{target_type}]) -> uint"
1326
+ resolve_explicit_associated_binding(target_type, "hash", requirement_message:) do |method_binding, _method_analysis, _method_entry_receiver_type|
1327
+ unless method_binding.type.params.map(&:type) == [const_pointer_to(target_type)]
1328
+ raise LoweringError.new("#{context} requires #{target_type}.hash(value: const_ptr[#{target_type}]) -> uint", line: 0, column: 0, path: @ctx.current_analysis_path)
1455
1329
  end
1456
- return nil unless method_entry
1330
+ unless method_binding.type.return_type == @ctx.types.fetch("uint")
1331
+ raise LoweringError.new("#{context} requires #{target_type}.hash(value: const_ptr[#{target_type}]) -> uint, got #{method_binding.type.return_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
1332
+ end
1333
+ end
1334
+ end
1457
1335
 
1458
- method_analysis, method_ast = method_entry
1459
- method_binding = method_analysis.methods.fetch(method_entry_receiver_type).fetch(method_analysis_key(method_ast))
1460
- raise LoweringError.new(requirement_message, line: 0, column: 0, path: @ctx.current_analysis_path) if method_binding.type.receiver_type.nil?
1336
+ def resolve_explicit_equal_binding(target_type, context:)
1337
+ requirement_message = "#{context} requires associated function #{target_type}.equal(left: const_ptr[#{target_type}], right: const_ptr[#{target_type}]) -> bool"
1338
+ resolve_explicit_associated_binding(target_type, "equal", requirement_message:) do |method_binding, _method_analysis, _method_entry_receiver_type|
1339
+ expected_param_types = [const_pointer_to(target_type), const_pointer_to(target_type)]
1340
+ unless method_binding.type.params.map(&:type) == expected_param_types
1341
+ raise LoweringError.new("#{context} requires #{target_type}.equal(left: const_ptr[#{target_type}], right: const_ptr[#{target_type}]) -> bool", line: 0, column: 0, path: @ctx.current_analysis_path)
1342
+ end
1343
+ unless method_binding.type.return_type == @ctx.types.fetch("bool")
1344
+ raise LoweringError.new("#{context} requires #{target_type}.equal(left: const_ptr[#{target_type}], right: const_ptr[#{target_type}]) -> bool, got #{method_binding.type.return_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
1345
+ end
1346
+ end
1347
+ end
1348
+
1349
+ def resolve_explicit_order_binding(target_type, context:)
1350
+ requirement_message = "#{context} requires associated function #{target_type}.order(left: const_ptr[#{target_type}], right: const_ptr[#{target_type}]) -> int"
1351
+ resolve_explicit_associated_binding(target_type, "order", requirement_message:) do |method_binding, _method_analysis, _method_entry_receiver_type|
1352
+ expected_param_types = [const_pointer_to(target_type), const_pointer_to(target_type)]
1353
+ unless method_binding.type.params.map(&:type) == expected_param_types
1354
+ raise LoweringError.new("#{context} requires #{target_type}.order(left: const_ptr[#{target_type}], right: const_ptr[#{target_type}]) -> int", line: 0, column: 0, path: @ctx.current_analysis_path)
1355
+ end
1356
+ unless method_binding.type.return_type == @ctx.types.fetch("int")
1357
+ raise LoweringError.new("#{context} requires #{target_type}.order(left: const_ptr[#{target_type}], right: const_ptr[#{target_type}]) -> int, got #{method_binding.type.return_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
1358
+ end
1359
+ end
1360
+ end
1461
1361
 
1462
- method_binding = instantiate_function_binding_with_receiver(method_binding, [], receiver_type: target_type) if method_binding.type_params.any?
1463
- yield method_binding, method_analysis, method_entry_receiver_type
1362
+ def resolve_explicit_format_binding(target_type, context:)
1363
+ length_binding = resolve_explicit_format_len_binding(target_type, context:)
1364
+ append_binding = resolve_explicit_format_append_binding(target_type, context:)
1464
1365
 
1465
- callee_name = if method_binding.external
1466
- external_function_c_name(method_binding)
1467
- else
1468
- function_binding_c_name(method_binding, module_name: method_analysis.module_name, receiver_type: method_entry_receiver_type)
1469
- end
1366
+ return ExplicitFormatBinding.new(
1367
+ length_binding: length_binding.fetch(:binding),
1368
+ length_callee_name: length_binding.fetch(:callee_name),
1369
+ append_binding: append_binding.fetch(:binding),
1370
+ append_callee_name: append_binding.fetch(:callee_name),
1371
+ ) if length_binding && append_binding
1470
1372
 
1471
- {
1472
- binding: method_binding,
1473
- callee_name: callee_name,
1474
- }
1373
+ if length_binding || append_binding
1374
+ raise LoweringError.new("#{context} requires methods #{target_type}.format_len() -> ptr_uint and #{target_type}.append_format(output: ref[std.string.String]) -> void", line: 0, column: 0, path: @ctx.current_analysis_path)
1475
1375
  end
1476
1376
 
1477
- def resolve_specialization_type_arguments(expression)
1478
- expression.arguments.map do |argument|
1479
- resolve_type_argument(argument.value)
1377
+ nil
1378
+ end
1379
+
1380
+ def resolve_explicit_format_len_binding(target_type, context:)
1381
+ requirement_message = "#{context} requires method #{target_type}.format_len() -> ptr_uint"
1382
+ resolve_explicit_instance_binding(target_type, "format_len", requirement_message:) do |method_binding, _method_analysis, _method_entry_receiver_type|
1383
+ raise LoweringError.new("#{context} requires #{target_type}.format_len() to take 0 arguments", line: 0, column: 0, path: @ctx.current_analysis_path) unless method_binding.type.params.empty?
1384
+ raise LoweringError.new("#{context} requires #{target_type}.format_len() to be non-editable", line: 0, column: 0, path: @ctx.current_analysis_path) if method_binding.type.receiver_editable
1385
+ unless method_binding.type.return_type == @ctx.types.fetch("ptr_uint")
1386
+ raise LoweringError.new("#{context} requires #{target_type}.format_len() -> ptr_uint, got #{method_binding.type.return_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
1480
1387
  end
1481
1388
  end
1389
+ end
1482
1390
 
1483
- def resolve_type_argument(argument, type_params: current_type_params)
1484
- case argument
1485
- when AST::TypeRef
1486
- resolve_type_argument_ref(argument, type_params:)
1487
- when AST::FunctionType, AST::ProcType
1488
- resolve_type_ref(argument, type_params:)
1489
- when AST::IntegerLiteral, AST::FloatLiteral
1490
- Types::LiteralTypeArg.new(argument.value)
1491
- else
1492
- raise LoweringError.new("unsupported type argument #{argument.class.name}", line: 0, column: 0, path: @ctx.current_analysis_path)
1391
+ def resolve_explicit_format_append_binding(target_type, context:)
1392
+ requirement_message = "#{context} requires method #{target_type}.append_format(output: ref[std.string.String]) -> void"
1393
+ resolve_explicit_instance_binding(target_type, "append_format", requirement_message:) do |method_binding, _method_analysis, _method_entry_receiver_type|
1394
+ raise LoweringError.new("#{context} requires #{target_type}.append_format() to be non-editable", line: 0, column: 0, path: @ctx.current_analysis_path) if method_binding.type.receiver_editable
1395
+ unless method_binding.type.params.length == 1 && string_builder_ref_type?(method_binding.type.params.first.type)
1396
+ raise LoweringError.new("#{context} requires #{target_type}.append_format(output: ref[std.string.String]) -> void", line: 0, column: 0, path: @ctx.current_analysis_path)
1397
+ end
1398
+ unless method_binding.type.return_type == @ctx.types.fetch("void")
1399
+ raise LoweringError.new("#{context} requires #{target_type}.append_format(output: ref[std.string.String]) -> void, got #{method_binding.type.return_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
1493
1400
  end
1494
1401
  end
1402
+ end
1495
1403
 
1496
- def resolve_type_argument_ref(type_ref, type_params:)
1497
- return resolve_type_ref(type_ref, type_params:) unless literal_type_argument_name_candidate?(type_ref)
1498
-
1499
- resolve_type_ref(type_ref, type_params:)
1500
- rescue LoweringError => error
1501
- literal_type_argument = resolve_named_literal_type_argument(type_ref)
1502
- return literal_type_argument if literal_type_argument
1404
+ def method_analysis_key(method_ast)
1405
+ method_ast.kind == :static ? "static:#{method_ast.name}" : method_ast.name
1406
+ end
1503
1407
 
1504
- raise error
1408
+ def resolve_explicit_associated_binding(target_type, method_name, requirement_message:)
1409
+ dispatch_receiver_type = method_dispatch_receiver_type(target_type)
1410
+ method_entry_receiver_type = target_type
1411
+ static_method_name = "static:#{method_name}"
1412
+ method_entry = @method_definitions[[target_type, static_method_name]]
1413
+ unless method_entry || dispatch_receiver_type == target_type
1414
+ method_entry_receiver_type = dispatch_receiver_type
1415
+ method_entry = @method_definitions[[dispatch_receiver_type, static_method_name]]
1505
1416
  end
1417
+ return nil unless method_entry
1506
1418
 
1507
- def literal_type_argument_name_candidate?(type_ref)
1508
- type_ref.arguments.empty? && !type_ref.nullable
1509
- end
1419
+ method_analysis, method_ast = method_entry
1420
+ method_binding = method_analysis.methods.fetch(method_entry_receiver_type).fetch(method_analysis_key(method_ast))
1421
+ raise LoweringError.new(requirement_message, line: 0, column: 0, path: @ctx.current_analysis_path) unless method_binding.type.receiver_type.nil?
1510
1422
 
1511
- def resolve_named_literal_type_argument(type_ref)
1512
- value = case type_ref.name.parts.length
1513
- when 1
1514
- resolve_current_module_const_value(type_ref.name.parts.first)
1515
- when 2
1516
- resolve_imported_module_const_value(type_ref.name.parts.first, type_ref.name.parts.last)
1517
- end
1423
+ method_binding = instantiate_function_binding_with_receiver(method_binding, [], receiver_type: target_type) if method_binding.type_params.any?
1424
+ yield method_binding, method_analysis, method_entry_receiver_type
1425
+
1426
+ callee_name = if method_binding.external
1427
+ external_function_c_name(method_binding)
1428
+ else
1429
+ function_binding_c_name(method_binding, module_name: method_analysis.module_name, receiver_type: method_entry_receiver_type)
1430
+ end
1518
1431
 
1519
- return unless value.is_a?(Integer) || value.is_a?(Float)
1432
+ case method_name
1433
+ when "default"
1434
+ ExplicitDefaultBinding.new(binding: method_binding, callee_name:)
1435
+ when "hash"
1436
+ ExplicitHashBinding.new(binding: method_binding, callee_name:)
1437
+ when "equal"
1438
+ ExplicitEqualBinding.new(binding: method_binding, callee_name:)
1439
+ when "order"
1440
+ ExplicitOrderBinding.new(binding: method_binding, callee_name:)
1441
+ else
1442
+ raise LoweringError.new("unsupported associated hook #{method_name}", line: 0, column: 0, path: @ctx.current_analysis_path)
1443
+ end
1444
+ end
1445
+
1446
+ def resolve_explicit_instance_binding(target_type, method_name, requirement_message:)
1447
+ dispatch_receiver_type = method_dispatch_receiver_type(target_type)
1448
+ method_entry_receiver_type = target_type
1449
+ method_entry = @method_definitions[[target_type, method_name]]
1450
+ unless method_entry || dispatch_receiver_type == target_type
1451
+ method_entry_receiver_type = dispatch_receiver_type
1452
+ method_entry = @method_definitions[[dispatch_receiver_type, method_name]]
1453
+ end
1454
+ return nil unless method_entry
1455
+
1456
+ method_analysis, method_ast = method_entry
1457
+ method_binding = method_analysis.methods.fetch(method_entry_receiver_type).fetch(method_analysis_key(method_ast))
1458
+ raise LoweringError.new(requirement_message, line: 0, column: 0, path: @ctx.current_analysis_path) if method_binding.type.receiver_type.nil?
1459
+
1460
+ method_binding = instantiate_function_binding_with_receiver(method_binding, [], receiver_type: target_type) if method_binding.type_params.any?
1461
+ yield method_binding, method_analysis, method_entry_receiver_type
1462
+
1463
+ callee_name = if method_binding.external
1464
+ external_function_c_name(method_binding)
1465
+ else
1466
+ function_binding_c_name(method_binding, module_name: method_analysis.module_name, receiver_type: method_entry_receiver_type)
1467
+ end
1520
1468
 
1521
- Types::LiteralTypeArg.new(value)
1522
- end
1469
+ {
1470
+ binding: method_binding,
1471
+ callee_name: callee_name,
1472
+ }
1473
+ end
1474
+
1475
+ def resolve_specialization_type_arguments(expression)
1476
+ expression.arguments.map do |argument|
1477
+ resolve_type_argument(argument.value)
1478
+ end
1479
+ end
1480
+
1481
+ def resolve_type_argument(argument, type_params: current_type_params)
1482
+ case argument
1483
+ when AST::TypeRef
1484
+ resolve_type_argument_ref(argument, type_params:)
1485
+ when AST::FunctionType, AST::ProcType
1486
+ resolve_type_ref(argument, type_params:)
1487
+ when AST::IntegerLiteral, AST::FloatLiteral
1488
+ Types::LiteralTypeArg.new(argument.value)
1489
+ else
1490
+ raise LoweringError.new("unsupported type argument #{argument.class.name}", line: 0, column: 0, path: @ctx.current_analysis_path)
1491
+ end
1492
+ end
1493
+
1494
+ def resolve_type_argument_ref(type_ref, type_params:)
1495
+ return resolve_type_ref(type_ref, type_params:) unless literal_type_argument_name_candidate?(type_ref)
1496
+
1497
+ resolve_type_ref(type_ref, type_params:)
1498
+ rescue LoweringError => error
1499
+ literal_type_argument = resolve_named_literal_type_argument(type_ref)
1500
+ return literal_type_argument if literal_type_argument
1501
+
1502
+ raise error
1503
+ end
1504
+
1505
+ def literal_type_argument_name_candidate?(type_ref)
1506
+ type_ref.arguments.empty? && !type_ref.nullable
1507
+ end
1508
+
1509
+ def resolve_named_literal_type_argument(type_ref)
1510
+ value = case type_ref.name.parts.length
1511
+ when 1
1512
+ resolve_current_module_const_value(type_ref.name.parts.first)
1513
+ when 2
1514
+ resolve_imported_module_const_value(type_ref.name.parts.first, type_ref.name.parts.last)
1515
+ end
1523
1516
 
1524
- def resolve_current_module_const_value(name)
1525
- binding = @ctx.values[name]
1526
- return unless binding&.kind == :const
1517
+ return unless value.is_a?(Integer) || value.is_a?(Float)
1527
1518
 
1528
- binding.const_value
1529
- end
1519
+ Types::LiteralTypeArg.new(value)
1520
+ end
1530
1521
 
1531
- def resolve_imported_module_const_value(import_name, value_name)
1532
- imported_module = @ctx.imports[import_name]
1533
- return unless imported_module
1534
- if imported_module.private_value?(value_name)
1535
- raise LoweringError.new("#{import_name}.#{value_name} is private to module #{imported_module.name}", line: 0, column: 0, path: @ctx.current_analysis_path)
1536
- end
1522
+ def resolve_current_module_const_value(name)
1523
+ binding = @ctx.values[name]
1524
+ return unless binding&.kind == :const
1537
1525
 
1538
- binding = imported_module.values[value_name]
1539
- return unless binding&.kind == :const
1526
+ binding.const_value
1527
+ end
1540
1528
 
1541
- binding.const_value
1529
+ def resolve_imported_module_const_value(import_name, value_name)
1530
+ imported_module = @ctx.imports[import_name]
1531
+ return unless imported_module
1532
+ if imported_module.private_value?(value_name)
1533
+ raise LoweringError.new("#{import_name}.#{value_name} is private to module #{imported_module.name}", line: 0, column: 0, path: @ctx.current_analysis_path)
1542
1534
  end
1543
1535
 
1544
- def resolve_type_member_const_value(expression)
1545
- type = resolve_type_expression(expression.receiver)
1546
- return unless type.is_a?(Types::EnumBase)
1536
+ binding = imported_module.values[value_name]
1537
+ return unless binding&.kind == :const
1547
1538
 
1548
- type.member_value(expression.member)
1549
- end
1539
+ binding.const_value
1540
+ end
1550
1541
 
1551
- def compile_time_numeric_const_expression?(expression, env: nil)
1552
- value = compile_time_const_value(expression, env:)
1553
- value.is_a?(Integer) || value.is_a?(Float)
1554
- end
1542
+ def resolve_type_member_const_value(expression)
1543
+ type = resolve_type_expression(expression.receiver)
1544
+ return unless type.is_a?(Types::EnumBase)
1555
1545
 
1556
- def compile_time_const_value(expression, env: nil)
1557
- CompileTime.evaluate(
1558
- expression,
1559
- resolve_identifier: lambda do |identifier_expression|
1560
- if env
1561
- binding = lookup_value(identifier_expression.name, env)
1562
- return binding[:const_value] unless binding&.fetch(:const_value, nil).nil?
1563
- end
1546
+ type.member_value(expression.member)
1547
+ end
1564
1548
 
1565
- value = resolve_current_module_const_value(identifier_expression.name)
1566
- return value if value
1567
-
1568
- # Resolve a bare type-parameter name (e.g. `T`) to its substituted
1569
- # concrete type so `inline if T == int` folds during lowering too.
1570
- current_type_params[identifier_expression.name] || @ctx.types[identifier_expression.name]
1571
- end,
1572
- resolve_member_access: lambda do |member_access_expression|
1573
- if (receiver_value = CompileTime.evaluate(
1574
- member_access_expression.receiver,
1575
- resolve_identifier: lambda do |identifier_expression|
1576
- if env
1577
- binding = lookup_value(identifier_expression.name, env)
1578
- return binding[:const_value] unless binding&.fetch(:const_value, nil).nil?
1579
- end
1580
- resolve_current_module_const_value(identifier_expression.name)
1581
- end,
1582
- resolve_member_access: lambda { |ma| nil },
1583
- resolve_type_ref: lambda { |tr| resolve_type_ref(tr) },
1584
- resolve_call: lambda { |ce| evaluate_compile_time_call(ce, env:) },
1585
- ))
1586
- case receiver_value
1587
- when Types::FieldHandle
1588
- case member_access_expression.member
1589
- when "name" then next receiver_value.field_name
1590
- when "type" then next receiver_value.struct_handle.struct_type.field(receiver_value.field_name)
1591
- end
1592
- when Types::MemberHandle
1593
- case member_access_expression.member
1594
- when "name" then next receiver_value.member_name
1595
- when "value" then next receiver_value.member_value
1596
- end
1549
+ def compile_time_numeric_const_expression?(expression, env: nil)
1550
+ value = compile_time_const_value(expression, env:)
1551
+ value.is_a?(Integer) || value.is_a?(Float)
1552
+ end
1553
+
1554
+ def compile_time_const_value(expression, env: nil)
1555
+ CompileTime.evaluate(
1556
+ expression,
1557
+ resolve_identifier: lambda do |identifier_expression|
1558
+ if env
1559
+ binding = lookup_value(identifier_expression.name, env)
1560
+ return binding[:const_value] unless binding&.fetch(:const_value, nil).nil?
1561
+ end
1562
+
1563
+ value = resolve_current_module_const_value(identifier_expression.name)
1564
+ return value if value
1565
+
1566
+ # Resolve a bare type-parameter name (e.g. `T`) to its substituted
1567
+ # concrete type so `inline if T == int` folds during lowering too.
1568
+ current_type_params[identifier_expression.name] || @ctx.types[identifier_expression.name]
1569
+ end,
1570
+ resolve_member_access: lambda do |member_access_expression|
1571
+ if (receiver_value = CompileTime.evaluate(
1572
+ member_access_expression.receiver,
1573
+ resolve_identifier: lambda do |identifier_expression|
1574
+ if env
1575
+ binding = lookup_value(identifier_expression.name, env)
1576
+ return binding[:const_value] unless binding&.fetch(:const_value, nil).nil?
1577
+ end
1578
+ resolve_current_module_const_value(identifier_expression.name)
1579
+ end,
1580
+ resolve_member_access: lambda { |ma| nil },
1581
+ resolve_type_ref: lambda { |tr| resolve_type_ref(tr) },
1582
+ resolve_call: lambda { |ce| evaluate_compile_time_call(ce, env:) },
1583
+ ))
1584
+ case receiver_value
1585
+ when Types::FieldHandle
1586
+ case member_access_expression.member
1587
+ when "name" then next receiver_value.field_name
1588
+ when "type" then next receiver_value.struct_handle.struct_type.field(receiver_value.field_name)
1589
+ end
1590
+ when Types::MemberHandle
1591
+ case member_access_expression.member
1592
+ when "name" then next receiver_value.member_name
1593
+ when "value" then next receiver_value.member_value
1597
1594
  end
1598
1595
  end
1596
+ end
1599
1597
 
1600
- value = if member_access_expression.receiver.is_a?(AST::Identifier)
1601
- resolve_imported_module_const_value(member_access_expression.receiver.name, member_access_expression.member)
1602
- end
1603
- next value unless value.nil?
1604
-
1605
- resolve_type_member_const_value(member_access_expression)
1606
- end,
1607
- resolve_type_ref: lambda do |type_ref|
1608
- resolve_type_ref(type_ref)
1609
- end,
1610
- resolve_call: lambda do |call_expression|
1611
- evaluate_compile_time_call(call_expression, env:)
1612
- end,
1613
- )
1614
- end
1598
+ value = if member_access_expression.receiver.is_a?(AST::Identifier)
1599
+ resolve_imported_module_const_value(member_access_expression.receiver.name, member_access_expression.member)
1600
+ end
1601
+ next value unless value.nil?
1615
1602
 
1616
- def evaluate_compile_time_call(expression, env:)
1617
- case expression.callee
1618
- when AST::Identifier
1619
- case expression.callee.name
1620
- when "field_of"
1621
- evaluate_field_of_call(expression.arguments, env:)
1622
- when "fields_of"
1623
- evaluate_fields_of_call(expression.arguments, env:)
1624
- when "callable_of"
1625
- evaluate_callable_of_call(expression.arguments)
1626
- when "has_attribute"
1627
- evaluate_has_attribute_call(expression.arguments, env:)
1628
- when "attribute_of"
1629
- evaluate_attribute_of_call(expression.arguments, env:)
1630
- when "members_of"
1631
- evaluate_members_of_call(expression.arguments, env:)
1632
- when "attributes_of"
1633
- evaluate_attributes_of_call(expression.arguments, env:)
1603
+ resolve_type_member_const_value(member_access_expression)
1604
+ end,
1605
+ resolve_type_ref: lambda do |type_ref|
1606
+ resolve_type_ref(type_ref)
1607
+ end,
1608
+ resolve_call: lambda do |call_expression|
1609
+ evaluate_compile_time_call(call_expression, env:)
1610
+ end,
1611
+ )
1612
+ end
1613
+
1614
+ def evaluate_compile_time_call(expression, env:)
1615
+ case expression.callee
1616
+ when AST::Identifier
1617
+ case expression.callee.name
1618
+ when "field_of"
1619
+ evaluate_field_of_call(expression.arguments, env:)
1620
+ when "fields_of"
1621
+ evaluate_fields_of_call(expression.arguments, env:)
1622
+ when "callable_of"
1623
+ evaluate_callable_of_call(expression.arguments)
1624
+ when "has_attribute"
1625
+ evaluate_has_attribute_call(expression.arguments, env:)
1626
+ when "attribute_of"
1627
+ evaluate_attribute_of_call(expression.arguments, env:)
1628
+ when "members_of"
1629
+ evaluate_members_of_call(expression.arguments, env:)
1630
+ when "attributes_of"
1631
+ evaluate_attributes_of_call(expression.arguments, env:)
1632
+ else
1633
+ func = @ctx.functions[expression.callee.name]
1634
+ if func&.ast&.respond_to?(:const) && func.ast.const
1635
+ evaluate_const_function_body_lower(func, expression.arguments)
1634
1636
  else
1635
- func = @ctx.functions[expression.callee.name]
1637
+ evaluate_type_returning_call(expression, env:)
1638
+ end
1639
+ end
1640
+ when AST::Specialization
1641
+ if expression.callee.callee.is_a?(AST::Identifier) && expression.callee.callee.name == "attribute_arg"
1642
+ evaluate_attribute_arg_call(expression.arguments, env:)
1643
+ else
1644
+ callee_name = expression.callee.callee.is_a?(AST::Identifier) ? expression.callee.callee.name : nil
1645
+ if callee_name
1646
+ func = @ctx.functions[callee_name]
1636
1647
  if func&.ast&.respond_to?(:const) && func.ast.const
1637
1648
  evaluate_const_function_body_lower(func, expression.arguments)
1638
1649
  else
1639
1650
  evaluate_type_returning_call(expression, env:)
1640
1651
  end
1641
- end
1642
- when AST::Specialization
1643
- if expression.callee.callee.is_a?(AST::Identifier) && expression.callee.callee.name == "attribute_arg"
1644
- evaluate_attribute_arg_call(expression.arguments, env:)
1645
1652
  else
1646
- callee_name = expression.callee.callee.is_a?(AST::Identifier) ? expression.callee.callee.name : nil
1647
- if callee_name
1648
- func = @ctx.functions[callee_name]
1649
- if func&.ast&.respond_to?(:const) && func.ast.const
1650
- evaluate_const_function_body_lower(func, expression.arguments)
1651
- else
1652
- evaluate_type_returning_call(expression, env:)
1653
- end
1654
- else
1655
- evaluate_type_returning_call(expression, env:)
1656
- end
1653
+ evaluate_type_returning_call(expression, env:)
1657
1654
  end
1658
1655
  end
1659
1656
  end
1657
+ end
1660
1658
 
1661
- def evaluate_type_returning_call(expression, env:)
1662
- callee_name, type_args = extract_type_callee_info(expression)
1663
- return nil unless callee_name
1659
+ def evaluate_type_returning_call(expression, env:)
1660
+ callee_name, type_args = extract_type_callee_info(expression)
1661
+ return nil unless callee_name
1664
1662
 
1665
- CompileTime::Reflection.core_evaluate_type_returning(
1666
- callee_name, type_args,
1667
- evaluate_value: ->(v) { compile_time_const_value(v, env:) },
1668
- resolve_type_ref: ->(tr) { resolve_type_ref(tr) },
1669
- pointer_to: ->(t) { pointer_to(t) },
1670
- const_pointer_to: ->(t) { const_pointer_to(t) },
1671
- top_level_functions: ->(name) { nil },
1672
- evaluate_type_returning_function_body: nil,
1673
- )
1674
- end
1663
+ CompileTime::Reflection.core_evaluate_type_returning(
1664
+ callee_name, type_args,
1665
+ evaluate_value: ->(v) { compile_time_const_value(v, env:) },
1666
+ resolve_type_ref: ->(tr) { resolve_type_ref(tr) },
1667
+ pointer_to: ->(t) { pointer_to(t) },
1668
+ const_pointer_to: ->(t) { const_pointer_to(t) },
1669
+ top_level_functions: ->(name) { nil },
1670
+ evaluate_type_returning_function_body: nil,
1671
+ )
1672
+ end
1675
1673
 
1676
- def extract_type_callee_info(expression)
1677
- if expression.is_a?(AST::Call) && expression.callee.is_a?(AST::Identifier)
1678
- [expression.callee.name, nil]
1679
- elsif expression.is_a?(AST::Specialization)
1680
- if expression.callee.is_a?(AST::Identifier)
1681
- [expression.callee.name, expression.arguments]
1682
- elsif expression.callee.is_a?(AST::Specialization) && expression.callee.callee.is_a?(AST::Identifier)
1683
- [expression.callee.callee.name, expression.callee.arguments]
1684
- end
1674
+ def extract_type_callee_info(expression)
1675
+ if expression.is_a?(AST::Call) && expression.callee.is_a?(AST::Identifier)
1676
+ [expression.callee.name, nil]
1677
+ elsif expression.is_a?(AST::Specialization)
1678
+ if expression.callee.is_a?(AST::Identifier)
1679
+ [expression.callee.name, expression.arguments]
1680
+ elsif expression.callee.is_a?(AST::Specialization) && expression.callee.callee.is_a?(AST::Identifier)
1681
+ [expression.callee.callee.name, expression.callee.arguments]
1685
1682
  end
1686
1683
  end
1684
+ end
1687
1685
 
1688
- def evaluate_field_of_call(arguments, env:)
1689
- return nil unless reflection_positional_arguments?(arguments, 2)
1686
+ def evaluate_field_of_call(arguments, env:)
1687
+ return nil unless reflection_positional_arguments?(arguments, 2)
1690
1688
 
1691
- struct_handle = resolve_struct_handle_argument(arguments.first.value, env:)
1692
- return nil unless struct_handle
1689
+ struct_handle = resolve_struct_handle_argument(arguments.first.value, env:)
1690
+ return nil unless struct_handle
1693
1691
 
1694
- field_name = reflection_identifier_name(arguments[1].value)
1695
- return nil unless field_name
1692
+ field_name = reflection_identifier_name(arguments[1].value)
1693
+ return nil unless field_name
1696
1694
 
1697
- CompileTime::Reflection.core_field_handle(struct_handle, field_name)
1698
- end
1695
+ CompileTime::Reflection.core_field_handle(struct_handle, field_name)
1696
+ end
1699
1697
 
1700
- def evaluate_fields_of_call(arguments, env:)
1701
- return nil unless reflection_positional_arguments?(arguments, 1)
1698
+ def evaluate_fields_of_call(arguments, env:)
1699
+ return nil unless reflection_positional_arguments?(arguments, 1)
1702
1700
 
1703
- struct_handle = resolve_struct_handle_argument(arguments.first.value, env:)
1704
- return nil unless struct_handle
1701
+ struct_handle = resolve_struct_handle_argument(arguments.first.value, env:)
1702
+ return nil unless struct_handle
1705
1703
 
1706
- CompileTime::Reflection.core_field_handles(struct_handle)
1707
- end
1704
+ CompileTime::Reflection.core_field_handles(struct_handle)
1705
+ end
1708
1706
 
1709
- def evaluate_members_of_call(arguments, env:)
1710
- return nil unless reflection_positional_arguments?(arguments, 1)
1707
+ def evaluate_members_of_call(arguments, env:)
1708
+ return nil unless reflection_positional_arguments?(arguments, 1)
1711
1709
 
1712
- type = resolve_type_expression(arguments.first.value)
1713
- return nil unless type
1710
+ type = resolve_type_expression(arguments.first.value)
1711
+ return nil unless type
1714
1712
 
1715
- return nil unless type.is_a?(Types::Enum) || type.is_a?(Types::Flags)
1713
+ return nil unless type.is_a?(Types::Enum) || type.is_a?(Types::Flags)
1716
1714
 
1717
- CompileTime::Reflection.core_member_handles(type)
1718
- end
1715
+ CompileTime::Reflection.core_member_handles(type)
1716
+ end
1719
1717
 
1720
- def evaluate_attributes_of_call(arguments, env:)
1721
- return nil unless reflection_positional_arguments?(arguments, 1) || reflection_positional_arguments?(arguments, 2)
1718
+ def evaluate_attributes_of_call(arguments, env:)
1719
+ return nil unless reflection_positional_arguments?(arguments, 1) || reflection_positional_arguments?(arguments, 2)
1722
1720
 
1723
- target = evaluate_reflection_target_argument(arguments.first.value, env:)
1724
- return nil unless target
1721
+ target = evaluate_reflection_target_argument(arguments.first.value, env:)
1722
+ return nil unless target
1725
1723
 
1726
- if arguments.length == 2
1727
- attribute_binding = resolve_attribute_name_argument(arguments[1].value)
1728
- application = find_attribute_application(target, attribute_binding)
1729
- return [] unless application
1724
+ if arguments.length == 2
1725
+ attribute_binding = resolve_attribute_name_argument(arguments[1].value)
1726
+ application = find_attribute_application(target, attribute_binding)
1727
+ return [] unless application
1730
1728
 
1731
- [Types::AttributeHandle.new(
1732
- attribute_binding.name,
1733
- attribute_binding.module_name,
1729
+ [Types::AttributeHandle.new(
1730
+ attribute_binding.name,
1731
+ attribute_binding.module_name,
1732
+ target,
1733
+ attribute_binding.params,
1734
+ application.argument_values,
1735
+ )]
1736
+ else
1737
+ resolved_attribute_applications_for_target(target).map do |application|
1738
+ Types::AttributeHandle.new(
1739
+ application.binding.name,
1740
+ application.binding.module_name,
1734
1741
  target,
1735
- attribute_binding.params,
1742
+ application.binding.params,
1736
1743
  application.argument_values,
1737
- )]
1738
- else
1739
- resolved_attribute_applications_for_target(target).map do |application|
1740
- Types::AttributeHandle.new(
1741
- application.binding.name,
1742
- application.binding.module_name,
1743
- target,
1744
- application.binding.params,
1745
- application.argument_values,
1746
- )
1747
- end
1744
+ )
1748
1745
  end
1749
1746
  end
1747
+ end
1750
1748
 
1751
- def evaluate_callable_of_call(arguments)
1752
- return nil unless reflection_positional_arguments?(arguments, 1)
1753
-
1754
- resolve_callable_handle_argument(arguments.first.value)
1755
- end
1749
+ def evaluate_callable_of_call(arguments)
1750
+ return nil unless reflection_positional_arguments?(arguments, 1)
1756
1751
 
1757
- def evaluate_has_attribute_call(arguments, env:)
1758
- return nil unless reflection_positional_arguments?(arguments, 2)
1752
+ resolve_callable_handle_argument(arguments.first.value)
1753
+ end
1759
1754
 
1760
- target = evaluate_reflection_target_argument(arguments.first.value, env:)
1761
- binding = resolve_attribute_name_argument(arguments[1].value)
1762
- return nil unless attribute_binding_supports_target?(binding, target)
1755
+ def evaluate_has_attribute_call(arguments, env:)
1756
+ return nil unless reflection_positional_arguments?(arguments, 2)
1763
1757
 
1764
- !find_attribute_application(target, binding).nil?
1765
- end
1758
+ target = evaluate_reflection_target_argument(arguments.first.value, env:)
1759
+ binding = resolve_attribute_name_argument(arguments[1].value)
1760
+ return nil unless attribute_binding_supports_target?(binding, target)
1766
1761
 
1767
- def evaluate_attribute_of_call(arguments, env:)
1768
- return nil unless reflection_positional_arguments?(arguments, 2)
1762
+ !find_attribute_application(target, binding).nil?
1763
+ end
1769
1764
 
1770
- target = evaluate_reflection_target_argument(arguments.first.value, env:)
1771
- binding = resolve_attribute_name_argument(arguments[1].value)
1772
- return nil unless attribute_binding_supports_target?(binding, target)
1765
+ def evaluate_attribute_of_call(arguments, env:)
1766
+ return nil unless reflection_positional_arguments?(arguments, 2)
1773
1767
 
1774
- application = find_attribute_application(target, binding)
1775
- return nil unless application
1768
+ target = evaluate_reflection_target_argument(arguments.first.value, env:)
1769
+ binding = resolve_attribute_name_argument(arguments[1].value)
1770
+ return nil unless attribute_binding_supports_target?(binding, target)
1776
1771
 
1777
- Types::AttributeHandle.new(
1778
- binding.name,
1779
- binding.module_name,
1780
- target,
1781
- binding.params,
1782
- application.argument_values,
1783
- )
1784
- end
1772
+ application = find_attribute_application(target, binding)
1773
+ return nil unless application
1785
1774
 
1786
- def evaluate_attribute_arg_call(arguments, env:)
1787
- return nil unless reflection_positional_arguments?(arguments, 2)
1775
+ Types::AttributeHandle.new(
1776
+ binding.name,
1777
+ binding.module_name,
1778
+ target,
1779
+ binding.params,
1780
+ application.argument_values,
1781
+ )
1782
+ end
1788
1783
 
1789
- attribute_handle = compile_time_const_value(arguments.first.value, env:)
1790
- return nil unless attribute_handle.is_a?(Types::AttributeHandle)
1784
+ def evaluate_attribute_arg_call(arguments, env:)
1785
+ return nil unless reflection_positional_arguments?(arguments, 2)
1791
1786
 
1792
- param_name = reflection_identifier_name(arguments[1].value)
1793
- return nil unless param_name && attribute_handle.argument_values
1787
+ attribute_handle = compile_time_const_value(arguments.first.value, env:)
1788
+ return nil unless attribute_handle.is_a?(Types::AttributeHandle)
1794
1789
 
1795
- attribute_handle.argument_values[param_name]
1796
- end
1790
+ param_name = reflection_identifier_name(arguments[1].value)
1791
+ return nil unless param_name && attribute_handle.argument_values
1797
1792
 
1798
- def evaluate_const_function_body_lower(func, arguments)
1799
- return nil unless func.ast.params.length == arguments.length
1793
+ attribute_handle.argument_values[param_name]
1794
+ end
1800
1795
 
1801
- initial_vars = {}
1802
- func.ast.params.each_with_index do |param, idx|
1803
- arg_expr = arguments[idx].value
1804
- arg_value = compile_time_const_value(arg_expr, env: empty_env)
1805
- return nil unless arg_value
1796
+ def evaluate_const_function_body_lower(func, arguments)
1797
+ return nil unless func.ast.params.length == arguments.length
1806
1798
 
1807
- initial_vars[param.name] = arg_value
1808
- end
1799
+ initial_vars = {}
1800
+ func.ast.params.each_with_index do |param, idx|
1801
+ arg_expr = arguments[idx].value
1802
+ arg_value = compile_time_const_value(arg_expr, env: empty_env)
1803
+ return nil unless arg_value
1809
1804
 
1810
- evaluator = ConstFnLowerEvaluator.new(self)
1811
- ctx = CompileTime::BlockContext.new(evaluator, initial_variables: initial_vars)
1812
- ctx.evaluate_block(func.ast.body, scopes: nil)
1813
- rescue CompileTime::ReturnValue => e
1814
- e.value
1805
+ initial_vars[param.name] = arg_value
1815
1806
  end
1816
1807
 
1817
- class ConstFnLowerEvaluator
1818
- def initialize(lowerer)
1819
- @lowerer = lowerer
1820
- end
1821
-
1822
- def types
1823
- @lowerer.instance_variable_get(:@ctx).types
1824
- end
1825
-
1826
- def evaluate_compile_time_const_value(expression, scopes: nil)
1827
- @lowerer.send(:compile_time_const_value, expression, env: @lowerer.send(:empty_env))
1828
- end
1829
-
1830
- def top_level_function(name)
1831
- @lowerer.instance_variable_get(:@ctx).functions&.[](name)
1832
- end
1808
+ evaluator = ConstFnLowerEvaluator.new(self)
1809
+ ctx = CompileTime::BlockContext.new(evaluator, initial_variables: initial_vars)
1810
+ ctx.evaluate_block(func.ast.body, scopes: nil)
1811
+ rescue CompileTime::ReturnValue => e
1812
+ e.value
1813
+ end
1833
1814
 
1834
- def raise_sema_error(message)
1835
- raise CompileTime::Error, message
1836
- end
1815
+ class ConstFnLowerEvaluator
1816
+ def initialize(lowerer)
1817
+ @lowerer = lowerer
1837
1818
  end
1838
1819
 
1839
- def evaluate_reflection_target_argument(expression, env:)
1840
- struct_handle = resolve_struct_handle_argument(expression, env:)
1841
- return struct_handle if struct_handle
1820
+ def types
1821
+ @lowerer.instance_variable_get(:@ctx).types
1822
+ end
1842
1823
 
1843
- value = compile_time_const_value(expression, env:)
1844
- return value if value.is_a?(Types::FieldHandle) || value.is_a?(Types::CallableHandle)
1824
+ def evaluate_compile_time_const_value(expression, scopes: nil)
1825
+ @lowerer.compile_time_const_value(expression, env: @lowerer.empty_env)
1826
+ end
1845
1827
 
1846
- nil
1828
+ def top_level_function(name)
1829
+ @lowerer.instance_variable_get(:@ctx).functions&.[](name)
1847
1830
  end
1848
1831
 
1849
- def reflection_positional_arguments?(arguments, expected_length)
1850
- arguments.length == expected_length && arguments.none?(&:name)
1832
+ def raise_sema_error(message)
1833
+ raise CompileTime::Error, message
1851
1834
  end
1835
+ end
1852
1836
 
1853
- def resolve_struct_handle_argument(expression, env:)
1854
- type = reflection_type_from_expression(expression, env:)
1855
- return nil unless type
1837
+ def evaluate_reflection_target_argument(expression, env:)
1838
+ struct_handle = resolve_struct_handle_argument(expression, env:)
1839
+ return struct_handle if struct_handle
1856
1840
 
1857
- struct_handle_for_type(type)
1858
- end
1841
+ value = compile_time_const_value(expression, env:)
1842
+ return value if value.is_a?(Types::FieldHandle) || value.is_a?(Types::CallableHandle)
1859
1843
 
1860
- def reflection_type_from_expression(expression, env:)
1861
- case expression
1862
- when AST::Identifier
1863
- return nil if env && lookup_value(expression.name, env)
1844
+ nil
1845
+ end
1864
1846
 
1865
- current_type_params[expression.name] || @ctx.types[expression.name]
1866
- when AST::MemberAccess
1867
- return nil unless expression.receiver.is_a?(AST::Identifier)
1847
+ def reflection_positional_arguments?(arguments, expected_length)
1848
+ arguments.length == expected_length && arguments.none?(&:name)
1849
+ end
1868
1850
 
1869
- if @ctx.imports.key?(expression.receiver.name)
1870
- imported_module = @ctx.imports[expression.receiver.name]
1871
- return nil if imported_module.private_type?(expression.member)
1872
- return imported_module.types[expression.member]
1873
- end
1851
+ def resolve_struct_handle_argument(expression, env:)
1852
+ type = reflection_type_from_expression(expression, env:)
1853
+ return nil unless type
1874
1854
 
1875
- parent_type = @ctx.types[expression.receiver.name]
1876
- return parent_type.nested_types[expression.member] if parent_type.respond_to?(:nested_types) && parent_type.nested_types.key?(expression.member)
1855
+ struct_handle_for_type(type)
1856
+ end
1877
1857
 
1878
- nil
1879
- else
1880
- nil
1858
+ def reflection_type_from_expression(expression, env:)
1859
+ case expression
1860
+ when AST::Identifier
1861
+ return nil if env && lookup_value(expression.name, env)
1862
+
1863
+ current_type_params[expression.name] || @ctx.types[expression.name]
1864
+ when AST::MemberAccess
1865
+ return nil unless expression.receiver.is_a?(AST::Identifier)
1866
+
1867
+ if @ctx.imports.key?(expression.receiver.name)
1868
+ imported_module = @ctx.imports[expression.receiver.name]
1869
+ return nil if imported_module.private_type?(expression.member)
1870
+ return imported_module.types[expression.member]
1881
1871
  end
1872
+
1873
+ parent_type = @ctx.types[expression.receiver.name]
1874
+ return parent_type.nested_types[expression.member] if parent_type.respond_to?(:nested_types) && parent_type.nested_types.key?(expression.member)
1875
+
1876
+ nil
1877
+ else
1878
+ nil
1882
1879
  end
1880
+ end
1883
1881
 
1884
- def struct_handle_for_type(type)
1885
- base_type = type.is_a?(Types::StructInstance) ? type.definition : type
1886
- return nil unless base_type.is_a?(Types::Struct) || base_type.is_a?(Types::GenericStructDefinition)
1887
- return nil unless base_type.respond_to?(:module_name)
1882
+ def struct_handle_for_type(type)
1883
+ base_type = type.is_a?(Types::StructInstance) ? type.definition : type
1884
+ return nil unless base_type.is_a?(Types::Struct) || base_type.is_a?(Types::GenericStructDefinition)
1885
+ return nil unless base_type.respond_to?(:module_name)
1888
1886
 
1889
- analysis = analysis_for_module(base_type.module_name)
1890
- declaration = find_struct_decl_by_name(analysis.ast.declarations, base_type.name)
1891
- return nil unless declaration
1887
+ analysis = analysis_for_module(base_type.module_name)
1888
+ declaration = find_struct_decl_by_name(analysis.ast.declarations, base_type.name)
1889
+ return nil unless declaration
1892
1890
 
1893
- Types::StructHandle.new(base_type, declaration)
1894
- end
1891
+ Types::StructHandle.new(base_type, declaration)
1892
+ end
1895
1893
 
1896
- def find_struct_decl_by_name(declarations, name)
1897
- declarations.each do |decl|
1898
- next unless decl.is_a?(AST::StructDecl)
1899
- return decl if decl.name == name
1900
- if decl.nested_types&.any?
1901
- found = find_struct_decl_by_name(decl.nested_types, name)
1902
- return found if found
1903
- end
1894
+ def find_struct_decl_by_name(declarations, name)
1895
+ declarations.each do |decl|
1896
+ next unless decl.is_a?(AST::StructDecl)
1897
+ return decl if decl.name == name
1898
+ if decl.nested_types&.any?
1899
+ found = find_struct_decl_by_name(decl.nested_types, name)
1900
+ return found if found
1904
1901
  end
1905
- nil
1906
1902
  end
1903
+ nil
1904
+ end
1907
1905
 
1908
- def resolve_callable_handle_argument(expression)
1909
- case expression
1910
- when AST::Identifier
1911
- binding = @ctx.functions[expression.name]
1912
- return nil unless binding&.ast
1906
+ def resolve_callable_handle_argument(expression)
1907
+ case expression
1908
+ when AST::Identifier
1909
+ binding = @ctx.functions[expression.name]
1910
+ return nil unless binding&.ast
1913
1911
 
1914
- Types::CallableHandle.new(expression.name, binding.ast)
1915
- when AST::MemberAccess
1916
- return nil unless expression.receiver.is_a?(AST::Identifier)
1912
+ Types::CallableHandle.new(expression.name, binding.ast)
1913
+ when AST::MemberAccess
1914
+ return nil unless expression.receiver.is_a?(AST::Identifier)
1917
1915
 
1918
- imported_module = @ctx.imports[expression.receiver.name]
1919
- return nil unless imported_module
1920
- return nil if imported_module.private_function?(expression.member)
1916
+ imported_module = @ctx.imports[expression.receiver.name]
1917
+ return nil unless imported_module
1918
+ return nil if imported_module.private_function?(expression.member)
1921
1919
 
1922
- binding = imported_module.functions[expression.member]
1923
- return nil unless binding&.ast
1920
+ binding = imported_module.functions[expression.member]
1921
+ return nil unless binding&.ast
1924
1922
 
1925
- Types::CallableHandle.new("#{expression.receiver.name}.#{expression.member}", binding.ast)
1926
- else
1927
- nil
1928
- end
1923
+ Types::CallableHandle.new("#{expression.receiver.name}.#{expression.member}", binding.ast)
1924
+ else
1925
+ nil
1929
1926
  end
1927
+ end
1930
1928
 
1931
- def resolve_attribute_name_argument(expression)
1932
- case expression
1933
- when AST::Identifier
1934
- @ctx.attributes[expression.name] || builtin_attribute_binding(expression.name)
1935
- when AST::MemberAccess
1936
- return nil unless expression.receiver.is_a?(AST::Identifier)
1929
+ def resolve_attribute_name_argument(expression)
1930
+ case expression
1931
+ when AST::Identifier
1932
+ @ctx.attributes[expression.name] || builtin_attribute_binding(expression.name)
1933
+ when AST::MemberAccess
1934
+ return nil unless expression.receiver.is_a?(AST::Identifier)
1937
1935
 
1938
- imported_module = @ctx.imports[expression.receiver.name]
1939
- return nil unless imported_module
1940
- return nil if imported_module.private_attribute?(expression.member)
1936
+ imported_module = @ctx.imports[expression.receiver.name]
1937
+ return nil unless imported_module
1938
+ return nil if imported_module.private_attribute?(expression.member)
1941
1939
 
1942
- imported_module.attributes[expression.member]
1943
- else
1944
- nil
1945
- end
1940
+ imported_module.attributes[expression.member]
1941
+ else
1942
+ nil
1946
1943
  end
1944
+ end
1947
1945
 
1948
- def reflection_identifier_name(expression)
1949
- expression.is_a?(AST::Identifier) ? expression.name : nil
1950
- end
1946
+ def reflection_identifier_name(expression)
1947
+ expression.is_a?(AST::Identifier) ? expression.name : nil
1948
+ end
1949
+
1950
+ def attribute_binding_supports_target?(binding, target)
1951
+ binding && target && binding.targets.include?(attribute_target_kind(target))
1952
+ end
1951
1953
 
1952
- def attribute_binding_supports_target?(binding, target)
1953
- binding && target && binding.targets.include?(attribute_target_kind(target))
1954
+ def attribute_target_kind(target)
1955
+ case target
1956
+ when Types::StructHandle then :struct
1957
+ when Types::FieldHandle then :field
1958
+ when Types::CallableHandle then :callable
1954
1959
  end
1960
+ end
1955
1961
 
1956
- def attribute_target_kind(target)
1957
- case target
1958
- when Types::StructHandle then :struct
1959
- when Types::FieldHandle then :field
1960
- when Types::CallableHandle then :callable
1961
- end
1962
+ def resolved_attribute_applications_for_target(target)
1963
+ target_id = case target
1964
+ when Types::StructHandle then target.declaration.object_id
1965
+ when Types::FieldHandle then target.field_declaration.object_id
1966
+ when Types::CallableHandle then target.declaration.object_id
1962
1967
  end
1968
+ return [] unless target_id
1963
1969
 
1964
- def resolved_attribute_applications_for_target(target)
1965
- target_id = case target
1966
- when Types::StructHandle then target.declaration.object_id
1967
- when Types::FieldHandle then target.field_declaration.object_id
1968
- when Types::CallableHandle then target.declaration.object_id
1969
- end
1970
- return [] unless target_id
1970
+ applications = @ctx.attribute_applications[target_id]
1971
+ return applications if applications
1971
1972
 
1972
- applications = @ctx.attribute_applications[target_id]
1973
+ @ctx.imports.each_value do |imported_module|
1974
+ applications = imported_module.attribute_applications[target_id]
1973
1975
  return applications if applications
1976
+ end
1974
1977
 
1975
- @ctx.imports.each_value do |imported_module|
1976
- applications = imported_module.attribute_applications[target_id]
1977
- return applications if applications
1978
- end
1978
+ []
1979
+ end
1979
1980
 
1980
- []
1981
+ def find_attribute_application(target, binding)
1982
+ resolved_attribute_applications_for_target(target).find do |application|
1983
+ same_attribute_binding?(application.binding, binding)
1981
1984
  end
1985
+ end
1982
1986
 
1983
- def find_attribute_application(target, binding)
1984
- resolved_attribute_applications_for_target(target).find do |application|
1985
- same_attribute_binding?(application.binding, binding)
1986
- end
1987
- end
1987
+ def same_attribute_binding?(left, right)
1988
+ left.name == right.name && left.module_name == right.module_name
1989
+ end
1988
1990
 
1989
- def same_attribute_binding?(left, right)
1990
- left.name == right.name && left.module_name == right.module_name
1991
- end
1991
+ def builtin_attribute_binding(name)
1992
+ MilkTea.builtin_attribute_binding(name, @ctx.types)
1993
+ end
1992
1994
 
1993
- def builtin_attribute_binding(name)
1994
- MilkTea.builtin_attribute_binding(name, @ctx.types)
1995
- end
1995
+ def specialize_function_binding(binding, arguments, env, receiver_type: nil)
1996
+ return binding if binding.type_params.empty?
1997
+ raise LoweringError.new("generic function #{binding.name} must be called", line: 0, column: 0, path: @ctx.current_analysis_path) unless arguments
1996
1998
 
1997
- def specialize_function_binding(binding, arguments, env, receiver_type: nil)
1998
- return binding if binding.type_params.empty?
1999
- raise LoweringError.new("generic function #{binding.name} must be called", line: 0, column: 0, path: @ctx.current_analysis_path) unless arguments
1999
+ type_arguments = infer_function_type_arguments(binding, arguments, env, receiver_type:)
2000
+ instantiate_function_binding(binding, type_arguments)
2001
+ end
2000
2002
 
2001
- type_arguments = infer_function_type_arguments(binding, arguments, env, receiver_type:)
2002
- instantiate_function_binding(binding, type_arguments)
2003
+ def instantiate_function_binding_with_receiver(binding, explicit_type_arguments, receiver_type: nil)
2004
+ if binding.type_params.empty?
2005
+ raise LoweringError.new("function #{binding.name} is not generic and cannot be specialized", line: 0, column: 0, path: @ctx.current_analysis_path)
2003
2006
  end
2004
2007
 
2005
- def instantiate_function_binding_with_receiver(binding, explicit_type_arguments, receiver_type: nil)
2006
- if binding.type_params.empty?
2007
- raise LoweringError.new("function #{binding.name} is not generic and cannot be specialized", line: 0, column: 0, path: @ctx.current_analysis_path)
2008
- end
2008
+ receiver_substitutions = infer_receiver_type_substitutions(binding, receiver_type)
2009
+ remaining_type_params = binding.type_params.reject { |name| receiver_substitutions.key?(name) }
2010
+ unless remaining_type_params.length == explicit_type_arguments.length
2011
+ raise LoweringError.new("function #{binding.name} expects #{remaining_type_params.length} type arguments, got #{explicit_type_arguments.length}", line: 0, column: 0, path: @ctx.current_analysis_path)
2012
+ end
2009
2013
 
2010
- receiver_substitutions = infer_receiver_type_substitutions(binding, receiver_type)
2011
- remaining_type_params = binding.type_params.reject { |name| receiver_substitutions.key?(name) }
2012
- unless remaining_type_params.length == explicit_type_arguments.length
2013
- raise LoweringError.new("function #{binding.name} expects #{remaining_type_params.length} type arguments, got #{explicit_type_arguments.length}", line: 0, column: 0, path: @ctx.current_analysis_path)
2014
- end
2014
+ substitutions = receiver_substitutions.dup
2015
+ remaining_type_params.zip(explicit_type_arguments).each do |name, type_argument|
2016
+ raise LoweringError.new("generic function #{binding.name} cannot be instantiated with ref types", line: 0, column: 0, path: @ctx.current_analysis_path) if contains_ref_type?(type_argument)
2015
2017
 
2016
- substitutions = receiver_substitutions.dup
2017
- remaining_type_params.zip(explicit_type_arguments).each do |name, type_argument|
2018
- raise LoweringError.new("generic function #{binding.name} cannot be instantiated with ref types", line: 0, column: 0, path: @ctx.current_analysis_path) if contains_ref_type?(type_argument)
2018
+ substitutions[name] = type_argument
2019
+ end
2019
2020
 
2020
- substitutions[name] = type_argument
2021
- end
2021
+ type_arguments = binding.type_params.map do |name|
2022
+ inferred = substitutions[name]
2023
+ raise LoweringError.new("cannot infer type argument #{name} for function #{binding.name}", line: 0, column: 0, path: @ctx.current_analysis_path) unless inferred
2022
2024
 
2023
- type_arguments = binding.type_params.map do |name|
2024
- inferred = substitutions[name]
2025
- raise LoweringError.new("cannot infer type argument #{name} for function #{binding.name}", line: 0, column: 0, path: @ctx.current_analysis_path) unless inferred
2025
+ inferred
2026
+ end
2026
2027
 
2027
- inferred
2028
- end
2028
+ instantiate_function_binding(binding, type_arguments)
2029
+ end
2029
2030
 
2030
- instantiate_function_binding(binding, type_arguments)
2031
+ def instantiate_function_binding(binding, type_arguments)
2032
+ if binding.type_params.empty?
2033
+ raise LoweringError.new("function #{binding.name} is not generic and cannot be specialized", line: 0, column: 0, path: @ctx.current_analysis_path)
2031
2034
  end
2032
2035
 
2033
- def instantiate_function_binding(binding, type_arguments)
2034
- if binding.type_params.empty?
2035
- raise LoweringError.new("function #{binding.name} is not generic and cannot be specialized", line: 0, column: 0, path: @ctx.current_analysis_path)
2036
- end
2037
-
2038
- unless binding.type_params.length == type_arguments.length
2039
- raise LoweringError.new("function #{binding.name} expects #{binding.type_params.length} type arguments, got #{type_arguments.length}", line: 0, column: 0, path: @ctx.current_analysis_path)
2040
- end
2036
+ unless binding.type_params.length == type_arguments.length
2037
+ raise LoweringError.new("function #{binding.name} expects #{binding.type_params.length} type arguments, got #{type_arguments.length}", line: 0, column: 0, path: @ctx.current_analysis_path)
2038
+ end
2041
2039
 
2042
- if type_arguments.any? { |type_argument| contains_ref_type?(type_argument) }
2043
- raise LoweringError.new("generic function #{binding.name} cannot be instantiated with ref types", line: 0, column: 0, path: @ctx.current_analysis_path)
2044
- end
2040
+ if type_arguments.any? { |type_argument| contains_ref_type?(type_argument) }
2041
+ raise LoweringError.new("generic function #{binding.name} cannot be instantiated with ref types", line: 0, column: 0, path: @ctx.current_analysis_path)
2042
+ end
2045
2043
 
2046
- key = type_arguments.freeze
2047
- return binding.instances.fetch(key) if binding.instances.key?(key)
2044
+ key = type_arguments.freeze
2045
+ return binding.instances.fetch(key) if binding.instances.key?(key)
2048
2046
 
2049
- substitutions = binding.type_params.zip(type_arguments).to_h
2050
- validate_function_type_param_constraints!(binding, substitutions)
2051
- instance = FunctionBinding.new(
2052
- name: binding.name,
2053
- type: substitute_type(binding.type, substitutions),
2054
- body_params: binding.body_params.map { |param| substitute_value_binding(param, substitutions) },
2055
- body_return_type: substitute_type(binding.body_return_type, substitutions),
2056
- ast: binding.ast,
2057
- external: binding.external,
2058
- async: binding.async,
2059
- type_params: [].freeze,
2060
- type_param_constraints: {}.freeze,
2061
- instances: {},
2062
- type_arguments: key,
2063
- owner: binding.owner,
2064
- specialization_owner: nil,
2065
- type_substitutions: substitutions.freeze,
2066
- declared_receiver_type: binding.declared_receiver_type ? substitute_type(binding.declared_receiver_type, substitutions) : nil,
2067
- )
2068
- binding.instances[key] = instance
2069
- end
2047
+ substitutions = binding.type_params.zip(type_arguments).to_h
2048
+ validate_function_type_param_constraints!(binding, substitutions)
2049
+ instance = FunctionBinding.new(
2050
+ name: binding.name,
2051
+ type: substitute_type(binding.type, substitutions),
2052
+ body_params: binding.body_params.map { |param| substitute_value_binding(param, substitutions) },
2053
+ body_return_type: substitute_type(binding.body_return_type, substitutions),
2054
+ ast: binding.ast,
2055
+ external: binding.external,
2056
+ async: binding.async,
2057
+ type_params: [].freeze,
2058
+ type_param_constraints: {}.freeze,
2059
+ instances: {},
2060
+ type_arguments: key,
2061
+ owner: binding.owner,
2062
+ specialization_owner: nil,
2063
+ type_substitutions: substitutions.freeze,
2064
+ declared_receiver_type: binding.declared_receiver_type ? substitute_type(binding.declared_receiver_type, substitutions) : nil,
2065
+ )
2066
+ binding.instances[key] = instance
2067
+ end
2070
2068
 
2071
- def validate_function_type_param_constraints!(binding, substitutions)
2072
- binding.type_param_constraints.each do |name, constraints|
2073
- actual_type = substitutions[name]
2074
- raise LoweringError.new("cannot infer type argument #{name} for function #{binding.name}", line: 0, column: 0, path: @ctx.current_analysis_path) unless actual_type
2069
+ def validate_function_type_param_constraints!(binding, substitutions)
2070
+ binding.type_param_constraints.each do |name, constraints|
2071
+ actual_type = substitutions[name]
2072
+ raise LoweringError.new("cannot infer type argument #{name} for function #{binding.name}", line: 0, column: 0, path: @ctx.current_analysis_path) unless actual_type
2075
2073
 
2076
- constraints.interfaces.each do |interface|
2077
- next if type_implements_interface?(actual_type, interface)
2074
+ constraints.interfaces.each do |interface|
2075
+ next if type_implements_interface?(actual_type, interface)
2078
2076
 
2079
- raise LoweringError.new("type #{actual_type} does not implement interface #{interface.name} for function #{binding.name}", line: 0, column: 0, path: @ctx.current_analysis_path)
2080
- end
2077
+ raise LoweringError.new("type #{actual_type} does not implement interface #{interface.name} for function #{binding.name}", line: 0, column: 0, path: @ctx.current_analysis_path)
2081
2078
  end
2082
2079
  end
2080
+ end
2083
2081
 
2084
2082
 
2085
- def interface_implementation_key(type)
2086
- return type.definition if type.is_a?(Types::StructInstance)
2087
-
2088
- type
2089
- end
2083
+ def interface_implementation_key(type)
2084
+ return type.definition if type.is_a?(Types::StructInstance)
2090
2085
 
2091
- def type_implements_interface?(type, interface)
2092
- key = interface_implementation_key(type)
2093
- return true if @ctx.implemented_interfaces.fetch(key, []).include?(interface)
2086
+ type
2087
+ end
2094
2088
 
2095
- @ctx.imports.each_value do |module_binding|
2096
- return true if module_binding.implemented_interfaces.fetch(key, []).include?(interface)
2097
- end
2089
+ def type_implements_interface?(type, interface)
2090
+ key = interface_implementation_key(type)
2091
+ return true if @ctx.implemented_interfaces.fetch(key, []).include?(interface)
2098
2092
 
2099
- false
2093
+ @ctx.imports.each_value do |module_binding|
2094
+ return true if module_binding.implemented_interfaces.fetch(key, []).include?(interface)
2100
2095
  end
2101
2096
 
2102
- def infer_function_type_arguments(binding, arguments, env, receiver_type: nil)
2103
- expected_params = binding.type.params
2104
- unless call_arity_matches?(binding.type, arguments.length)
2105
- raise LoweringError.new(arity_error_message(binding.type, binding.name, arguments.length), line: 0, column: 0, path: @ctx.current_analysis_path)
2106
- end
2107
-
2108
- substitutions = infer_receiver_type_substitutions(binding, receiver_type)
2109
- expected_params.each_with_index do |parameter, index|
2110
- argument = arguments.fetch(index)
2111
- candidate_type = substitute_type(parameter.type, substitutions)
2112
- expected_argument_type = if callable_type?(candidate_type)
2113
- candidate_type
2114
- elsif contains_type_var?(candidate_type)
2115
- nil
2116
- else
2117
- candidate_type
2118
- end
2119
- actual_type = infer_expression_type(argument.value, env:, expected_type: expected_argument_type)
2120
- collect_type_substitutions(parameter.type, actual_type, substitutions, binding.name)
2121
- end
2097
+ false
2098
+ end
2122
2099
 
2123
- binding.type_params.map do |name|
2124
- inferred = substitutions[name]
2125
- raise LoweringError.new("cannot infer type argument #{name} for function #{binding.name}", line: 0, column: 0, path: @ctx.current_analysis_path) unless inferred
2100
+ def infer_function_type_arguments(binding, arguments, env, receiver_type: nil)
2101
+ expected_params = binding.type.params
2102
+ unless call_arity_matches?(binding.type, arguments.length)
2103
+ raise LoweringError.new(arity_error_message(binding.type, binding.name, arguments.length), line: 0, column: 0, path: @ctx.current_analysis_path)
2104
+ end
2126
2105
 
2127
- inferred
2128
- end
2106
+ substitutions = infer_receiver_type_substitutions(binding, receiver_type)
2107
+ expected_params.each_with_index do |parameter, index|
2108
+ argument = arguments.fetch(index)
2109
+ candidate_type = substitute_type(parameter.type, substitutions)
2110
+ expected_argument_type = if callable_type?(candidate_type)
2111
+ candidate_type
2112
+ elsif contains_type_var?(candidate_type)
2113
+ nil
2114
+ else
2115
+ candidate_type
2116
+ end
2117
+ actual_type = infer_expression_type(argument.value, env:, expected_type: expected_argument_type)
2118
+ collect_type_substitutions(parameter.type, actual_type, substitutions, binding.name)
2129
2119
  end
2130
2120
 
2121
+ binding.type_params.map do |name|
2122
+ inferred = substitutions[name]
2123
+ raise LoweringError.new("cannot infer type argument #{name} for function #{binding.name}", line: 0, column: 0, path: @ctx.current_analysis_path) unless inferred
2124
+
2125
+ inferred
2126
+ end
2127
+ end
2131
2128
 
2132
2129
 
2133
- def resolve_named_generic_type_for_analysis(analysis, parts)
2134
- if parts.length == 1
2135
- type = analysis.types[parts.first]
2136
- return type if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
2137
- elsif parts.length == 2 && analysis.imports.key?(parts.first)
2138
- type = analysis.imports.fetch(parts.first).types[parts.last]
2139
- return type if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
2140
- end
2141
2130
 
2142
- nil
2131
+ def resolve_named_generic_type_for_analysis(analysis, parts)
2132
+ if parts.length == 1
2133
+ type = analysis.types[parts.first]
2134
+ return type if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
2135
+ elsif parts.length == 2 && analysis.imports.key?(parts.first)
2136
+ type = analysis.imports.fetch(parts.first).types[parts.last]
2137
+ return type if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
2143
2138
  end
2144
2139
 
2145
- def validate_methods_receiver_type_arguments!(type_ref, generic_type)
2146
- names = type_ref.arguments.map do |argument|
2147
- value = argument.value
2148
- next unless value.is_a?(AST::TypeRef)
2149
- next unless value.arguments.empty? && !value.nullable && value.name.parts.length == 1
2150
-
2151
- value.name.parts.first
2152
- end
2140
+ nil
2141
+ end
2153
2142
 
2154
- expected_names = generic_type.type_params
2155
- unless names == expected_names
2156
- raise LoweringError.new("extending target #{type_ref} must use the receiver type parameters directly", line: 0, column: 0, path: @ctx.current_analysis_path)
2157
- end
2143
+ def validate_methods_receiver_type_arguments!(type_ref, generic_type)
2144
+ names = type_ref.arguments.map do |argument|
2145
+ value = argument.value
2146
+ next unless value.is_a?(AST::TypeRef)
2147
+ next unless value.arguments.empty? && !value.nullable && value.name.parts.length == 1
2158
2148
 
2159
- expected_names
2149
+ value.name.parts.first
2160
2150
  end
2161
2151
 
2162
- def methods_receiver_type_argument_names!(type_ref)
2163
- names = type_ref.arguments.map do |argument|
2164
- value = argument.value
2165
- next unless value.is_a?(AST::TypeRef)
2166
- next unless value.arguments.empty? && !value.nullable && value.name.parts.length == 1
2152
+ expected_names = generic_type.type_params
2153
+ unless names == expected_names
2154
+ raise LoweringError.new("extending target #{type_ref} must use the receiver type parameters directly", line: 0, column: 0, path: @ctx.current_analysis_path)
2155
+ end
2167
2156
 
2168
- value.name.parts.first
2169
- end
2157
+ expected_names
2158
+ end
2170
2159
 
2171
- raise LoweringError.new("extending target #{type_ref} must use the receiver type parameters directly", line: 0, column: 0, path: @ctx.current_analysis_path) if names.any?(&:nil?)
2160
+ def methods_receiver_type_argument_names!(type_ref)
2161
+ names = type_ref.arguments.map do |argument|
2162
+ value = argument.value
2163
+ next unless value.is_a?(AST::TypeRef)
2164
+ next unless value.arguments.empty? && !value.nullable && value.name.parts.length == 1
2172
2165
 
2173
- names
2166
+ value.name.parts.first
2174
2167
  end
2175
2168
 
2176
- def infer_receiver_type_substitutions(binding, receiver_type)
2177
- declared_receiver_type = binding.declared_receiver_type
2178
- return {} unless declared_receiver_type
2179
- case declared_receiver_type
2180
- when Types::Nullable
2181
- unless receiver_type.is_a?(Types::Nullable)
2182
- raise LoweringError.new("cannot use method #{binding.name} with receiver #{receiver_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
2183
- end
2169
+ raise LoweringError.new("extending target #{type_ref} must use the receiver type parameters directly", line: 0, column: 0, path: @ctx.current_analysis_path) if names.any?(&:nil?)
2184
2170
 
2185
- infer_receiver_type_substitutions(
2186
- binding.with(declared_receiver_type: declared_receiver_type.base),
2187
- receiver_type.base,
2188
- )
2189
- when Types::StructInstance
2190
- return {} unless declared_receiver_type.definition.is_a?(Types::GenericStructDefinition)
2171
+ names
2172
+ end
2191
2173
 
2192
- unless receiver_type.is_a?(Types::StructInstance) && receiver_type.definition == declared_receiver_type.definition
2193
- raise LoweringError.new("cannot use method #{binding.name} with receiver #{receiver_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
2194
- end
2174
+ def infer_receiver_type_substitutions(binding, receiver_type)
2175
+ declared_receiver_type = binding.declared_receiver_type
2176
+ return {} unless declared_receiver_type
2177
+ case declared_receiver_type
2178
+ when Types::Nullable
2179
+ unless receiver_type.is_a?(Types::Nullable)
2180
+ raise LoweringError.new("cannot use method #{binding.name} with receiver #{receiver_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
2181
+ end
2195
2182
 
2196
- declared_receiver_type.definition.type_params.zip(receiver_type.arguments).to_h
2197
- when Types::VariantInstance
2198
- return {} unless declared_receiver_type.definition.is_a?(Types::GenericVariantDefinition)
2183
+ infer_receiver_type_substitutions(
2184
+ binding.with(declared_receiver_type: declared_receiver_type.base),
2185
+ receiver_type.base,
2186
+ )
2187
+ when Types::StructInstance
2188
+ return {} unless declared_receiver_type.definition.is_a?(Types::GenericStructDefinition)
2199
2189
 
2200
- unless receiver_type.is_a?(Types::VariantInstance) && receiver_type.definition == declared_receiver_type.definition
2201
- raise LoweringError.new("cannot use method #{binding.name} with receiver #{receiver_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
2202
- end
2190
+ unless receiver_type.is_a?(Types::StructInstance) && receiver_type.definition == declared_receiver_type.definition
2191
+ raise LoweringError.new("cannot use method #{binding.name} with receiver #{receiver_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
2192
+ end
2203
2193
 
2204
- declared_receiver_type.definition.type_params.zip(receiver_type.arguments).to_h
2205
- when Types::GenericInstance
2206
- unless receiver_type.is_a?(Types::GenericInstance) && receiver_type.name == declared_receiver_type.name && receiver_type.arguments.length == declared_receiver_type.arguments.length
2207
- raise LoweringError.new("cannot use method #{binding.name} with receiver #{receiver_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
2208
- end
2194
+ declared_receiver_type.definition.type_params.zip(receiver_type.arguments).to_h
2195
+ when Types::VariantInstance
2196
+ return {} unless declared_receiver_type.definition.is_a?(Types::GenericVariantDefinition)
2209
2197
 
2210
- declared_receiver_type.arguments.zip(receiver_type.arguments).each_with_object({}) do |(declared_argument, actual_argument), substitutions|
2211
- if declared_argument.is_a?(Types::TypeVar)
2212
- substitutions[declared_argument.name] = actual_argument
2213
- elsif declared_argument != actual_argument
2214
- raise LoweringError.new("cannot use method #{binding.name} with receiver #{receiver_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
2215
- end
2216
- end
2217
- when Types::Span
2218
- return {} unless receiver_type.is_a?(Types::Span)
2198
+ unless receiver_type.is_a?(Types::VariantInstance) && receiver_type.definition == declared_receiver_type.definition
2199
+ raise LoweringError.new("cannot use method #{binding.name} with receiver #{receiver_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
2200
+ end
2219
2201
 
2220
- substitutions = {}
2221
- if declared_receiver_type.element_type.is_a?(Types::TypeVar)
2222
- substitutions[declared_receiver_type.element_type.name] = receiver_type.element_type
2223
- elsif declared_receiver_type.element_type != receiver_type.element_type
2224
- raise LoweringError.new("cannot use method #{binding.name} with receiver #{receiver_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
2225
- end
2226
- substitutions
2227
- when Types::Task
2228
- return {} unless receiver_type.is_a?(Types::Task)
2229
-
2230
- substitutions = {}
2231
- if declared_receiver_type.result_type.is_a?(Types::TypeVar)
2232
- substitutions[declared_receiver_type.result_type.name] = receiver_type.result_type
2233
- elsif declared_receiver_type.result_type != receiver_type.result_type
2234
- raise LoweringError.new("cannot use method #{binding.name} with receiver #{receiver_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
2235
- end
2236
- substitutions
2237
- when Types::SoA
2238
- return {} unless receiver_type.is_a?(Types::SoA)
2239
-
2240
- substitutions = {}
2241
- if declared_receiver_type.element_type.is_a?(Types::TypeVar)
2242
- substitutions[declared_receiver_type.element_type.name] = receiver_type.element_type
2243
- elsif declared_receiver_type.element_type != receiver_type.element_type
2244
- raise LoweringError.new("cannot use method #{binding.name} with receiver #{receiver_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
2245
- end
2246
- substitutions
2247
- when Types::Simd
2248
- return {} unless receiver_type.is_a?(Types::Simd)
2249
-
2250
- substitutions = {}
2251
- if declared_receiver_type.element_type.is_a?(Types::TypeVar)
2252
- substitutions[declared_receiver_type.element_type.name] = receiver_type.element_type
2253
- elsif declared_receiver_type.element_type != receiver_type.element_type
2202
+ declared_receiver_type.definition.type_params.zip(receiver_type.arguments).to_h
2203
+ when Types::GenericInstance
2204
+ unless receiver_type.is_a?(Types::GenericInstance) && receiver_type.name == declared_receiver_type.name && receiver_type.arguments.length == declared_receiver_type.arguments.length
2205
+ raise LoweringError.new("cannot use method #{binding.name} with receiver #{receiver_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
2206
+ end
2207
+
2208
+ declared_receiver_type.arguments.zip(receiver_type.arguments).each_with_object({}) do |(declared_argument, actual_argument), substitutions|
2209
+ if declared_argument.is_a?(Types::TypeVar)
2210
+ substitutions[declared_argument.name] = actual_argument
2211
+ elsif declared_argument != actual_argument
2254
2212
  raise LoweringError.new("cannot use method #{binding.name} with receiver #{receiver_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
2255
2213
  end
2256
- substitutions
2257
- else
2258
- {}
2259
2214
  end
2260
- end
2215
+ when Types::Span
2216
+ return {} unless receiver_type.is_a?(Types::Span)
2217
+
2218
+ substitutions = {}
2219
+ if declared_receiver_type.element_type.is_a?(Types::TypeVar)
2220
+ substitutions[declared_receiver_type.element_type.name] = receiver_type.element_type
2221
+ elsif declared_receiver_type.element_type != receiver_type.element_type
2222
+ raise LoweringError.new("cannot use method #{binding.name} with receiver #{receiver_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
2223
+ end
2224
+ substitutions
2225
+ when Types::Task
2226
+ return {} unless receiver_type.is_a?(Types::Task)
2227
+
2228
+ substitutions = {}
2229
+ if declared_receiver_type.result_type.is_a?(Types::TypeVar)
2230
+ substitutions[declared_receiver_type.result_type.name] = receiver_type.result_type
2231
+ elsif declared_receiver_type.result_type != receiver_type.result_type
2232
+ raise LoweringError.new("cannot use method #{binding.name} with receiver #{receiver_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
2233
+ end
2234
+ substitutions
2235
+ when Types::SoA
2236
+ return {} unless receiver_type.is_a?(Types::SoA)
2237
+
2238
+ substitutions = {}
2239
+ if declared_receiver_type.element_type.is_a?(Types::TypeVar)
2240
+ substitutions[declared_receiver_type.element_type.name] = receiver_type.element_type
2241
+ elsif declared_receiver_type.element_type != receiver_type.element_type
2242
+ raise LoweringError.new("cannot use method #{binding.name} with receiver #{receiver_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
2243
+ end
2244
+ substitutions
2245
+ when Types::Simd
2246
+ return {} unless receiver_type.is_a?(Types::Simd)
2247
+
2248
+ substitutions = {}
2249
+ if declared_receiver_type.element_type.is_a?(Types::TypeVar)
2250
+ substitutions[declared_receiver_type.element_type.name] = receiver_type.element_type
2251
+ elsif declared_receiver_type.element_type != receiver_type.element_type
2252
+ raise LoweringError.new("cannot use method #{binding.name} with receiver #{receiver_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
2253
+ end
2254
+ substitutions
2255
+ else
2256
+ {}
2257
+ end
2258
+ end
2259
+
2260
+ def collect_type_substitutions(pattern_type, actual_type, substitutions, function_name)
2261
+ case pattern_type
2262
+ when Types::TypeVar
2263
+ existing = substitutions[pattern_type.name]
2264
+ if existing && existing != actual_type
2265
+ raise LoweringError.new("conflicting type argument #{pattern_type.name} for function #{function_name}: got #{existing} and #{actual_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
2266
+ end
2267
+
2268
+ substitutions[pattern_type.name] ||= actual_type
2269
+ when Types::Nullable
2270
+ candidate = actual_type.is_a?(Types::Nullable) ? actual_type.base : actual_type
2271
+ collect_type_substitutions(pattern_type.base, candidate, substitutions, function_name)
2272
+ when Types::GenericInstance
2273
+ if ref_type?(pattern_type) && !ref_type?(actual_type)
2274
+ collect_type_substitutions(referenced_type(pattern_type), actual_type, substitutions, function_name)
2275
+ return
2276
+ end
2261
2277
 
2262
- def collect_type_substitutions(pattern_type, actual_type, substitutions, function_name)
2263
- case pattern_type
2264
- when Types::TypeVar
2265
- existing = substitutions[pattern_type.name]
2266
- if existing && existing != actual_type
2267
- raise LoweringError.new("conflicting type argument #{pattern_type.name} for function #{function_name}: got #{existing} and #{actual_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
2268
- end
2278
+ if own_type?(actual_type) && (mutable_pointer_type?(pattern_type) || const_pointer_type?(pattern_type))
2279
+ collect_type_substitutions(pointee_type(pattern_type), owned_referent_type(actual_type), substitutions, function_name)
2280
+ return
2281
+ end
2269
2282
 
2270
- substitutions[pattern_type.name] ||= actual_type
2271
- when Types::Nullable
2272
- candidate = actual_type.is_a?(Types::Nullable) ? actual_type.base : actual_type
2273
- collect_type_substitutions(pattern_type.base, candidate, substitutions, function_name)
2274
- when Types::GenericInstance
2275
- if ref_type?(pattern_type) && !ref_type?(actual_type)
2276
- collect_type_substitutions(referenced_type(pattern_type), actual_type, substitutions, function_name)
2277
- return
2278
- end
2283
+ return unless actual_type.is_a?(Types::GenericInstance)
2284
+ return unless actual_type.name == pattern_type.name && actual_type.arguments.length == pattern_type.arguments.length
2279
2285
 
2280
- if own_type?(actual_type) && (mutable_pointer_type?(pattern_type) || const_pointer_type?(pattern_type))
2281
- collect_type_substitutions(pointee_type(pattern_type), owned_referent_type(actual_type), substitutions, function_name)
2282
- return
2283
- end
2286
+ pattern_type.arguments.zip(actual_type.arguments).each do |expected_argument, actual_argument|
2287
+ next if expected_argument.is_a?(Types::LiteralTypeArg)
2284
2288
 
2285
- return unless actual_type.is_a?(Types::GenericInstance)
2286
- return unless actual_type.name == pattern_type.name && actual_type.arguments.length == pattern_type.arguments.length
2289
+ collect_type_substitutions(expected_argument, actual_argument, substitutions, function_name)
2290
+ end
2291
+ when Types::Span
2292
+ return unless actual_type.is_a?(Types::Span)
2287
2293
 
2288
- pattern_type.arguments.zip(actual_type.arguments).each do |expected_argument, actual_argument|
2289
- next if expected_argument.is_a?(Types::LiteralTypeArg)
2294
+ collect_type_substitutions(pattern_type.element_type, actual_type.element_type, substitutions, function_name)
2295
+ when Types::Task
2296
+ return unless actual_type.is_a?(Types::Task)
2290
2297
 
2291
- collect_type_substitutions(expected_argument, actual_argument, substitutions, function_name)
2292
- end
2293
- when Types::Span
2294
- return unless actual_type.is_a?(Types::Span)
2295
-
2296
- collect_type_substitutions(pattern_type.element_type, actual_type.element_type, substitutions, function_name)
2297
- when Types::Task
2298
- return unless actual_type.is_a?(Types::Task)
2299
-
2300
- collect_type_substitutions(pattern_type.result_type, actual_type.result_type, substitutions, function_name)
2301
- when Types::Proc
2302
- if task_root_proc_type?(pattern_type) && actual_type.is_a?(Types::Task)
2303
- collect_type_substitutions(pattern_type.return_type, actual_type, substitutions, function_name)
2304
- return
2305
- end
2298
+ collect_type_substitutions(pattern_type.result_type, actual_type.result_type, substitutions, function_name)
2299
+ when Types::Proc
2300
+ if task_root_proc_type?(pattern_type) && actual_type.is_a?(Types::Task)
2301
+ collect_type_substitutions(pattern_type.return_type, actual_type, substitutions, function_name)
2302
+ return
2303
+ end
2306
2304
 
2307
- actual_params = case actual_type
2308
- when Types::Proc
2309
- return unless actual_type.params.length == pattern_type.params.length
2305
+ actual_params = case actual_type
2306
+ when Types::Proc
2307
+ return unless actual_type.params.length == pattern_type.params.length
2310
2308
 
2311
- actual_type.params
2312
- when Types::Function
2313
- return if actual_type.receiver_type || actual_type.variadic
2314
- return unless actual_type.params.length == pattern_type.params.length
2315
- return unless actual_type.params.zip(pattern_type.params).all? { |actual_param, expected_param| actual_param.mutable == expected_param.mutable }
2309
+ actual_type.params
2310
+ when Types::Function
2311
+ return if actual_type.receiver_type || actual_type.variadic
2312
+ return unless actual_type.params.length == pattern_type.params.length
2313
+ return unless actual_type.params.zip(pattern_type.params).all? { |actual_param, expected_param| actual_param.mutable == expected_param.mutable }
2316
2314
 
2317
- actual_type.params
2318
- else
2319
- return
2320
- end
2315
+ actual_type.params
2316
+ else
2317
+ return
2318
+ end
2321
2319
 
2322
- pattern_type.params.zip(actual_params).each do |expected_param, actual_param|
2323
- collect_type_substitutions(expected_param.type, actual_param.type, substitutions, function_name)
2324
- end
2325
- collect_type_substitutions(pattern_type.return_type, actual_type.return_type, substitutions, function_name)
2326
- when Types::StructInstance
2327
- return unless actual_type.is_a?(Types::StructInstance)
2328
- return unless actual_type.definition == pattern_type.definition && actual_type.arguments.length == pattern_type.arguments.length
2320
+ pattern_type.params.zip(actual_params).each do |expected_param, actual_param|
2321
+ collect_type_substitutions(expected_param.type, actual_param.type, substitutions, function_name)
2322
+ end
2323
+ collect_type_substitutions(pattern_type.return_type, actual_type.return_type, substitutions, function_name)
2324
+ when Types::StructInstance
2325
+ return unless actual_type.is_a?(Types::StructInstance)
2326
+ return unless actual_type.definition == pattern_type.definition && actual_type.arguments.length == pattern_type.arguments.length
2329
2327
 
2330
- pattern_type.arguments.zip(actual_type.arguments).each do |expected_argument, actual_argument|
2331
- collect_type_substitutions(expected_argument, actual_argument, substitutions, function_name)
2332
- end
2333
- when Types::VariantInstance
2334
- return unless actual_type.is_a?(Types::VariantInstance)
2335
- return unless actual_type.definition == pattern_type.definition && actual_type.arguments.length == pattern_type.arguments.length
2328
+ pattern_type.arguments.zip(actual_type.arguments).each do |expected_argument, actual_argument|
2329
+ collect_type_substitutions(expected_argument, actual_argument, substitutions, function_name)
2330
+ end
2331
+ when Types::VariantInstance
2332
+ return unless actual_type.is_a?(Types::VariantInstance)
2333
+ return unless actual_type.definition == pattern_type.definition && actual_type.arguments.length == pattern_type.arguments.length
2336
2334
 
2337
- pattern_type.arguments.zip(actual_type.arguments).each do |expected_argument, actual_argument|
2338
- collect_type_substitutions(expected_argument, actual_argument, substitutions, function_name)
2339
- end
2340
- when Types::Function
2341
- return unless actual_type.is_a?(Types::Function)
2342
- return unless actual_type.params.length == pattern_type.params.length
2335
+ pattern_type.arguments.zip(actual_type.arguments).each do |expected_argument, actual_argument|
2336
+ collect_type_substitutions(expected_argument, actual_argument, substitutions, function_name)
2337
+ end
2338
+ when Types::Function
2339
+ return unless actual_type.is_a?(Types::Function)
2340
+ return unless actual_type.params.length == pattern_type.params.length
2343
2341
 
2344
- pattern_type.params.zip(actual_type.params).each do |expected_param, actual_param|
2345
- collect_type_substitutions(expected_param.type, actual_param.type, substitutions, function_name)
2346
- end
2347
- collect_type_substitutions(pattern_type.return_type, actual_type.return_type, substitutions, function_name)
2342
+ pattern_type.params.zip(actual_type.params).each do |expected_param, actual_param|
2343
+ collect_type_substitutions(expected_param.type, actual_param.type, substitutions, function_name)
2348
2344
  end
2345
+ collect_type_substitutions(pattern_type.return_type, actual_type.return_type, substitutions, function_name)
2349
2346
  end
2347
+ end
2350
2348
 
2351
- def substitute_value_binding(binding, substitutions)
2352
- ValueBinding.new(
2353
- id: binding.id,
2354
- name: binding.name,
2355
- storage_type: substitute_type(binding.storage_type, substitutions),
2356
- flow_type: binding.flow_type ? substitute_type(binding.flow_type, substitutions) : nil,
2357
- mutable: binding.mutable,
2358
- kind: binding.kind,
2359
- const_value: binding.const_value,
2360
- )
2361
- end
2349
+ def substitute_value_binding(binding, substitutions)
2350
+ ValueBinding.new(
2351
+ id: binding.id,
2352
+ name: binding.name,
2353
+ storage_type: substitute_type(binding.storage_type, substitutions),
2354
+ flow_type: binding.flow_type ? substitute_type(binding.flow_type, substitutions) : nil,
2355
+ mutable: binding.mutable,
2356
+ kind: binding.kind,
2357
+ const_value: binding.const_value,
2358
+ )
2359
+ end
2362
2360
 
2363
- def substitute_type(type, substitutions)
2364
- SubstituteTypeVisitor.new(substitutions).apply(type)
2365
- end
2361
+ def substitute_type(type, substitutions)
2362
+ SubstituteTypeVisitor.new(substitutions).apply(type)
2363
+ end
2366
2364
 
2367
- def analysis_for_module(module_name)
2368
- @program.analyses_by_module_name.fetch(module_name)
2369
- end
2365
+ def analysis_for_module(module_name)
2366
+ @program.analyses_by_module_name.fetch(module_name)
2367
+ end
2370
2368
 
2371
- def each_raw_module_analysis(&block)
2372
- return @program.analyses_by_module_name.each_value.select { |a| a.module_kind == :raw_module }.each unless block
2373
- @program.analyses_by_module_name.each_value { |a| block.call(a) if a.module_kind == :raw_module }
2374
- end
2369
+ def each_raw_module_analysis(&block)
2370
+ return @program.analyses_by_module_name.each_value.select { |a| a.module_kind == :raw_module }.each unless block
2371
+ @program.analyses_by_module_name.each_value { |a| block.call(a) if a.module_kind == :raw_module }
2372
+ end
2375
2373
 
2376
- def each_non_raw_module_analysis(&block)
2377
- return @program.analyses_by_module_name.each_value.reject { |a| a.module_kind == :raw_module }.each unless block
2378
- @program.analyses_by_module_name.each_value { |a| block.call(a) unless a.module_kind == :raw_module }
2379
- end
2374
+ def each_non_raw_module_analysis(&block)
2375
+ return @program.analyses_by_module_name.each_value.reject { |a| a.module_kind == :raw_module }.each unless block
2376
+ @program.analyses_by_module_name.each_value { |a| block.call(a) unless a.module_kind == :raw_module }
2377
+ end
2380
2378
 
2381
- def types_for_module(module_name)
2382
- @program.analyses_by_module_name.fetch(module_name).types
2383
- end
2379
+ def types_for_module(module_name)
2380
+ @program.analyses_by_module_name.fetch(module_name).types
2381
+ end
2384
2382
 
2385
- def imports_for_module(module_name)
2386
- @program.analyses_by_module_name.fetch(module_name).imports
2387
- end
2383
+ def imports_for_module(module_name)
2384
+ @program.analyses_by_module_name.fetch(module_name).imports
2385
+ end
2388
2386
 
2389
- def const_declaration_for_module(module_name, name)
2390
- analysis = @program.analyses_by_module_name.fetch(module_name)
2391
- declaration = analysis.ast.declarations.find { |decl| decl.is_a?(AST::ConstDecl) && decl.name == name }
2392
- raise LoweringError.new("unknown constant #{analysis.module_name}.#{name}", line: 0, column: 0, path: @ctx.current_analysis_path) unless declaration
2387
+ def const_declaration_for_module(module_name, name)
2388
+ analysis = @program.analyses_by_module_name.fetch(module_name)
2389
+ declaration = analysis.ast.declarations.find { |decl| decl.is_a?(AST::ConstDecl) && decl.name == name }
2390
+ raise LoweringError.new("unknown constant #{analysis.module_name}.#{name}", line: 0, column: 0, path: @ctx.current_analysis_path) unless declaration
2393
2391
 
2394
- declaration
2395
- end
2392
+ declaration
2393
+ end
2396
2394
 
2397
- def resolve_type_ref_for_analysis(type_ref, analysis, type_params: current_type_params)
2398
- saved = @ctx.save
2399
- @ctx.install(analysis)
2400
- @ctx.module_prefix = module_c_prefix(@ctx.module_name)
2401
- resolve_type_ref(type_ref, type_params:)
2402
- ensure
2403
- @ctx.restore(saved)
2404
- end
2395
+ def resolve_type_ref_for_analysis(type_ref, analysis, type_params: current_type_params)
2396
+ saved = @ctx.save
2397
+ @ctx.install(analysis)
2398
+ @ctx.module_prefix = module_c_prefix(@ctx.module_name)
2399
+ resolve_type_ref(type_ref, type_params:)
2400
+ ensure
2401
+ @ctx.restore(saved)
2402
+ end
2405
2403
 
2406
- def current_type_params
2407
- @ctx.current_type_substitutions || {}
2404
+ def current_type_params
2405
+ @ctx.current_type_substitutions || {}
2406
+ end
2407
+
2408
+ def resolve_type_ref(type_ref, type_params: current_type_params)
2409
+ if type_ref.is_a?(AST::FunctionType)
2410
+ params = type_ref.params.map do |param|
2411
+ Types::Registry.parameter(param.name, resolve_type_ref(param.type, type_params:))
2412
+ end
2413
+ return Types::Registry.function(nil, params:, return_type: resolve_type_ref(type_ref.return_type, type_params:))
2408
2414
  end
2409
2415
 
2410
- def resolve_type_ref(type_ref, type_params: current_type_params)
2411
- if type_ref.is_a?(AST::FunctionType)
2412
- params = type_ref.params.map do |param|
2413
- Types::Registry.parameter(param.name, resolve_type_ref(param.type, type_params:))
2414
- end
2415
- return Types::Registry.function(nil, params:, return_type: resolve_type_ref(type_ref.return_type, type_params:))
2416
+ if type_ref.is_a?(AST::ProcType)
2417
+ params = type_ref.params.map do |param|
2418
+ Types::Registry.parameter(param.name, resolve_type_ref(param.type, type_params:))
2416
2419
  end
2420
+ return Types::Registry.proc(params:, return_type: resolve_type_ref(type_ref.return_type, type_params:))
2421
+ end
2417
2422
 
2418
- if type_ref.is_a?(AST::ProcType)
2419
- params = type_ref.params.map do |param|
2420
- Types::Registry.parameter(param.name, resolve_type_ref(param.type, type_params:))
2423
+ if type_ref.is_a?(AST::DynType)
2424
+ interface = resolve_interface_ref(type_ref.interface)
2425
+ raise LoweringError.new("generic interface requires type arguments", line: 0, column: 0, path: @ctx.current_analysis_path) if interface.respond_to?(:instantiate)
2426
+ type_arguments = interface.respond_to?(:type_arguments) ? (interface.type_arguments || []) : []
2427
+ return Types::Dyn.new(interface, type_arguments)
2428
+ end
2429
+
2430
+ if type_ref.is_a?(AST::TupleType)
2431
+ names = []
2432
+ element_types = []
2433
+ type_ref.element_types.each do |et|
2434
+ if et.is_a?(AST::Argument)
2435
+ names << et.name
2436
+ element_types << resolve_type_ref(et.value, type_params:)
2437
+ else
2438
+ names << nil
2439
+ element_types << resolve_type_ref(et, type_params:)
2421
2440
  end
2422
- return Types::Registry.proc(params:, return_type: resolve_type_ref(type_ref.return_type, type_params:))
2423
2441
  end
2442
+ has_named = names.any?
2443
+ return Types::Registry.tuple(element_types, field_names: has_named ? names : nil)
2444
+ end
2424
2445
 
2425
- if type_ref.is_a?(AST::DynType)
2426
- interface = resolve_interface_ref(type_ref.interface)
2427
- raise LoweringError.new("generic interface requires type arguments", line: 0, column: 0, path: @ctx.current_analysis_path) if interface.respond_to?(:instantiate)
2428
- type_arguments = interface.respond_to?(:type_arguments) ? (interface.type_arguments || []) : []
2429
- return Types::Dyn.new(interface, type_arguments)
2430
- end
2446
+ parts = type_ref.name.parts
2447
+ base = if type_ref.arguments.any?
2448
+ name = parts.join(".")
2449
+ args = type_ref.arguments.map { |argument| resolve_type_argument(argument.value, type_params:) }
2450
+ if name != "ref" && args.any? { |argument| contains_ref_type?(argument) && !stored_ref_supported_type?(argument) }
2451
+ raise LoweringError.new("ref types cannot be nested inside #{name}", line: 0, column: 0, path: @ctx.current_analysis_path)
2452
+ end
2453
+ if name == "Task"
2454
+ validate_generic_type!(name, args)
2455
+ Types::Registry.task(args.fetch(0))
2456
+ elsif (generic_type = resolve_named_generic_type(parts))
2457
+ generic_type.instantiate(args)
2458
+ elsif name == "span"
2459
+ Types::Registry.span(args.fetch(0))
2460
+ elsif name == "SoA"
2461
+ validate_generic_type!(name, args)
2462
+ Types::Registry.soa(args.fetch(0), count: args.fetch(1).value)
2463
+ elsif name == "simd"
2464
+ validate_generic_type!(name, args)
2465
+ Types::Registry.simd(args.fetch(0), lane_count: args.fetch(1).value)
2466
+ else
2467
+ validate_generic_type!(name, args)
2468
+ args = [type_ref.lifetime] + args if name == "ref" && type_ref.lifetime
2469
+ Types::Registry.generic_instance(name, args)
2470
+ end
2471
+ elsif parts.length == 1 && type_params.key?(parts.first)
2472
+ type_params.fetch(parts.first)
2473
+ elsif parts.length == 1
2474
+ type = @ctx.types[parts.first]
2475
+ raise LoweringError.new("unknown type #{parts.first}", line: 0, column: 0, path: @ctx.current_analysis_path) unless type
2476
+ raise LoweringError.new("generic type #{parts.first} requires type arguments", line: 0, column: 0, path: @ctx.current_analysis_path) if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
2477
+
2478
+ type
2479
+ elsif parts.length >= 2
2480
+ type = resolve_nested_type_ref(parts)
2481
+
2482
+ unless type
2483
+ if @ctx.imports.key?(parts.first)
2484
+ imported_module = @ctx.imports.fetch(parts.first)
2485
+ if imported_module.private_type?(parts.last)
2486
+ raise LoweringError.new("#{parts.first}.#{parts.last} is private to module #{imported_module.name}", line: 0, column: 0, path: @ctx.current_analysis_path)
2487
+ end
2431
2488
 
2432
- if type_ref.is_a?(AST::TupleType)
2433
- names = []
2434
- element_types = []
2435
- type_ref.element_types.each do |et|
2436
- if et.is_a?(AST::Argument)
2437
- names << et.name
2438
- element_types << resolve_type_ref(et.value, type_params:)
2489
+ type = imported_module.types[parts.last]
2490
+ raise LoweringError.new("unknown type #{type_ref.name}", line: 0, column: 0, path: @ctx.current_analysis_path) unless type
2491
+ raise LoweringError.new("generic type #{type_ref.name} requires type arguments", line: 0, column: 0, path: @ctx.current_analysis_path) if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
2492
+ elsif @type_resolution_env && (field_type = resolve_field_handle_type_ref(parts))
2493
+ type = field_type
2439
2494
  else
2440
- names << nil
2441
- element_types << resolve_type_ref(et, type_params:)
2495
+ raise LoweringError.new("unknown type #{type_ref.name}", line: 0, column: 0, path: @ctx.current_analysis_path)
2442
2496
  end
2443
2497
  end
2444
- has_named = names.any?
2445
- return Types::Registry.tuple(element_types, field_names: has_named ? names : nil)
2446
- end
2447
-
2448
- parts = type_ref.name.parts
2449
- base = if type_ref.arguments.any?
2450
- name = parts.join(".")
2451
- args = type_ref.arguments.map { |argument| resolve_type_argument(argument.value, type_params:) }
2452
- if name != "ref" && args.any? { |argument| contains_ref_type?(argument) && !stored_ref_supported_type?(argument) }
2453
- raise LoweringError.new("ref types cannot be nested inside #{name}", line: 0, column: 0, path: @ctx.current_analysis_path)
2454
- end
2455
- if name == "Task"
2456
- validate_generic_type!(name, args)
2457
- Types::Registry.task(args.fetch(0))
2458
- elsif (generic_type = resolve_named_generic_type(parts))
2459
- generic_type.instantiate(args)
2460
- elsif name == "span"
2461
- Types::Registry.span(args.fetch(0))
2462
- elsif name == "SoA"
2463
- validate_generic_type!(name, args)
2464
- Types::Registry.soa(args.fetch(0), count: args.fetch(1).value)
2465
- elsif name == "simd"
2466
- validate_generic_type!(name, args)
2467
- Types::Registry.simd(args.fetch(0), lane_count: args.fetch(1).value)
2468
- else
2469
- validate_generic_type!(name, args)
2470
- args = [type_ref.lifetime] + args if name == "ref" && type_ref.lifetime
2471
- Types::Registry.generic_instance(name, args)
2472
- end
2473
- elsif parts.length == 1 && type_params.key?(parts.first)
2474
- type_params.fetch(parts.first)
2475
- elsif parts.length == 1
2476
- type = @ctx.types[parts.first]
2477
- raise LoweringError.new("unknown type #{parts.first}", line: 0, column: 0, path: @ctx.current_analysis_path) unless type
2478
- raise LoweringError.new("generic type #{parts.first} requires type arguments", line: 0, column: 0, path: @ctx.current_analysis_path) if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
2479
-
2480
- type
2481
- elsif parts.length >= 2
2482
- type = resolve_nested_type_ref(parts)
2483
-
2484
- unless type
2485
- if @ctx.imports.key?(parts.first)
2486
- imported_module = @ctx.imports.fetch(parts.first)
2487
- if imported_module.private_type?(parts.last)
2488
- raise LoweringError.new("#{parts.first}.#{parts.last} is private to module #{imported_module.name}", line: 0, column: 0, path: @ctx.current_analysis_path)
2489
- end
2490
-
2491
- type = imported_module.types[parts.last]
2492
- raise LoweringError.new("unknown type #{type_ref.name}", line: 0, column: 0, path: @ctx.current_analysis_path) unless type
2493
- raise LoweringError.new("generic type #{type_ref.name} requires type arguments", line: 0, column: 0, path: @ctx.current_analysis_path) if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
2494
- elsif @type_resolution_env && (field_type = resolve_field_handle_type_ref(parts))
2495
- type = field_type
2496
- else
2497
- raise LoweringError.new("unknown type #{type_ref.name}", line: 0, column: 0, path: @ctx.current_analysis_path)
2498
- end
2499
- end
2500
-
2501
- type
2502
- else
2503
- raise LoweringError.new("unknown type #{type_ref.name}", line: 0, column: 0, path: @ctx.current_analysis_path)
2504
- end
2505
-
2506
- raise LoweringError.new("ref types are non-null and cannot be nullable", line: 0, column: 0, path: @ctx.current_analysis_path) if type_ref.nullable && ref_type?(base)
2507
-
2508
- type_ref.nullable ? Types::Registry.nullable(base) : base
2509
- end
2510
-
2511
- def resolve_nested_type_ref(parts)
2512
- current = @ctx.types[parts.first]
2513
- return nil unless current.is_a?(Types::Struct) || current.is_a?(Types::GenericStructDefinition)
2514
-
2515
- parts[1..].each do |part|
2516
- nested = current.respond_to?(:nested_types) ? current.nested_types[part] : nil
2517
- return nil unless nested
2518
- current = nested
2519
- end
2520
- current
2521
- end
2522
-
2523
- def resolve_named_generic_type(parts)
2524
- if parts.length == 1
2525
- type = @ctx.types[parts.first]
2526
- return type if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
2527
- elsif parts.length >= 2
2528
- type = resolve_nested_type_ref(parts)
2529
- return type if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
2530
- if @ctx.imports.key?(parts.first)
2531
- type = @ctx.imports.fetch(parts.first).types[parts.last]
2532
- return type if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
2533
- end
2498
+
2499
+ type
2500
+ else
2501
+ raise LoweringError.new("unknown type #{type_ref.name}", line: 0, column: 0, path: @ctx.current_analysis_path)
2534
2502
  end
2535
2503
 
2536
- nil
2537
- end
2504
+ raise LoweringError.new("ref types are non-null and cannot be nullable", line: 0, column: 0, path: @ctx.current_analysis_path) if type_ref.nullable && ref_type?(base)
2538
2505
 
2539
- # Resolves a bare dotted reflection type ref `field.type` (where `field` is
2540
- # a compile-time `field_handle` bound in the active inline-for env) to the
2541
- # field's concrete type. Mirrors the sema-side `resolve_compile_time_type_ref`.
2542
- def resolve_field_handle_type_ref(parts)
2543
- return nil unless parts.length == 2 && parts.last == "type"
2506
+ type_ref.nullable ? Types::Registry.nullable(base) : base
2507
+ end
2544
2508
 
2545
- binding = lookup_value(parts.first, @type_resolution_env)
2546
- handle = binding && binding[:const_value]
2547
- return nil unless handle.is_a?(Types::FieldHandle)
2509
+ def resolve_nested_type_ref(parts)
2510
+ current = @ctx.types[parts.first]
2511
+ return nil unless current.is_a?(Types::Struct) || current.is_a?(Types::GenericStructDefinition)
2548
2512
 
2549
- # Use the struct's already-resolved field type (module-independent) rather
2550
- # than re-resolving the field's declared TypeRef, which would look up a
2551
- # user struct name in this (std) module's scope and fail.
2552
- handle.struct_handle.struct_type.field(handle.field_name)
2513
+ parts[1..].each do |part|
2514
+ nested = current.respond_to?(:nested_types) ? current.nested_types[part] : nil
2515
+ return nil unless nested
2516
+ current = nested
2553
2517
  end
2518
+ current
2519
+ end
2554
2520
 
2555
- def infer_field_handle_member_type(expression)
2556
- case expression.member
2557
- when "name" then @ctx.types["str"]
2558
- when "type"
2559
- handle = compile_time_const_value(expression.receiver, env: nil)
2560
- return @error_type unless handle.is_a?(Types::FieldHandle)
2561
-
2562
- resolve_type_ref(handle.field_declaration.type)
2563
- else
2564
- @error_type
2521
+ def resolve_named_generic_type(parts)
2522
+ if parts.length == 1
2523
+ type = @ctx.types[parts.first]
2524
+ return type if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
2525
+ elsif parts.length >= 2
2526
+ type = resolve_nested_type_ref(parts)
2527
+ return type if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
2528
+ if @ctx.imports.key?(parts.first)
2529
+ type = @ctx.imports.fetch(parts.first).types[parts.last]
2530
+ return type if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
2565
2531
  end
2566
2532
  end
2567
2533
 
2568
- def infer_member_handle_member_type(expression)
2569
- case expression.member
2570
- when "name" then @ctx.types["str"]
2571
- when "value" then @ctx.types["int"]
2572
- else @error_type
2573
- end
2534
+ nil
2535
+ end
2536
+
2537
+ # Resolves a bare dotted reflection type ref `field.type` (where `field` is
2538
+ # a compile-time `field_handle` bound in the active inline-for env) to the
2539
+ # field's concrete type. Mirrors the sema-side `resolve_compile_time_type_ref`.
2540
+ def resolve_field_handle_type_ref(parts)
2541
+ return nil unless parts.length == 2 && parts.last == "type"
2542
+
2543
+ binding = lookup_value(parts.first, @type_resolution_env)
2544
+ handle = binding && binding[:const_value]
2545
+ return nil unless handle.is_a?(Types::FieldHandle)
2546
+
2547
+ # Use the struct's already-resolved field type (module-independent) rather
2548
+ # than re-resolving the field's declared TypeRef, which would look up a
2549
+ # user struct name in this (std) module's scope and fail.
2550
+ handle.struct_handle.struct_type.field(handle.field_name)
2551
+ end
2552
+
2553
+ def infer_field_handle_member_type(expression)
2554
+ case expression.member
2555
+ when "name" then @ctx.types["str"]
2556
+ when "type"
2557
+ handle = compile_time_const_value(expression.receiver, env: nil)
2558
+ return @error_type unless handle.is_a?(Types::FieldHandle)
2559
+
2560
+ resolve_type_ref(handle.field_declaration.type)
2561
+ else
2562
+ @error_type
2574
2563
  end
2564
+ end
2575
2565
 
2576
- def resolve_interface_ref(interface_ref)
2577
- parts = interface_ref.parts
2578
- interface = if parts.length == 1
2579
- @ctx.interfaces[parts.first]
2580
- elsif parts.length == 2 && @ctx.imports.key?(parts.first)
2581
- @ctx.imports.fetch(parts.first).interfaces[parts.last]
2582
- end
2583
- raise LoweringError.new("unknown interface #{interface_ref}", line: 0, column: 0, path: @ctx.current_analysis_path) unless interface
2566
+ def infer_member_handle_member_type(expression)
2567
+ case expression.member
2568
+ when "name" then @ctx.types["str"]
2569
+ when "value" then @ctx.types["int"]
2570
+ else @error_type
2571
+ end
2572
+ end
2584
2573
 
2585
- if interface_ref.type_arguments.any?
2586
- raise LoweringError.new("interface #{interface.name} is not generic", line: 0, column: 0, path: @ctx.current_analysis_path) unless interface.respond_to?(:instantiate)
2587
- type_args = interface_ref.type_arguments.map { |arg| resolve_type_ref(arg) }
2588
- interface.instantiate(type_args)
2589
- else
2590
- interface
2591
- end
2574
+ def resolve_interface_ref(interface_ref)
2575
+ parts = interface_ref.parts
2576
+ interface = if parts.length == 1
2577
+ @ctx.interfaces[parts.first]
2578
+ elsif parts.length == 2 && @ctx.imports.key?(parts.first)
2579
+ @ctx.imports.fetch(parts.first).interfaces[parts.last]
2580
+ end
2581
+ raise LoweringError.new("unknown interface #{interface_ref}", line: 0, column: 0, path: @ctx.current_analysis_path) unless interface
2582
+
2583
+ if interface_ref.type_arguments.any?
2584
+ raise LoweringError.new("interface #{interface.name} is not generic", line: 0, column: 0, path: @ctx.current_analysis_path) unless interface.respond_to?(:instantiate)
2585
+ type_args = interface_ref.type_arguments.map { |arg| resolve_type_ref(arg) }
2586
+ interface.instantiate(type_args)
2587
+ else
2588
+ interface
2592
2589
  end
2590
+ end
2593
2591
  end
2594
2592
  end