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 +4 -4
- data/lib/milk_tea/base.rb +1 -1
- data/lib/milk_tea/core/c_backend/aggregate_utils.rb +1 -1
- data/lib/milk_tea/core/c_backend/expressions.rb +3 -3
- data/lib/milk_tea/core/c_backend/statements.rb +5 -5
- data/lib/milk_tea/core/c_backend/type_system.rb +8 -8
- data/lib/milk_tea/core/lowering/async/lowering.rb +12 -12
- data/lib/milk_tea/core/lowering/async/normalization.rb +5 -5
- data/lib/milk_tea/core/lowering/async.rb +4 -2
- data/lib/milk_tea/core/lowering/block.rb +41 -21
- data/lib/milk_tea/core/lowering/calls.rb +25 -25
- data/lib/milk_tea/core/lowering/declarations.rb +2 -2
- data/lib/milk_tea/core/lowering/dyn.rb +2 -1
- data/lib/milk_tea/core/lowering/events.rb +1 -1
- data/lib/milk_tea/core/lowering/expressions.rb +26 -26
- data/lib/milk_tea/core/lowering/foreign_cstr.rb +2 -2
- data/lib/milk_tea/core/lowering/functions.rb +1 -1
- data/lib/milk_tea/core/lowering/loops.rb +6 -6
- data/lib/milk_tea/core/lowering/proc.rb +3 -3
- data/lib/milk_tea/core/lowering/resolve.rb +81 -81
- data/lib/milk_tea/core/lowering/str_buffer.rb +1 -1
- data/lib/milk_tea/core/lowering/utils.rb +22 -22
- data/lib/milk_tea/core/lowering.rb +4 -2
- data/std/parse.mt +13 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3f5f1a4cb47c9822d4aef3caefdd90aca32171fe59775d7906ab9c1485a422cb
|
|
4
|
+
data.tar.gz: 72e1d25c2082827fd40f723ac4f3b11045391dda39b1f8ef339aa5fac5e57611
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b6362b05316203c6b8d6e5c48cbfddad6351540096f9bc90580b8903866bb165e202cc654bd083c4e1de8786acb3f74e86ec85bbb020ee0e5c6874b46ef088fb
|
|
7
|
+
data.tar.gz: 0c7ffb83f660d7d1a30dbbb42713e5e798ff983795590d3e14074346d350f268184de505fc0091c14c975fcc7d141039368e652a2f0540b533575dcf8a097389
|
data/lib/milk_tea/base.rb
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
123
|
-
raise LoweringError
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1002
|
-
raise LoweringError
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
527
|
-
|
|
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
|
|
717
|
-
|
|
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
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|