mt-lang 0.3.23 → 0.3.25

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 (85) 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 +2 -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 +965 -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/linter/flow_rules.rb +3 -3
  82. metadata +4 -5
  83. data/lib/milk_tea/core/cst_builder.rb +0 -19
  84. data/lib/milk_tea/core/lowering/async/lowering.rb +0 -1404
  85. data/lib/milk_tea/core/token_stream.rb +0 -30
@@ -1,222 +1,224 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MilkTea
4
- module LowererDeclarations
5
- def expanded_declarations
6
- @ctx.ast.declarations.flat_map do |decl|
7
- case decl
8
- when AST::WhenStmt
9
- val = compile_time_const_value(decl.discriminant)
10
- next [decl] if val.nil?
11
-
12
- chosen = decl.branches.find { |b| val == compile_time_const_value(b.pattern) }
13
- body = chosen ? chosen.body : (decl.else_body || [])
14
- body
15
- else
16
- [decl]
4
+ module Lowering
5
+ module Declarations
6
+ def expanded_declarations
7
+ @ctx.ast.declarations.flat_map do |decl|
8
+ case decl
9
+ when AST::WhenStmt
10
+ val = compile_time_const_value(decl.discriminant)
11
+ next [decl] if val.nil?
12
+
13
+ chosen = decl.branches.find { |b| val == compile_time_const_value(b.pattern) }
14
+ body = chosen ? chosen.body : (decl.else_body || [])
15
+ body
16
+ else
17
+ [decl]
18
+ end
17
19
  end
18
20
  end
19
- end
20
21
 
21
- def lower_constants
22
- expanded_declarations.grep(AST::ConstDecl).filter_map do |decl|
23
- type = @ctx.values.fetch(decl.name).type
24
- const_value = @ctx.values.fetch(decl.name).const_value
22
+ def lower_constants
23
+ expanded_declarations.grep(AST::ConstDecl).filter_map do |decl|
24
+ type = @ctx.values.fetch(decl.name).type
25
+ const_value = @ctx.values.fetch(decl.name).const_value
25
26
 
26
- next if type == Types::BUILTIN_TYPE_META_TYPE
27
+ next if type == Types::BUILTIN_TYPE_META_TYPE
27
28
 
28
- if const_value && (decl.value.is_a?(AST::Call) || decl.value.is_a?(AST::Specialization))
29
- value = lower_const_value_literal(type, const_value)
30
- elsif const_value && (decl.block_body || decl.value.is_a?(AST::ExpressionList))
31
- if const_value.is_a?(Array) && const_value.empty? && decl.value.is_a?(AST::ExpressionList) && !decl.value.elements.empty?
32
- value = lower_static_storage_initializer(decl.value, env: empty_env, expected_type: type)
33
- else
29
+ if const_value && (decl.value.is_a?(AST::Call) || decl.value.is_a?(AST::Specialization))
34
30
  value = lower_const_value_literal(type, const_value)
31
+ elsif const_value && (decl.block_body || decl.value.is_a?(AST::ExpressionList))
32
+ if const_value.is_a?(Array) && const_value.empty? && decl.value.is_a?(AST::ExpressionList) && !decl.value.elements.empty?
33
+ value = lower_static_storage_initializer(decl.value, env: empty_env, expected_type: type)
34
+ else
35
+ value = lower_const_value_literal(type, const_value)
36
+ end
37
+ elsif decl.block_body || decl.value.is_a?(AST::ExpressionList)
38
+ raise LoweringError.new("constant #{decl.name} has no compile-time value", line: decl.line, column: decl.column)
39
+ else
40
+ value = lower_static_storage_initializer(decl.value, env: empty_env, expected_type: type)
35
41
  end
36
- elsif decl.block_body || decl.value.is_a?(AST::ExpressionList)
37
- raise LoweringError.new("constant #{decl.name} has no compile-time value", line: decl.line, column: decl.column)
38
- else
39
- value = lower_static_storage_initializer(decl.value, env: empty_env, expected_type: type)
40
- end
41
42
 
