mt-lang 0.3.6 → 0.3.8

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2d5caebfa149a9d43d576f3cbf1b36b175ce70b28bfe474bc942fc2d11f0f1e8
4
- data.tar.gz: bf9f4a30b1cabadbed2b2d276dd29d567e118d008000791eefb2ec0e81f80c4f
3
+ metadata.gz: 180f49844f839480b6aed67ca33f5aef4532cb0a372dce913699b892fc85c4b1
4
+ data.tar.gz: f99ec00f1749c5142694ff93211a9745cc1cbd0c53e7a1b311125a53aafedfd0
5
5
  SHA512:
6
- metadata.gz: 681c1614c3449f16bb71fbb0f9ee7e9ec10420e302602b131c4ed813b087742e7474ff71e9111f5d35cb1e4315eb440c3c85e29d66e8c733159063cbe946ea01
7
- data.tar.gz: 6ea9caabdb7407f64d634f6576135df74e614878f81680777062c2e5f64f75278bb56f71bb48406153e40745e2d2b458e99c46193c9c85837c2b28b3b7aca4b4
6
+ metadata.gz: 8874f3444b514ac33d33949a01d438a5de17139443e618ba2fc282a47fefc9138df686493eb368b116802750a03b844535f881a2ba48c3fae8fbcfbb4062b608
7
+ data.tar.gz: 0172adf373b345e1b3d40f79c4c0f3e05e2da088053af78b582f258cff87312dd2bac29ba2434bafab09630e13455c7f75ea32cb33a517694206e46a4f2ce95e
data/lib/milk_tea/base.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  require "pathname"
4
4
 
5
5
  module MilkTea
6
- VERSION = "0.3.6"
6
+ VERSION = "0.3.8"
7
7
 
8
8
  def self.root
9
9
  @root ||= Pathname.new(File.expand_path("../..", __dir__))
@@ -32,7 +32,7 @@ module MilkTea
32
32
 
33
33
  visit = lambda do |aggregate_decl|
34
34
  return if visited[aggregate_decl.linkage_name]
35
- raise CBackendError, "cyclic aggregate dependency involving #{aggregate_decl.linkage_name}" if visiting[aggregate_decl.linkage_name]
35
+ raise CBackendError.new("cyclic aggregate dependency involving #{aggregate_decl.linkage_name}", line: 0, column: 0, path: @path) if visiting[aggregate_decl.linkage_name]
36
36
 
37
37
  visiting[aggregate_decl.linkage_name] = true
38
38
  aggregate_decl_dependencies(aggregate_decl).each do |dependency|
@@ -105,7 +105,7 @@ module MilkTea
105
105
  when IR::VariantLiteral
106
106
  emit_variant_literal(expression)
107
107
  else
108
- raise CBackendError, "unsupported IR expression #{expression.class.name}"
108
+ raise CBackendError.new("unsupported IR expression #{expression.class.name}", line: 0, column: 0, path: @path)
109
109
  end
110
110
  end
111
111
 
@@ -163,7 +163,7 @@ module MilkTea
163
163
  when "+", "-" then 9
164
164
  when "*", "/", "%" then 10
165
165
  else
166
- raise CBackendError, "unsupported binary operator #{operator}"
166
+ raise CBackendError.new("unsupported binary operator #{operator}", line: 0, column: 0, path: @path)
167
167
  end
168
168
  end
169
169
 
@@ -408,7 +408,7 @@ module MilkTea
408
408
  end
409
409
  return type.field(field_name) if type.respond_to?(:field)
410
410
 
411
- raise CBackendError, "unsupported aggregate field lookup for #{type}"
411
+ raise CBackendError.new("unsupported aggregate field lookup for #{type}", line: 0, column: 0, path: @path)
412
412
  end
413
413
 
414
414
  def emit_aggregate_field_initializer(type, field)
@@ -178,7 +178,7 @@ module MilkTea
178
178
  lines
179
179
  end
180
180
  else
