mt-lang 0.3.5 → 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 +9 -4
- data/lib/milk_tea/core/c_backend/statements.rb +9 -5
- data/lib/milk_tea/core/c_backend/type_system.rb +8 -8
- data/lib/milk_tea/core/c_backend.rb +8 -0
- data/lib/milk_tea/core/compile_time.rb +19 -1
- data/lib/milk_tea/core/ir.rb +3 -1
- 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 +45 -24
- data/lib/milk_tea/core/lowering/calls.rb +25 -25
- data/lib/milk_tea/core/lowering/declarations.rb +4 -3
- 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 +84 -84
- 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/lib/milk_tea/core/semantic_analyzer/top_level.rb +23 -0
- data/lib/milk_tea/tooling/error_formatter.rb +18 -14
- data/std/mem/ptr.mt +9 -0
- 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|
|
|
@@ -33,7 +33,12 @@ module MilkTea
|
|
|
33
33
|
when IR::NullableSpanIndex
|
|
34
34
|
"#{nullable_span_index_helper_name(expression.receiver_type)}(#{emit_expression(expression.receiver)}, #{emit_expression(expression.index)})"
|
|
35
35
|
when IR::Call
|
|
36
|
-
|
|
36
|
+
if array_type?(expression.type)
|
|
37
|
+
location = [@source_path, @current_line && "line #{@current_line}"].compact.join(" ")
|
|
38
|
+
msg = "array-return call must be materialized before C emission"
|
|
39
|
+
msg += " (#{location})" unless location.empty?
|
|
40
|
+
raise CBackendError.new(msg, line: @current_line, path: @source_path)
|
|
41
|
+
end
|
|
37
42
|
|
|
38
43
|
emit_call_expression(expression)
|
|
39
44
|
when IR::Unary
|
|
@@ -100,7 +105,7 @@ module MilkTea
|
|
|
100
105
|
when IR::VariantLiteral
|
|
101
106
|
emit_variant_literal(expression)
|
|
102
107
|
else
|
|
103
|
-
raise CBackendError
|
|
108
|
+
raise CBackendError.new("unsupported IR expression #{expression.class.name}", line: 0, column: 0, path: @path)
|
|
104
109
|
end
|
|
105
110
|
end
|
|
106
111
|
|
|
@@ -158,7 +163,7 @@ module MilkTea
|
|
|
158
163
|
when "+", "-" then 9
|
|
159
164
|
when "*", "/", "%" then 10
|
|
160
165
|
else
|
|
161
|
-
raise CBackendError
|
|
166
|
+
raise CBackendError.new("unsupported binary operator #{operator}", line: 0, column: 0, path: @path)
|
|
162
167
|
end
|
|
163
168
|
end
|
|
164
169
|
|
|
@@ -403,7 +408,7 @@ module MilkTea
|
|
|
403
408
|
end
|
|
404
409
|
return type.field(field_name) if type.respond_to?(:field)
|
|
405
410
|
|
|
406
|
-
raise CBackendError
|
|
411
|
+
raise CBackendError.new("unsupported aggregate field lookup for #{type}", line: 0, column: 0, path: @path)
|
|
407
412
|
end
|
|
408
413
|
|
|
409
414
|
def emit_aggregate_field_initializer(type, field)
|
|
@@ -23,6 +23,10 @@ module MilkTea
|
|
|
23
23
|
indent = INDENT * level
|
|
24
24
|
aliases = checked_index_aliases_for_statement(statement)
|
|
25
25
|
alias_lines = emit_checked_index_alias_declarations(aliases, indent)
|
|
26
|
+
if statement.respond_to?(:line) && statement.line
|
|
27
|
+
@current_line = statement.line
|
|
28
|
+
@source_path ||= statement.source_path if statement.respond_to?(:source_path) && statement.source_path
|
|
29
|
+
end
|
|
26
30
|
line_directive = if @emit_line_directives && statement.respond_to?(:line) && statement.line
|
|
27
31
|
sp = (statement.respond_to?(:source_path) && statement.source_path) || @source_path
|
|
28
32
|
sp ? ["#line #{statement.line} #{sp.inspect}"] : []
|
|
@@ -174,7 +178,7 @@ module MilkTea
|
|
|
174
178
|
lines
|
|
175
179
|
end
|
|
176
180
|
else
|
|
177
|
-
raise CBackendError
|
|
181
|
+
raise CBackendError.new("unsupported IR statement #{statement.class.name}", line: 0, column: 0, path: @path)
|
|
178
182
|
end
|
|
179
183
|
end
|
|
180
184
|
|
|
@@ -497,7 +501,7 @@ module MilkTea
|
|
|
497
501
|
when IR::CheckedSpanIndex
|
|
498
502
|
"#{checked_span_index_helper_name(expression.receiver_type)}(#{emit_expression(expression.receiver)}, #{emit_expression(expression.index)})"
|
|
499
503
|
else
|
|
500
|
-
raise CBackendError
|
|
504
|
+
raise CBackendError.new("unsupported checked index alias expression #{expression.class.name}", line: 0, column: 0, path: @path)
|
|
501
505
|
end
|
|
502
506
|
end
|
|
503
507
|
|
|
@@ -529,19 +533,19 @@ module MilkTea
|
|
|
529
533
|
def emit_for_clause_statement(statement)
|
|
530
534
|
case statement
|
|
531
535
|
when IR::LocalDecl
|
|
532
|
-
raise CBackendError
|
|
536
|
+
raise CBackendError.new("array for-loop init declarations are unsupported", line: 0, column: 0, path: @path) if array_type?(statement.type)
|
|
533
537
|
|
|
534
538
|
"#{c_declaration(statement.type, statement.linkage_name)} = #{emit_initializer(statement.value)}"
|
|
535
539
|
when IR::Assignment
|
|
536
540
|
if array_type?(statement.target.type) && statement.operator == "="
|
|
537
|
-
raise CBackendError
|
|
541
|
+
raise CBackendError.new("array for-loop assignment clauses are unsupported", line: 0, column: 0, path: @path)
|
|
538
542
|
end
|
|
539
543
|
|
|
540
544
|
"#{emit_expression(statement.target)} #{statement.operator} #{emit_expression(statement.value)}"
|
|
541
545
|
when IR::ExpressionStmt
|
|
542
546
|
emit_expression(statement.expression)
|
|
543
547
|
else
|
|
544
|
-
raise CBackendError
|
|
548
|
+
raise CBackendError.new("unsupported for-loop clause #{statement.class.name}", line: 0, column: 0, path: @path)
|
|
545
549
|
end
|
|
546
550
|
end
|
|
547
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
|
|
|
@@ -55,6 +55,8 @@ module MilkTea
|
|
|
55
55
|
@checked_index_alias_id = 0
|
|
56
56
|
@loop_guard_id = 0
|
|
57
57
|
@emitted_span_type_names = Set.new
|
|
58
|
+
@source_path = program.source_path
|
|
59
|
+
@current_line = nil
|
|
58
60
|
end
|
|
59
61
|
|
|
60
62
|
def emit
|
|
@@ -218,10 +220,16 @@ module MilkTea
|
|
|
218
220
|
end
|
|
219
221
|
|
|
220
222
|
constants.each do |constant|
|
|
223
|
+
@current_line = constant.line if constant.line
|
|
224
|
+
@source_path ||= constant.source_path if constant.source_path
|
|
221
225
|
lines << "#{constant_storage(constant.type)} #{c_declaration(constant.type, constant.linkage_name)} = #{emit_initializer(constant.value)};"
|
|
222
226
|
end
|
|
223
227
|
@program.globals.each do |global|
|
|
224
228
|
next unless emitted_globals.include?(global)
|
|
229
|
+
if global.respond_to?(:line) && global.line
|
|
230
|
+
@current_line = global.line
|
|
231
|
+
@source_path ||= global.source_path if global.respond_to?(:source_path) && global.source_path
|
|
232
|
+
end
|
|
225
233
|
lines << "#{global_storage(global.type)} #{c_declaration(global.type, global.linkage_name)} = #{emit_initializer(global.value)};"
|
|
226
234
|
end
|
|
227
235
|
lines << "" unless constants.empty? && @program.globals.empty?
|
|
@@ -114,7 +114,12 @@ module MilkTea
|
|
|
114
114
|
else
|
|
115
115
|
@checker.instance_variable_get(:@ctx).types
|
|
116
116
|
end
|
|
117
|
-
|
|
117
|
+
callee_name = if call_expr.callee.is_a?(AST::Specialization) && call_expr.callee.callee.respond_to?(:name)
|
|
118
|
+
call_expr.callee.callee.name
|
|
119
|
+
elsif call_expr.callee.respond_to?(:name)
|
|
120
|
+
call_expr.callee.name
|
|
121
|
+
end
|
|
122
|
+
if callee_name && (type = types[callee_name]) && type.is_a?(Types::Struct)
|
|
118
123
|
fields = {}
|
|
119
124
|
call_expr.arguments.each do |argument|
|
|
120
125
|
val = evaluate_expression(argument.value, scopes:)
|
|
@@ -123,6 +128,19 @@ module MilkTea
|
|
|
123
128
|
end
|
|
124
129
|
next fields
|
|
125
130
|
end
|
|
131
|
+
|
|
132
|
+
if call_expr.callee.is_a?(AST::Specialization) && @checker.respond_to?(:resolve_type_expression)
|
|
133
|
+
resolved = @checker.send(:resolve_type_expression, call_expr.callee)
|
|
134
|
+
if resolved && @checker.respond_to?(:array_type?) && @checker.send(:array_type?, resolved)
|
|
135
|
+
values = []
|
|
136
|
+
call_expr.arguments.each do |argument|
|
|
137
|
+
val = evaluate_expression(argument.value, scopes:)
|
|
138
|
+
return nil unless val
|
|
139
|
+
values << val
|
|
140
|
+
end
|
|
141
|
+
next values
|
|
142
|
+
end
|
|
143
|
+
end
|
|
126
144
|
|
|
127
145
|
@checker.send(:evaluate_compile_time_const_value, call_expr, scopes:)
|
|
128
146
|
},
|
data/lib/milk_tea/core/ir.rb
CHANGED
|
@@ -6,7 +6,9 @@ module MilkTea
|
|
|
6
6
|
def initialize(module_name:, includes:, constants:, globals:, opaques:, structs:, unions:, enums:, variants:, static_asserts:, functions:, source_path: nil) = super
|
|
7
7
|
end
|
|
8
8
|
Include = Data.define(:header)
|
|
9
|
-
Constant = Data.define(:name, :linkage_name, :type, :value)
|
|
9
|
+
Constant = Data.define(:name, :linkage_name, :type, :value, :line, :source_path) do
|
|
10
|
+
def initialize(name:, linkage_name:, type:, value:, line: nil, source_path: nil) = super
|
|
11
|
+
end
|
|
10
12
|
Global = Data.define(:name, :linkage_name, :type, :value)
|
|
11
13
|
OpaqueDecl = Data.define(:name, :linkage_name, :forward_declarable, :source_module) do
|
|
12
14
|
def initialize(name:, linkage_name:, forward_declarable:, source_module: nil) = super
|
|
@@ -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
|
|
|
@@ -353,7 +358,8 @@ module MilkTea
|
|
|
353
358
|
value = lower_static_storage_initializer(decl.value, env:, expected_type: decl.type ? resolve_type_ref(decl.type) : nil)
|
|
354
359
|
type = decl.type ? resolve_type_ref(decl.type) : infer_expression_type(decl.value, env:)
|
|
355
360
|
linkage_name = value_c_name(decl.name)
|
|
356
|
-
constant = IR::Constant.new(name: decl.name, linkage_name:, type:, value
|
|
361
|
+
constant = IR::Constant.new(name: decl.name, linkage_name:, type:, value:,
|
|
362
|
+
line: decl.line, source_path: @ctx.current_analysis_path)
|
|
357
363
|
@artifacts.emitted_declarations << constant
|
|
358
364
|
[]
|
|
359
365
|
end
|
|
@@ -450,7 +456,8 @@ module MilkTea
|
|
|
450
456
|
end
|
|
451
457
|
|
|
452
458
|
def lower_block_return_stmt(statement, lowered:, local_defers:, local_env:, active_defers:, return_type:, allow_return:)
|
|
453
|
-
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
|
|
454
461
|
|
|
455
462
|
value = nil
|
|
456
463
|
prepared_setup = []
|
|
@@ -477,7 +484,8 @@ module MilkTea
|
|
|
477
484
|
contextual_int_to_float: contextual_int_to_float_target?(return_type),
|
|
478
485
|
) : nil
|
|
479
486
|
if prepared_cleanups.any? && cstr_trackable_type?(return_type)
|
|
480
|
-
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)
|
|
481
489
|
end
|
|
482
490
|
|
|
483
491
|
prepared_cleanup_list = prepared_cleanups.flat_map(&:itself)
|
|
@@ -511,7 +519,7 @@ module MilkTea
|
|
|
511
519
|
env: local_env,
|
|
512
520
|
expected_type: target.type,
|
|
513
521
|
allow_root_statement_foreign: true,
|
|
514
|
-
materialize_array_calls:
|
|
522
|
+
materialize_array_calls: true,
|
|
515
523
|
)
|
|
516
524
|
lowered.concat(prepared_setup)
|
|
517
525
|
if (foreign_call = foreign_call_info(prepared_value, local_env))
|
|
@@ -522,8 +530,10 @@ module MilkTea
|
|
|
522
530
|
statement_position: false,
|
|
523
531
|
)
|
|
524
532
|
lowered.concat(setup)
|
|
525
|
-
raise LoweringError
|
|
526
|
-
|
|
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?
|
|
527
537
|
|
|
528
538
|
lowered << IR::Assignment.new(target:, operator: statement.operator, value:)
|
|
529
539
|
lowered.concat(cleanup_statements)
|
|
@@ -700,7 +710,7 @@ module MilkTea
|
|
|
700
710
|
env: local_env,
|
|
701
711
|
expected_type: storage_type,
|
|
702
712
|
allow_root_statement_foreign: true,
|
|
703
|
-
materialize_array_calls:
|
|
713
|
+
materialize_array_calls: true,
|
|
704
714
|
)
|
|
705
715
|
lowered.concat(prepared_setup)
|
|
706
716
|
end
|
|
@@ -712,8 +722,10 @@ module MilkTea
|
|
|
712
722
|
statement_position: false,
|
|
713
723
|
)
|
|
714
724
|
lowered.concat(setup)
|
|
715
|
-
raise LoweringError
|
|
716
|
-
|
|
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?
|
|
717
729
|
|
|
718
730
|
lowered << IR::LocalDecl.new(name: decl_name, linkage_name:, type: storage_type, value:, line: statement.line, source_path: @ctx.current_analysis_path)
|
|
719
731
|
lowered.concat(cleanup_statements)
|
|
@@ -926,16 +938,25 @@ module MilkTea
|
|
|
926
938
|
nested_struct_c_name = nil
|
|
927
939
|
nested_struct_type = nil
|
|
928
940
|
if fields.size == 1 && fields.values.first.is_a?(Types::Struct)
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
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
|
|
939
960
|
end
|
|
940
961
|
|
|
941
962
|
if arm.pattern.is_a?(AST::Call) && !arm.pattern.arguments.empty?
|