42
- IR::Constant.new(name: decl.name, linkage_name: value_c_name(decl.name), type:, value:, line: decl.line, path: @ctx.current_analysis_path)
43
+ IR::Constant.new(name: decl.name, linkage_name: value_c_name(decl.name), type:, value:, line: decl.line, path: @ctx.current_analysis_path)
44
+ end
43
45
  end
44
- end
45
46
 
46
- def lower_const_value_literal(type, const_value)
47
- case const_value
48
- when Integer
49
- value = if type.respond_to?(:integer_width) && (width = type.integer_width) && width < 64
50
- mask = (1 << width) - 1
51
- masked = const_value & mask
52
- if type.respond_to?(:unsigned_integer?) && !type.unsigned_integer? && masked >= (1 << (width - 1))
53
- masked - (1 << width)
47
+ def lower_const_value_literal(type, const_value)
48
+ case const_value
49
+ when Integer
50
+ value = if type.respond_to?(:integer_width) && (width = type.integer_width) && width < 64
51
+ mask = (1 << width) - 1
52
+ masked = const_value & mask
53
+ if type.respond_to?(:unsigned_integer?) && !type.unsigned_integer? && masked >= (1 << (width - 1))
54
+ masked - (1 << width)
55
+ else
56
+ masked
57
+ end
54
58
  else
55
- masked
59
+ const_value
60
+ end
61
+ IR::IntegerLiteral.new(value:, type:)
62
+ when Float
63
+ IR::FloatLiteral.new(value: const_value, type:)
64
+ when String
65
+ IR::StringLiteral.new(value: const_value, type:, cstring: false)
66
+ when TrueClass, FalseClass
67
+ IR::BooleanLiteral.new(value: const_value, type:)
68
+ when Array
69
+ element_type = type.respond_to?(:arguments) ? type.arguments.first : @ctx.types["int"]
70
+ elements = const_value.map do |element|
71
+ lower_const_value_literal(element_type, element)
72
+ end
73
+ IR::ArrayLiteral.new(type:, elements:)
74
+ when Hash
75
+ fields = const_value.map do |name, field_value|
76
+ field_type = type.field(name)
77
+ raise LoweringError.new("constant struct field #{name} not found in #{type}", line: 0, column: 0, path: @ctx.current_analysis_path) unless field_type
78
+ IR::AggregateField.new(name:, value: lower_const_value_literal(field_type, field_value))
56
79
  end
80
+ IR::AggregateLiteral.new(type:, fields:)
57
81
  else
58
- const_value
82
+ raise LoweringError.new("unsupported const value type #{const_value.class}", line: 0, column: 0, path: @ctx.current_analysis_path)
59
83
  end
60
- IR::IntegerLiteral.new(value:, type:)
61
- when Float
62
- IR::FloatLiteral.new(value: const_value, type:)
63
- when String
64
- IR::StringLiteral.new(value: const_value, type:, cstring: false)
65
- when TrueClass, FalseClass
66
- IR::BooleanLiteral.new(value: const_value, type:)
67
- when Array
68
- element_type = type.respond_to?(:arguments) ? type.arguments.first : @ctx.types["int"]
69
- elements = const_value.map do |element|
70
- lower_const_value_literal(element_type, element)
71
- end
72
- IR::ArrayLiteral.new(type:, elements:)
73
- when Hash
74
- fields = const_value.map do |name, field_value|
75
- field_type = type.field(name)
76
- raise LoweringError.new("constant struct field #{name} not found in #{type}", line: 0, column: 0, path: @ctx.current_analysis_path) unless field_type
77
- IR::AggregateField.new(name:, value: lower_const_value_literal(field_type, field_value))
78
- end
79
- IR::AggregateLiteral.new(type:, fields:)
80
- else
81
- raise LoweringError.new("unsupported const value type #{const_value.class}", line: 0, column: 0, path: @ctx.current_analysis_path)
82
84
  end
83
- end
84
85
 