181
- raise CBackendError, "unsupported IR statement #{statement.class.name}"
181
+ raise CBackendError.new("unsupported IR statement #{statement.class.name}", line: 0, column: 0, path: @path)
182
182
  end
183
183
  end
184
184
 
@@ -501,7 +501,7 @@ module MilkTea
501
501
  when IR::CheckedSpanIndex
502
502
  "#{checked_span_index_helper_name(expression.receiver_type)}(#{emit_expression(expression.receiver)}, #{emit_expression(expression.index)})"
503
503
  else
504
- raise CBackendError, "unsupported checked index alias expression #{expression.class.name}"
504
+ raise CBackendError.new("unsupported checked index alias expression #{expression.class.name}", line: 0, column: 0, path: @path)
505
505
  end
506
506
  end
507
507
 
@@ -533,19 +533,19 @@ module MilkTea
533
533
  def emit_for_clause_statement(statement)
534
534
  case statement
535
535
  when IR::LocalDecl
536
- raise CBackendError, "array for-loop init declarations are unsupported" if array_type?(statement.type)
536
+ raise CBackendError.new("array for-loop init declarations are unsupported", line: 0, column: 0, path: @path) if array_type?(statement.type)
537
537
 
538
538
  "#{c_declaration(statement.type, statement.linkage_name)} = #{emit_initializer(statement.value)}"
539
539
  when IR::Assignment
540
540
  if array_type?(statement.target.type) && statement.operator == "="
541
- raise CBackendError, "array for-loop assignment clauses are unsupported"
541
+ raise CBackendError.new("array for-loop assignment clauses are unsupported", line: 0, column: 0, path: @path)
542
542
  end
543
543
 
544
544
  "#{emit_expression(statement.target)} #{statement.operator} #{emit_expression(statement.value)}"
545
545
  when IR::ExpressionStmt
546
546
  emit_expression(statement.expression)
547
547
  else
548
- raise CBackendError, "unsupported for-loop clause #{statement.class.name}"
548
+ raise CBackendError.new("unsupported for-loop clause #{statement.class.name}", line: 0, column: 0, path: @path)
549
549
  end
550
550
  end
551
551
 
@@ -171,7 +171,7 @@ module MilkTea
171
171
  when Types::Handle
172
172
  "void*"
173
173
  else
174
- raise CBackendError, "unsupported C type #{type.class.name}"
174
+ raise CBackendError.new("unsupported C type #{type.class.name}", line: 0, column: 0, path: @path)
175
175
  end
176
176
  end
177
177
 
@@ -261,33 +261,33 @@ module MilkTea
261
261
  def generic_c_type(type)
262
262
  case type.name
263
263
  when "ptr"
264
- raise CBackendError, "ptr requires exactly one type argument" unless type.arguments.length == 1
264
+ raise CBackendError.new("ptr requires exactly one type argument", line: 0, column: 0, path: @path) unless type.arguments.length == 1
265
265
 
266
266
  "#{c_type(type.arguments.first)}*"
267
267
  when "const_ptr"
268
- raise CBackendError, "const_ptr requires exactly one type argument" unless type.arguments.length == 1
268
+ raise CBackendError.new("const_ptr requires exactly one type argument", line: 0, column: 0, path: @path) unless type.arguments.length == 1
269
269
 
270
270
  "const #{c_type(type.arguments.first)}*"
271
271
  when "own"
272
- raise CBackendError, "own requires exactly one type argument" unless type.arguments.length == 1
272
+ raise CBackendError.new("own requires exactly one type argument", line: 0, column: 0, path: @path) unless type.arguments.length == 1
273
273
 
274
274
  "#{c_type(type.arguments.first)}*"
275
275
  when "ref"
276
- raise CBackendError, "ref requires at least one type argument" unless [1, 2].include?(type.arguments.length)
276
+ raise CBackendError.new("ref requires at least one type argument", line: 0, column: 0, path: @path) unless [1, 2].include?(type.arguments.length)
277
277
 
278
278
  "#{c_type(type.arguments.length == 1 ? type.arguments.first : type.arguments[1])}*"
279
279
  when "array"
