mt-lang 0.3.6 → 0.3.7

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: 3f5f1a4cb47c9822d4aef3caefdd90aca32171fe59775d7906ab9c1485a422cb
4
+ data.tar.gz: 72e1d25c2082827fd40f723ac4f3b11045391dda39b1f8ef339aa5fac5e57611
5
5
  SHA512:
6
- metadata.gz: 681c1614c3449f16bb71fbb0f9ee7e9ec10420e302602b131c4ed813b087742e7474ff71e9111f5d35cb1e4315eb440c3c85e29d66e8c733159063cbe946ea01
7
- data.tar.gz: 6ea9caabdb7407f64d634f6576135df74e614878f81680777062c2e5f64f75278bb56f71bb48406153e40745e2d2b458e99c46193c9c85837c2b28b3b7aca4b4
6
+ metadata.gz: b6362b05316203c6b8d6e5c48cbfddad6351540096f9bc90580b8903866bb165e202cc654bd083c4e1de8786acb3f74e86ec85bbb020ee0e5c6874b46ef088fb
7
+ data.tar.gz: 0c7ffb83f660d7d1a30dbbb42713e5e798ff983795590d3e14074346d350f268184de505fc0091c14c975fcc7d141039368e652a2f0540b533575dcf8a097389
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.7"
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
 
@@ -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?
@@ -21,7 +21,7 @@ module MilkTea
21
21
  case kind
22
22
  when :function
23
23
  if callee_binding && foreign_function_binding?(callee_binding)
24
- raise LoweringError, "consuming foreign calls must be top-level expression statements" if foreign_call_consumes_binding?(callee_binding)
24
+ raise LoweringError.new("consuming foreign calls must be top-level expression statements", line: 0, column: 0, path: @ctx.current_analysis_path) if foreign_call_consumes_binding?(callee_binding)
25
25
 
26
26
  return lower_foreign_call_inline(expression, callee_binding, env:, type:)
27
27
  end
@@ -287,7 +287,7 @@ module MilkTea
287
287
  elsif receiver_type.is_a?(Types::Span)
288
288
  IR::NullableSpanIndex.new(receiver:, index:, receiver_type:, type:)
289
289
  else