85
- def lower_globals
86
- expanded_declarations.filter_map do |decl|
87
- next unless decl.is_a?(AST::VarDecl) || decl.is_a?(AST::EventDecl)
86
+ def lower_globals
87
+ expanded_declarations.filter_map do |decl|
88
+ next unless decl.is_a?(AST::VarDecl) || decl.is_a?(AST::EventDecl)
88
89
 
89
- type = @ctx.values.fetch(decl.name).type
90
- ensure_event_runtime(type) if type.is_a?(Types::Event)
91
- value = if decl.is_a?(AST::VarDecl) && decl.value
92
- lower_static_storage_initializer(decl.value, env: empty_env, expected_type: type)
93
- else
94
- IR::ZeroInit.new(type: type)
90
+ type = @ctx.values.fetch(decl.name).type
91
+ ensure_event_runtime(type) if type.is_a?(Types::Event)
92
+ value = if decl.is_a?(AST::VarDecl) && decl.value
93
+ lower_static_storage_initializer(decl.value, env: empty_env, expected_type: type)
94
+ else
95
+ IR::ZeroInit.new(type: type)
96
+ end
97
+ IR::Global.new(name: decl.name, linkage_name: value_c_name(decl.name), type:, value:)
95
98
  end
96
- IR::Global.new(name: decl.name, linkage_name: value_c_name(decl.name), type:, value:)
97
99
  end
98
- end
99
100
 
100
- def lower_opaques
101
- expanded_declarations.grep(AST::OpaqueDecl).map do |decl|
102
- opaque_type = @ctx.opaque_types.fetch(decl.name)
103
- IR::OpaqueDecl.new(
104
- name: decl.name,
105
- linkage_name: opaque_c_type_name(opaque_type),
106
- forward_declarable: opaque_forward_declarable?(opaque_type),
107
- source_module: @ctx.module_name,
108
- )
109
- end
110
- end
111
-
112
- def lower_imported_external_opaques
113
- each_raw_module_analysis.flat_map do |analysis|
114
- analysis.ast.declarations.grep(AST::OpaqueDecl).filter_map do |decl|
115
- opaque_type = analysis.types.fetch(decl.name)
116
- next unless forward_declarable_external_opaque?(opaque_type)
117
-
118
- IR::OpaqueDecl.new(name: decl.name, linkage_name: opaque_c_type_name(opaque_type), forward_declarable: true, source_module: analysis.module_name)
101
+ def lower_opaques
102
+ expanded_declarations.grep(AST::OpaqueDecl).map do |decl|
103
+ opaque_type = @ctx.opaque_types.fetch(decl.name)
104
+ IR::OpaqueDecl.new(
105
+ name: decl.name,
106
+ linkage_name: opaque_c_type_name(opaque_type),
107
+ forward_declarable: opaque_forward_declarable?(opaque_type),
108
+ source_module: @ctx.module_name,
109
+ )
119
110
  end
120
- end.uniq { |decl| decl.linkage_name }
121
- end
122
-
123
- def lower_static_asserts
124
- expanded_declarations.grep(AST::StaticAssert).map do |statement|
125
- lower_static_assert(statement, env: empty_env)
126
111
  end
127
- end
128
112
 
129
- def lower_static_assert(statement, env:)
130
- condition_value = compile_time_const_value(statement.condition, env:)
131
- raise LoweringError.new("static_assert condition must lower to a compile-time bool constant", line: 0, column: 0, path: @ctx.current_analysis_path) unless condition_value == true || condition_value == false
113
+ def lower_imported_external_opaques
114
+ each_raw_module_analysis.flat_map do |analysis|
115
+ analysis.ast.declarations.grep(AST::OpaqueDecl).filter_map do |decl|
116
+ opaque_type = analysis.types.fetch(decl.name)
117
+ next unless forward_declarable_external_opaque?(opaque_type)
132
118
 
133
- IR::StaticAssert.new(
134
- condition: IR::BooleanLiteral.new(value: condition_value, type: @ctx.types.fetch("bool")),
135
- message: lower_expression(statement.message, env:, expected_type: @ctx.types.fetch("str")),
136
- )
137
- end
119
+ IR::OpaqueDecl.new(name: decl.name, linkage_name: opaque_c_type_name(opaque_type), forward_declarable: true, source_module: analysis.module_name)
120
+ end
121
+ end.uniq { |decl| decl.linkage_name }
122
+ end
138
123
 