280
- raise CBackendError, "array requires exactly two type arguments" unless type.arguments.length == 2
280
+ raise CBackendError.new("array requires exactly two type arguments", line: 0, column: 0, path: @path) unless type.arguments.length == 2
281
281
 
282
282
  c_type(type.arguments.first)
283
283
  when "str_buffer"
284
- raise CBackendError, "str_buffer requires exactly one type argument" unless str_buffer_type?(type)
284
+ raise CBackendError.new("str_buffer requires exactly one type argument", line: 0, column: 0, path: @path) unless str_buffer_type?(type)
285
285
 
286
286
  str_buffer_type_name(type)
287
287
  when "atomic"
288
288
  "_Atomic #{c_type(type.arguments.first)}"
289
289
  else
290
- raise CBackendError, "unsupported generic C type #{type.name}"
290
+ raise CBackendError.new("unsupported generic C type #{type.name}", line: 0, column: 0, path: @path)
291
291
  end
292
292
  end
293
293
 
@@ -137,7 +137,12 @@ module MilkTea
137
137
  @graph.add_edge(match_id, next_id)
138
138
  else
139
139
  stmt.arms.each do |arm|
140
- arm_entry = build_block(arm.body, next_id, break_target:, continue_target:)
140
+ arm_body = if arm.respond_to?(:body)
141
+ arm.body
142
+ else
143
+ [MilkTea::AST::ExpressionStmt.new(expression: arm.value, line: arm.value.respond_to?(:line) ? arm.value.line : nil)]
144
+ end
145
+ arm_entry = build_block(arm_body, next_id, break_target:, continue_target:)
141
146
  if arm.binding_name
142
147
  binding_key = declaration_binding_key(arm, arm.binding_name)
143
148
  if binding_key
@@ -119,8 +119,8 @@ module MilkTea
119
119
  statement_position: false,
120
120
  )
121
121
  lowered.concat(setup)
122
- raise LoweringError, "foreign call used to initialize #{statement.name} must return a value" if call_type == @ctx.types.fetch("void")
123
- raise LoweringError, "consuming foreign calls must return void" unless release_assignments.empty?
122
+ raise LoweringError.new("foreign call used to initialize #{statement.name} must return a value", line: 0, column: 0, path: @ctx.current_analysis_path) if call_type == @ctx.types.fetch("void")
123
+ raise LoweringError.new("consuming foreign calls must return void", line: 0, column: 0, path: @ctx.current_analysis_path) unless release_assignments.empty?
124
124
 
125
125
  lowered << IR::Assignment.new(target:, operator: "=", value:)
126
126
  lowered.concat(cleanup_statements)
@@ -307,7 +307,7 @@ module MilkTea
307
307
  when AST::StaticAssert
308
308
  lowered.concat(lower_static_assert(statement))
309
309
  else
310
- raise LoweringError, "unsupported async cf statement #{statement.class.name}"
310
+ raise LoweringError.new("unsupported async cf statement #{statement.class.name}", line: 0, column: 0, path: @ctx.current_analysis_path)
311
311
  end
312
312
  end
313
313
 
@@ -412,7 +412,7 @@ module MilkTea
412
412
  def lower_async_cf_collection_for_stmt(statement, env:, frame_expr:, raw_frame_expr:, resume_linkage_name:, async_info:, active_defers:)
413
413
  iterable_type = infer_expression_type(statement.iterable, env:)
414
414
  element_type = collection_loop_type(iterable_type)
415
- raise LoweringError, "for loop expects start..stop, array[T, N], or span[T], got #{iterable_type}" unless element_type
415
+ raise LoweringError.new("for loop expects start..stop, array[T, N], or span[T], got #{iterable_type}", line: 0, column: 0, path: @ctx.current_analysis_path) unless element_type
416
416
 
417
417
  iterable_setup, prepared_iterable = prepare_expression_for_inline_lowering(statement.iterable, env:, expected_type: iterable_type)
418
418
  continue_label = fresh_c_temp_name(env, "loop_continue")
