mt-lang 0.3.24 → 0.3.26

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