139
- def lower_structs
140
- expanded_declarations.grep(AST::StructDecl).filter_map do |decl|
141
- next unless decl.type_params.empty?
124
+ def lower_static_asserts
125
+ expanded_declarations.grep(AST::StaticAssert).map do |statement|
126
+ lower_static_assert(statement, env: empty_env)
127
+ end
128
+ end
142
129
 
143
- results = []
144
- lower_one_struct(decl, decl.name, results)
145
- results
146
- end.flatten
147
- end
130
+ def lower_static_assert(statement, env:)
131
+ condition_value = compile_time_const_value(statement.condition, env:)
132
+ raise LoweringError.new("static_assert condition must lower to a compile-time bool constant", line: 0, column: 0, path: @ctx.current_analysis_path) unless condition_value == true || condition_value == false
148
133
 
149
- def lower_one_struct(decl, qualified_name, results)
150
- struct_type = @ctx.struct_types.fetch(qualified_name)
151
- fields = decl.fields.map do |field|
152
- IR::Field.new(name: field.name, type: struct_type.field(field.name))
153
- end
154
- decl.events.each do |event_decl|
155
- event_type = struct_type.event(event_decl.name)
156
- ensure_event_runtime(event_type)
157
- fields << IR::Field.new(name: event_type.hidden_field_name, type: event_type)
134
+ IR::StaticAssert.new(
135
+ condition: IR::BooleanLiteral.new(value: condition_value, type: @ctx.types.fetch("bool")),
136
+ message: lower_expression(statement.message, env:, expected_type: @ctx.types.fetch("str")),
137
+ )
158
138
  end
159
139
 
160
- results << IR::StructDecl.new(name: decl.name, linkage_name: c_type_name(struct_type), fields:, packed: decl.packed, alignment: decl.alignment, source_module: @ctx.module_name)
140
+ def lower_structs
141
+ expanded_declarations.grep(AST::StructDecl).filter_map do |decl|
142
+ next unless decl.type_params.empty?
161
143
 
162
- decl.nested_types.each do |nested|
163
- lower_one_struct(nested, "#{qualified_name}.#{nested.name}", results)
144
+ results = []
145
+ lower_struct_decl(decl, decl.name, results)
146
+ results
147
+ end.flatten
164
148
  end
165
- end
166
149
 
167
- def lower_unions
168
- expanded_declarations.grep(AST::UnionDecl).map do |decl|
169
- union_type = @ctx.union_types.fetch(decl.name)
150
+ def lower_struct_decl(decl, qualified_name, results)
151
+ struct_type = @ctx.struct_types.fetch(qualified_name)
170
152
  fields = decl.fields.map do |field|
171
- IR::Field.new(name: field.name, type: union_type.field(field.name))
153
+ IR::Field.new(name: field.name, type: struct_type.field(field.name))
154
+ end
155
+ decl.events.each do |event_decl|
156
+ event_type = struct_type.event(event_decl.name)
157
+ ensure_event_runtime(event_type)
158
+ fields << IR::Field.new(name: event_type.hidden_field_name, type: event_type)
172
159
  end
173
- IR::UnionDecl.new(name: decl.name, linkage_name: c_type_name(union_type), fields:, source_module: @ctx.module_name)
174
- end
175
- end
176
160
 
177
- def lower_enums
178
- expanded_declarations.filter_map do |decl|
179
- case decl
180
- when AST::EnumDecl, AST::FlagsDecl
181
- enum_type = @ctx.types.fetch(decl.name)
182
- backing_type = enum_type.backing_type
183
- members = decl.members.map do |member|
184
- value = if member.value
185
- lower_expression(member.value, env: empty_env, expected_type: backing_type)
186
- else
187
- IR::IntegerLiteral.new(value: enum_type.member_value(member.name), type: backing_type)
188
- end
189
- IR::EnumMember.new(name: member.name, linkage_name: enum_member_c_name(enum_type, member.name), value:)
190
- end
161
+ results << IR::StructDecl.new(name: decl.name, linkage_name: c_type_name(struct_type), fields:, packed: decl.packed, alignment: decl.alignment, source_module: @ctx.module_name)
191
162
 