@@ -468,7 +468,7 @@ module MilkTea
468
468
  iterable = statement.iterables[index]
469
469
  iterable_type = infer_expression_type(iterable, env:)
470
470
  element_type = collection_loop_type(iterable_type)
471
- raise LoweringError, "parallel for loops expect arrays or spans for each iterable, got #{iterable_type}" unless element_type
471
+ raise LoweringError.new("parallel for loops expect arrays or spans for each iterable, got #{iterable_type}", line: 0, column: 0, path: @ctx.current_analysis_path) unless element_type
472
472
 
473
473
  {
474
474
  binding:,
@@ -744,7 +744,7 @@ module MilkTea
744
744
  when AST::StaticAssert
745
745
  lowered << lower_static_assert(statement, env: local_env)
746
746
  else
747
- raise LoweringError, "unsupported async non-await statement #{statement.class.name}"
747
+ raise LoweringError.new("unsupported async non-await statement #{statement.class.name}", line: 0, column: 0, path: @ctx.current_analysis_path)
748
748
  end
749
749
  end
750
750
 
@@ -837,7 +837,7 @@ module MilkTea
837
837
  def lower_async_collection_for_stmt(statement, env:, frame_expr:, raw_frame_expr:, async_info:, active_defers: [])
838
838
  iterable_type = infer_expression_type(statement.iterable, env:)
839
839
  element_type = collection_loop_type(iterable_type)
840
- raise LoweringError, "for loop expects start..stop, array[T, N], or span[T], got #{iterable_type}" unless element_type
840
+ raise LoweringError.new("for loop expects start..stop, array[T, N], or span[T], got #{iterable_type}", line: 0, column: 0, path: @ctx.current_analysis_path) unless element_type
841
841
 
842
842
  iterable_setup, prepared_iterable = prepare_expression_for_inline_lowering(statement.iterable, env:, expected_type: iterable_type)
843
843
  iterable_linkage_name = fresh_c_temp_name(env, "for_items")
@@ -896,7 +896,7 @@ module MilkTea
896
896
  iterable = statement.iterables[index]
897
897
  iterable_type = infer_expression_type(iterable, env:)
898
898
  element_type = collection_loop_type(iterable_type)
899
- raise LoweringError, "parallel for loops expect arrays or spans for each iterable, got #{iterable_type}" unless element_type
899
+ raise LoweringError.new("parallel for loops expect arrays or spans for each iterable, got #{iterable_type}", line: 0, column: 0, path: @ctx.current_analysis_path) unless element_type
900
900
 
901
901
  {
902
902
  binding:,
@@ -998,8 +998,8 @@ module MilkTea
998
998
  statement_position: false,
999
999
  )
1000
1000
  lowered.concat(setup)
1001
- raise LoweringError, "foreign call used in assignment must return a value" if call_type == @ctx.types.fetch("void")
1002
- raise LoweringError, "consuming foreign calls must return void" unless release_assignments.empty?
1001
+ raise LoweringError.new("foreign call used in assignment must return a value", line: 0, column: 0, path: @ctx.current_analysis_path) if call_type == @ctx.types.fetch("void")
1002
+ raise LoweringError.new("consuming foreign calls must return void", line: 0, column: 0, path: @ctx.current_analysis_path) unless release_assignments.empty?
1003
1003
 
1004
1004
  lowered << IR::Assignment.new(target:, operator: statement.operator, value:)
1005
1005
  lowered.concat(cleanup_statements)
@@ -1135,7 +1135,7 @@ module MilkTea
1135
1135
  expected_type: await_info[:task_type],
1136
1136
  )
1137
1137
  lowered.concat(prepared_setup)
1138
- raise LoweringError, "await does not support foreign task expressions" if foreign_call_info(prepared_task, env)
1138
+ raise LoweringError.new("await does not support foreign task expressions", line: 0, column: 0, path: @ctx.current_analysis_path) if foreign_call_info(prepared_task, env)
1139
1139
 
1140
1140
  task_expr = async_frame_field_expression(frame_expr, await_info[:field_name], await_info[:task_type])