290
- raise LoweringError, "get expects an array or span, got #{receiver_type}"
290
+ raise LoweringError.new("get expects an array or span, got #{receiver_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
291
291
  end
292
292
  when :ref_of
293
293
  argument = expression.arguments.fetch(0)
@@ -311,7 +311,7 @@ module MilkTea
311
311
  when :dyn_method
312
312
  lower_dyn_method_call(expression, receiver, callee_type, env:, type:)
313
313
  else
314
- raise LoweringError, "unsupported call kind #{kind}"
314
+ raise LoweringError.new("unsupported call kind #{kind}", line: 0, column: 0, path: @ctx.current_analysis_path)
315
315
  end
316
316
  end
317
317
 
@@ -488,7 +488,7 @@ module MilkTea
488
488
  def lower_foreign_call_components(foreign_call, env:, expected_type:, statement_position:)
489
489
  call = foreign_call.fetch(:call)
490
490
  binding = foreign_call.fetch(:binding)
491
- raise LoweringError, "consuming foreign calls must be top-level expression statements" if foreign_call_consumes_binding?(binding) && !statement_position
491
+ raise LoweringError.new("consuming foreign calls must be top-level expression statements", line: 0, column: 0, path: @ctx.current_analysis_path) if foreign_call_consumes_binding?(binding) && !statement_position
492
492
 
493
493
  previous_type_substitutions = @ctx.current_type_substitutions
494
494
  @ctx.current_type_substitutions = binding.type_substitutions
@@ -540,7 +540,7 @@ module MilkTea
540
540
  return [lowered, nil]
541
541
  end
542
542
 
543
- raise LoweringError, "consuming foreign calls must return void" unless release_assignments.empty?
543
+ raise LoweringError.new("consuming foreign calls must return void", line: 0, column: 0, path: @ctx.current_analysis_path) unless release_assignments.empty?
544
544
 
545
545
  if discard_result
546
546
  lowered << IR::ExpressionStmt.new(expression: lowered_call)
@@ -583,12 +583,12 @@ module MilkTea
583
583
 
584
584
  argument = call.arguments.fetch(index)
585
585
  unless argument.value.is_a?(AST::Identifier)
586
- raise LoweringError, "consuming foreign calls require bare nullable local or parameter bindings"
586
+ raise LoweringError.new("consuming foreign calls require bare nullable local or parameter bindings", line: 0, column: 0, path: @ctx.current_analysis_path)
587
587
  end
588
588
 
589
589
  lowered_binding = lookup_value(argument.value.name, env)
590
590
  unless lowered_binding && lowered_binding[:storage_type].is_a?(Types::Nullable) && lowered_binding[:storage_type].base == parameter.type
591
- raise LoweringError, "consuming foreign calls require bare nullable local or parameter bindings"
591
+ raise LoweringError.new("consuming foreign calls require bare nullable local or parameter bindings", line: 0, column: 0, path: @ctx.current_analysis_path)
592
592
  end
593
593
 
594
594
  lowered_binding.merge(name: argument.value.name)
@@ -757,14 +757,14 @@ module MilkTea
757
757
  converted = foreign_identity_projection_expression(lowered_value, parameter.boundary_type)
758
758
  return converted if converted
759
759
 
760
- raise LoweringError, "unsupported foreign boundary mapping #{parameter.type} as #{parameter.boundary_type}"
760
+ raise LoweringError.new("unsupported foreign boundary mapping #{parameter.type} as #{parameter.boundary_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
761
761
  end
762
762
  when :in
763
763
  lower_foreign_in_argument_value(parameter, argument, env:)
764
764
  when :out, :inout
765
765
  lower_foreign_pointer_argument_value(parameter, argument, env:)
766
766
  else
767
- raise LoweringError, "unsupported foreign passing mode #{parameter.passing_mode}"
767
+ raise LoweringError.new("unsupported foreign passing mode #{parameter.passing_mode}", line: 0, column: 0, path: @ctx.current_analysis_path)
768
768
  end
769
769
  end
770
770
 
@@ -779,7 +779,7 @@ module MilkTea
779
779
 
780
780
  data_expression = IR::Member.new(receiver: lowered_value, member: "data", type: pointer_to(public_element_type))
781
781
  converted_data = foreign_identity_projection_expression(data_expression, pointer_to(boundary_element_type))
782
- raise LoweringError, "unsupported foreign boundary mapping #{public_type} as #{boundary_type}" unless converted_data
782
+ raise LoweringError.new("unsupported foreign boundary mapping #{public_type} as #{boundary_type}", line: 0, column: 0, path: @ctx.current_analysis_path) unless converted_data
783
783
 
784
784
  len_expression = IR::Member.new(receiver: lowered_value, member: "len", type: @ctx.types.fetch("ptr_uint"))
785
785
  IR::AggregateLiteral.new(
@@ -799,7 +799,7 @@ module MilkTea
799
799
  converted = foreign_identity_projection_expression(address, parameter.boundary_type)
800
800
  return converted if converted
801
801
 
802
- raise LoweringError, "unsupported foreign pointer boundary mapping #{parameter.type} as #{parameter.boundary_type}"
802
+ raise LoweringError.new("unsupported foreign pointer boundary mapping #{parameter.type} as #{parameter.boundary_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
803
803
  end
804
804
 
805
805
  def foreign_slot_boundary_value_type(type)
@@ -841,7 +841,7 @@ module MilkTea
841
841
  converted = foreign_identity_projection_expression(address, parameter.boundary_type)
842
842
  return converted if converted
843
843
 
844
- raise LoweringError, "unsupported foreign in boundary mapping #{parameter.type} as #{parameter.boundary_type}"
844
+ raise LoweringError.new("unsupported foreign in boundary mapping #{parameter.type} as #{parameter.boundary_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
845
845
  end
846
846
 
847
847
  def lower_foreign_char_pointer_buffer_argument_value(parameter, argument, env:)
@@ -869,7 +869,7 @@ module MilkTea
869
869
  converted = foreign_identity_projection_expression(lowered_value, parameter.boundary_type)
870
870
  return converted if converted
871
871
 
872
- raise LoweringError, "unsupported foreign boundary mapping #{public_type} as #{parameter.boundary_type}"
872
+ raise LoweringError.new("unsupported foreign boundary mapping #{public_type} as #{parameter.boundary_type}", line: 0, column: 0, path: @ctx.current_analysis_path)
873
873
  end
874
874
 
875
875
  def lower_foreign_call_inline(expression, binding, env:, type:)
@@ -888,7 +888,7 @@ module MilkTea
888
888
  next unless total_references > 1
889
889
  next if duplicable_foreign_argument_expression?(expression.arguments.fetch(index).value)
890
890
 
891
- raise LoweringError, "foreign call #{binding.name} cannot be used inline because #{param_ast.name} is referenced multiple times in its mapping; use it as a statement, local initializer, assignment, or return expression"
891
+ raise LoweringError.new("foreign call #{binding.name} cannot be used inline because #{param_ast.name} is referenced multiple times in its mapping; use it as a statement, local initializer, assignment, or return expression", line: 0, column: 0, path: @ctx.current_analysis_path)
892
892
  end
893
893
 
894
894
  binding.ast.params.each_with_index do |param_ast, index|
@@ -896,13 +896,13 @@ module MilkTea
896
896
  next unless automatic_foreign_cstr_temp_needed?(parameter, expression.arguments.fetch(index).value, env:) ||
897
897
  automatic_foreign_cstr_list_temp_needed?(parameter, expression.arguments.fetch(index).value, env:)
898
898
 
899
- raise LoweringError, "foreign call #{binding.name} cannot be used inline because #{param_ast.name} needs temporary foreign text storage; use it as a statement, local initializer, assignment, or return expression"
899
+ raise LoweringError.new("foreign call #{binding.name} cannot be used inline because #{param_ast.name} needs temporary foreign text storage; use it as a statement, local initializer, assignment, or return expression", line: 0, column: 0, path: @ctx.current_analysis_path)
900
900
  end
901
901
 
902
902
  expression.arguments.drop(binding.type.params.length).each do |argument|
903
903
  next unless automatic_variadic_foreign_cstr_temp_needed?(argument.value, env:)
904
904
 
905
- raise LoweringError, "foreign call #{binding.name} cannot be used inline because a variadic argument needs temporary foreign text storage; use it as a statement, local initializer, assignment, or return expression"
905
+ raise LoweringError.new("foreign call #{binding.name} cannot be used inline because a variadic argument needs temporary foreign text storage; use it as a statement, local initializer, assignment, or return expression", line: 0, column: 0, path: @ctx.current_analysis_path)
906
906
  end
907
907
 
908
908
  binding.ast.params.each_with_index do |param_ast, index|
@@ -911,7 +911,7 @@ module MilkTea
911
911
  next unless parameter.passing_mode == :in
912
912
  next if addressable_storage_expression?(foreign_argument_expression(argument))
913
913
 
914
- raise LoweringError, "foreign call #{binding.name} cannot be used inline because #{param_ast.name} needs temporary in storage; use it as a statement, local initializer, assignment, or return expression"
914
+ raise LoweringError.new("foreign call #{binding.name} cannot be used inline because #{param_ast.name} needs temporary in storage; use it as a statement, local initializer, assignment, or return expression", line: 0, column: 0, path: @ctx.current_analysis_path)
915
915
  end
916
916
 
917
917
  replacements = {}
@@ -978,7 +978,7 @@ module MilkTea
978
978
  )
979
979
  return lowered_argument unless temporary_foreign_cstr_expression?(lowered_argument)
980
980
 
981
- raise LoweringError, "foreign variadic call cannot be used inline because an extra argument needs temporary foreign text storage; use it as a statement, local initializer, assignment, or return expression" unless lowered && cleanup
981
+ raise LoweringError.new("foreign variadic call cannot be used inline because an extra argument needs temporary foreign text storage; use it as a statement, local initializer, assignment, or return expression", line: 0, column: 0, path: @ctx.current_analysis_path) unless lowered && cleanup
982
982
 
983
983
  temp_name = fresh_c_temp_name(env, "foreign_arg")
984
984
  lowered << IR::LocalDecl.new(
@@ -1128,7 +1128,7 @@ module MilkTea
1128
1128
 
1129
1129
  case kind
1130
1130
  when :function
1131
- raise LoweringError, "consuming foreign calls must be top-level expression statements" if callee_binding && foreign_function_binding?(callee_binding) && foreign_call_consumes_binding?(callee_binding)
1131
+ raise LoweringError.new("consuming foreign calls must be top-level expression statements", line: 0, column: 0, path: @ctx.current_analysis_path) if callee_binding && foreign_function_binding?(callee_binding) && foreign_call_consumes_binding?(callee_binding)
1132
1132
 
1133
1133
  arguments = expression.arguments.map.with_index do |argument, index|
1134
1134
  expected_arg_type = index < callee_type.params.length ? callee_type.params[index].type : nil
@@ -1301,7 +1301,7 @@ module MilkTea
1301
1301
  )
1302
1302
  end
1303
1303
  else
1304
- raise LoweringError, "unsupported inline foreign mapping call kind #{kind}"
1304
+ raise LoweringError.new("unsupported inline foreign mapping call kind #{kind}", line: 0, column: 0, path: @ctx.current_analysis_path)
1305
1305
  end
1306
1306
  end
1307
1307
 
@@ -1537,9 +1537,9 @@ module MilkTea
1537
1537
 
1538
1538
  if (callable_resolution = resolve_specialized_callable_binding(expression, env:))
1539
1539
  callable_kind, function_binding, = callable_resolution
1540
- raise LoweringError, "specialized method must be called" if callable_kind == :method
1540
+ raise LoweringError.new("specialized method must be called", line: 0, column: 0, path: @ctx.current_analysis_path) if callable_kind == :method
1541
1541
 
1542
- raise LoweringError, "foreign function #{function_binding.name} cannot be used as a value" if foreign_function_binding?(function_binding)
1542
+ raise LoweringError.new("foreign function #{function_binding.name} cannot be used as a value", line: 0, column: 0, path: @ctx.current_analysis_path) if foreign_function_binding?(function_binding)
1543
1543
 
1544
1544
  if function_binding.external
1545
1545
  return IR::Name.new(name: external_function_c_name(function_binding), type:, pointer: false)
@@ -1552,9 +1552,9 @@ module MilkTea
1552
1552
  )
1553
1553
  end
1554
1554
 
1555
- raise LoweringError, "specialization #{expression.callee.name} must be called" if expression.callee.is_a?(AST::Identifier)
1555
+ raise LoweringError.new("specialization #{expression.callee.name} must be called", line: 0, column: 0, path: @ctx.current_analysis_path) if expression.callee.is_a?(AST::Identifier)
1556
1556
 
1557
- raise LoweringError, "unsupported specialization #{expression.class.name}"
1557
+ raise LoweringError.new("unsupported specialization #{expression.class.name}", line: 0, column: 0, path: @ctx.current_analysis_path)
1558
1558
  end
1559
1559
 
1560
1560
  def atomic_method_kind(receiver_type, name)
@@ -1602,7 +1602,7 @@ module MilkTea
1602
1602
  arg = lower_contextual_expression(expression.arguments.first.value, env:, expected_type: elem_type)
1603
1603
  IR::Call.new(callee: "__atomic_exchange_n", arguments: [addr, arg, seq_cst], type: elem_type)
1604
1604
  when :atomic_compare_exchange
1605
- raise LoweringError, "atomic compare_exchange is not yet implemented in the built-in surface; use std.sync.AtomicUint for compare-exchange operations"
1605
+ raise LoweringError.new("atomic compare_exchange is not yet implemented in the built-in surface; use std.sync.AtomicUint for compare-exchange operations", line: 0, column: 0, path: @ctx.current_analysis_path)
1606
1606
  end
1607
1607
  end
1608
1608