192
- IR::EnumDecl.new(
193
- name: decl.name,
194
- linkage_name: c_type_name(enum_type),
195
- backing_type:,
196
- members:,
197
- flags: decl.is_a?(AST::FlagsDecl),
198
- )
163
+ decl.nested_types.each do |nested|
164
+ lower_struct_decl(nested, "#{qualified_name}.#{nested.name}", results)
199
165
  end
200
166
  end
201
- end
202
167
 
203
- def lower_variants
204
- expanded_declarations.filter_map do |decl|
205
- next unless decl.is_a?(AST::VariantDecl)
168
+ def lower_unions
169
+ expanded_declarations.grep(AST::UnionDecl).map do |decl|
170
+ union_type = @ctx.union_types.fetch(decl.name)
171
+ fields = decl.fields.map do |field|
172
+ IR::Field.new(name: field.name, type: union_type.field(field.name))
173
+ end
174
+ IR::UnionDecl.new(name: decl.name, linkage_name: c_type_name(union_type), fields:, source_module: @ctx.module_name)
175
+ end
176
+ end
206
177
 
207
- variant_type = @ctx.types.fetch(decl.name)
208
- next if variant_type.is_a?(Types::GenericVariantDefinition)
178
+ def lower_enums
179
+ expanded_declarations.filter_map do |decl|
180
+ case decl
181
+ when AST::EnumDecl, AST::FlagsDecl
182
+ enum_type = @ctx.types.fetch(decl.name)
183
+ backing_type = enum_type.backing_type
184
+ members = decl.members.map do |member|
185
+ value = if member.value
186
+ lower_expression(member.value, env: empty_env, expected_type: backing_type)
187
+ else
188
+ IR::IntegerLiteral.new(value: enum_type.member_value(member.name), type: backing_type)
189
+ end
190
+ IR::EnumMember.new(name: member.name, linkage_name: enum_member_c_name(enum_type, member.name), value:)
191
+ end
192
+
193
+ IR::EnumDecl.new(
194
+ name: decl.name,
195
+ linkage_name: c_type_name(enum_type),
196
+ backing_type:,
197
+ members:,
198
+ flags: decl.is_a?(AST::FlagsDecl),
199
+ )
200
+ end
201
+ end
202
+ end
209
203
 
210
- outer_c = c_type_name(variant_type)
211
- arms = decl.arms.map do |arm|
212
- arm_c = "#{outer_c}_#{arm.name}"
213
- fields = arm.fields.map do |field|
214
- field_type = variant_type.arm(arm.name).fetch(field.name)
215
- IR::Field.new(name: field.name, type: field_type)
204
+ def lower_variants
205
+ expanded_declarations.filter_map do |decl|
206
+ next unless decl.is_a?(AST::VariantDecl)
207
+
208
+ variant_type = @ctx.types.fetch(decl.name)
209
+ next if variant_type.is_a?(Types::GenericVariantDefinition)
210
+
211
+ outer_c = c_type_name(variant_type)
212
+ arms = decl.arms.map do |arm|
213
+ arm_c = "#{outer_c}_#{arm.name}"
214
+ fields = arm.fields.map do |field|
215
+ field_type = variant_type.arm(arm.name).fetch(field.name)
216
+ IR::Field.new(name: field.name, type: field_type)
217
+ end
218
+ IR::VariantArm.new(name: arm.name, linkage_name: arm_c, fields:)
216
219
  end
217
- IR::VariantArm.new(name: arm.name, linkage_name: arm_c, fields:)
220
+ IR::VariantDecl.new(name: decl.name, linkage_name: outer_c, arms:, source_module: @ctx.module_name)
218
221
  end
219
- IR::VariantDecl.new(name: decl.name, linkage_name: outer_c, arms:, source_module: @ctx.module_name)
220
222
  end
221
223
  end
222
224
  end