1141
1141
  task_frame_expr = async_task_frame_expression(task_expr, await_info[:task_type])
@@ -1382,7 +1382,7 @@ module MilkTea
1382
1382
  [loop_exit_statement(target, local_defers:, outer_defers:)]
1383
1383
  else
1384
1384
  label = target[:label]
1385
- raise LoweringError, "structured loop exits with cleanup are unsupported" unless label
1385
+ raise LoweringError.new("structured loop exits with cleanup are unsupported", line: 0, column: 0, path: @ctx.current_analysis_path) unless label
1386
1386
 
1387
1387
  cleanup + [IR::GotoStmt.new(label:)]
1388
1388
  end
@@ -166,7 +166,7 @@ module MilkTea
166
166
  when AST::BreakStmt, AST::ContinueStmt, AST::StaticAssert, AST::PassStmt
167
167
  [statement]
168
168
  else
169
- raise LoweringError, "unsupported async statement #{statement.class.name}"
169
+ raise LoweringError.new("unsupported async statement #{statement.class.name}", line: 0, column: 0, path: @ctx.current_analysis_path)
170
170
  end
171
171
  end
172
172
 
@@ -210,10 +210,10 @@ module MilkTea
210
210
  end
211
211
  [setup, AST::Call.new(callee: target.callee, arguments: normalized_args)]
212
212
  else
213
- raise LoweringError, "unsupported assignment target #{target.class.name}"
213
+ raise LoweringError.new("unsupported assignment target #{target.class.name}", line: 0, column: 0, path: @ctx.current_analysis_path)
214
214
  end
215
215
  else
216
- raise LoweringError, "unsupported assignment target #{target.class.name}"
216
+ raise LoweringError.new("unsupported assignment target #{target.class.name}", line: 0, column: 0, path: @ctx.current_analysis_path)
217
217
  end
218
218
  end
219
219
 
@@ -372,7 +372,7 @@ module MilkTea
372
372
  AST::TypeRef.new(name: AST::QualifiedName.new(parts: [type.name]), arguments: [], nullable: false)
373
373
  when Types::Nullable
374
374
  inner = ast_type_ref_for(type.base)
375
- raise LoweringError, "nullable annotation is only valid for named/generic types" unless inner.is_a?(AST::TypeRef)
375
+ raise LoweringError.new("nullable annotation is only valid for named/generic types", line: 0, column: 0, path: @ctx.current_analysis_path) unless inner.is_a?(AST::TypeRef)
376
376
 
377
377
  AST::TypeRef.new(name: inner.name, arguments: inner.arguments, nullable: true)
378
378
  when Types::GenericInstance
@@ -420,7 +420,7 @@ module MilkTea
420
420
  return_type: ast_type_ref_for(type.return_type),
421
421
  )
422
422
  else
423
- raise LoweringError, "unsupported type for AST normalization #{type.class.name}"
423
+ raise LoweringError.new("unsupported type for AST normalization #{type.class.name}", line: 0, column: 0, path: @ctx.current_analysis_path)
424
424
  end
425
425
  end
426
426
 
@@ -8,7 +8,8 @@ module MilkTea
8
8
  def build_async_main_entrypoint(binding, _constructor_c_name, async_info)
9
9
  task_type = async_info[:task_type]
10
10
  signature = root_main_entrypoint_signature(binding)
11
- raise LoweringError, "async main entrypoint requires a supported signature" unless signature
11
+ raise LoweringError.new("async main entrypoint requires a supported signature",
12
+ line: 0, column: 0, path: @ctx.current_analysis_path) unless signature
12
13
 
13
14
  params, setup_statements, call_arguments, cleanup_statements = build_root_main_entrypoint_bridge(signature)
14
15
  body = []
@@ -229,7 +230,8 @@ module MilkTea
229
230
  cleanup,
230
231
  ]
231
232
  else
232
- raise LoweringError, "unsupported root main entrypoint bridge #{signature[:kind]}"
233
+ raise LoweringError.new("unsupported root main entrypoint bridge #{signature[:kind]}",
234
+ line: 0, column: 0, path: @ctx.current_analysis_path)
233
235
  end
234
236
  end
235
237
 
@@ -55,11 +55,13 @@ module MilkTea
55
55
  when AST::PassStmt
56
56
  nil
57
57
  when AST::BreakStmt
58
- raise LoweringError, "break must be inside a loop" unless loop_flow
58
+ raise LoweringError.new("break must be inside a loop",
59
+ line: statement.line, column: statement.column, path: @ctx.current_analysis_path) unless loop_flow
59
60
 
60
61
  lowered.concat(lower_loop_exit(loop_flow[:break_target], local_defers, loop_flow[:break_defers]))
61
62
  when AST::ContinueStmt
62
- raise LoweringError, "continue must be inside a loop" unless loop_flow
63
+ raise LoweringError.new("continue must be inside a loop",
64
+ line: statement.line, column: statement.column, path: @ctx.current_analysis_path) unless loop_flow
63
65
 
64
66
  lowered.concat(lower_loop_exit(loop_flow[:continue_target], local_defers, loop_flow[:continue_defers]))
65
67
  when AST::ReturnStmt
@@ -71,7 +73,8 @@ module MilkTea
71
73
  when AST::WhenStmt
72
74
  lower_block_when_stmt(statement, lowered:, local_env:, active_defers:, return_type:, loop_flow:, allow_return:)
73
75
  else
74
- raise LoweringError, "unsupported statement #{statement.class.name}"
76
+ raise LoweringError.new("unsupported statement #{statement.class.name}",
77
+ line: statement.line, column: statement.column, path: @ctx.current_analysis_path)
75
78
  end
76
79
  end
77
80
 
@@ -85,7 +88,8 @@ module MilkTea
85
88
  captures = proc_capture_entries(expression, env)
86
89
  captures.each do |capture|
87
90
  if ref_type?(capture[:type]) || contains_ref_type?(capture[:type])
88
- raise LoweringError, "proc capture #{capture[:name]} cannot use ref types"
91
+ raise LoweringError.new("proc capture #{capture[:name]} cannot use ref types",
92
+ line: expression.line, column: expression.column, path: @ctx.current_analysis_path)
89
93
  end
90
94
  end
91
95
 
@@ -279,7 +283,8 @@ module MilkTea
279
283
  when AST::ConstDecl
280
284
  lower_emitted_const(decl, env:)
281
285
  else
282
- raise LoweringError, "emit is not supported for #{decl.class.name}"
286
+ raise LoweringError.new("emit is not supported for #{decl.class.name}",
287
+ line: statement.line, column: statement.column, path: @ctx.current_analysis_path)
283
288
  end
284
289
  end
285
290
 
@@ -451,7 +456,8 @@ module MilkTea
451
456
  end
452
457
 
453
458
  def lower_block_return_stmt(statement, lowered:, local_defers:, local_env:, active_defers:, return_type:, allow_return:)
454
- raise LoweringError, "return is not allowed inside defer blocks" unless allow_return
459
+ raise LoweringError.new("return is not allowed inside defer blocks",
460
+ line: statement.line, column: statement.column, path: @ctx.current_analysis_path) unless allow_return
455
461
 
456
462
  value = nil
457
463
  prepared_setup = []
@@ -478,7 +484,8 @@ module MilkTea
478
484
  contextual_int_to_float: contextual_int_to_float_target?(return_type),
479
485
  ) : nil
480
486
  if prepared_cleanups.any? && cstr_trackable_type?(return_type)
481
- raise LoweringError, "formatted string temporaries cannot be returned as borrowed text; use std.fmt.format(f\"...\") when ownership must escape"
487
+ raise LoweringError.new("formatted string temporaries cannot be returned as borrowed text; use std.fmt.format(f\"...\") when ownership must escape",
488
+ line: statement.line, column: statement.column, path: @ctx.current_analysis_path)
482
489
  end
483
490
 
484
491
  prepared_cleanup_list = prepared_cleanups.flat_map(&:itself)
@@ -523,8 +530,10 @@ module MilkTea
523
530
  statement_position: false,
524
531
  )
525
532
  lowered.concat(setup)
526
- raise LoweringError, "foreign call used in assignment must return a value" if call_type == @ctx.types.fetch("void")
527
- raise LoweringError, "consuming foreign calls must return void" unless release_assignments.empty?
533
+ raise LoweringError.new("foreign call used in assignment must return a value",
534
+ line: statement.line, column: statement.column, path: @ctx.current_analysis_path) if call_type == @ctx.types.fetch("void")
535
+ raise LoweringError.new("consuming foreign calls must return void",
536
+ line: statement.line, column: statement.column, path: @ctx.current_analysis_path) unless release_assignments.empty?
528
537
 
529
538
  lowered << IR::Assignment.new(target:, operator: statement.operator, value:)
530
539
  lowered.concat(cleanup_statements)
@@ -713,8 +722,10 @@ module MilkTea
713
722
  statement_position: false,
714
723
  )
715
724
  lowered.concat(setup)
716
- raise LoweringError, "foreign call used to initialize #{statement.name} must return a value" if call_type == @ctx.types.fetch("void")
717
- raise LoweringError, "consuming foreign calls must return void" unless release_assignments.empty?
725
+ raise LoweringError.new("foreign call used to initialize #{statement.name} must return a value",
726
+ line: statement.line, column: statement.column, path: @ctx.current_analysis_path) if call_type == @ctx.types.fetch("void")
727
+ raise LoweringError.new("consuming foreign calls must return void",
728
+ line: statement.line, column: statement.column, path: @ctx.current_analysis_path) unless release_assignments.empty?
718
729
 
719
730
  lowered << IR::LocalDecl.new(name: decl_name, linkage_name:, type: storage_type, value:, line: statement.line, source_path: @ctx.current_analysis_path)
720
731
  lowered.concat(cleanup_statements)
@@ -927,16 +938,25 @@ module MilkTea
927
938
  nested_struct_c_name = nil
928
939
  nested_struct_type = nil
929
940
  if fields.size == 1 && fields.values.first.is_a?(Types::Struct)
930
- nested_struct_type = fields.values.first
931
- nested_struct_fields = nested_struct_type.fields
932
- single_field_name = fields.keys.first
933
- nested_struct_c_name = fresh_c_temp_name(arm_local_env, "match_struct")
934
- struct_expr = IR::Member.new(
935
- receiver: IR::Name.new(name: payload_c_name, type: payload_type, pointer: false),
936
- member: single_field_name,
937
- type: nested_struct_type,
938
- )
939
- arm_body_ir << IR::LocalDecl.new(name: nested_struct_c_name, linkage_name: nested_struct_c_name, type: nested_struct_type, value: struct_expr)
941
+ native_field = fields.keys.first
942
+ has_native_reference = arm.pattern.arguments.any? do |arg|
943
+ next false if !arg.name && arg.value.is_a?(AST::Identifier) && arg.value.name == "_"
944
+
945
+ name = arg.name || (arg.value.is_a?(AST::Identifier) ? arg.value.name : nil)
946
+ name == native_field
947
+ end
948
+ unless has_native_reference
949
+ nested_struct_type = fields.values.first
950
+ nested_struct_fields = nested_struct_type.fields
951
+ single_field_name = fields.keys.first
952
+ nested_struct_c_name = fresh_c_temp_name(arm_local_env, "match_struct")
953
+ struct_expr = IR::Member.new(
954
+ receiver: IR::Name.new(name: payload_c_name, type: payload_type, pointer: false),
955
+ member: single_field_name,
956
+ type: nested_struct_type,
957
+ )
958
+ arm_body_ir << IR::LocalDecl.new(name: nested_struct_c_name, linkage_name: nested_struct_c_name, type: nested_struct_type, value: struct_expr)
959
+ end
940
960
  end
941
961
 
942
962
  if arm.pattern.is_a?(AST::Call) && !arm.pattern.arguments.empty?