mt-lang 0.3.13 → 0.3.16
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/README.md +5 -5
- data/docs/index.html +31 -23
- data/docs/language-design.md +13 -17
- data/docs/language-manual.md +19 -7
- data/lib/milk_tea/base.rb +1 -1
- data/lib/milk_tea/core/ast.rb +2 -2
- data/lib/milk_tea/core/control_flow/builder.rb +62 -2
- data/lib/milk_tea/core/lowering/async/analysis.rb +3 -9
- data/lib/milk_tea/core/lowering/async/lowering.rb +2 -10
- data/lib/milk_tea/core/lowering/async/normalization.rb +2 -7
- data/lib/milk_tea/core/lowering/block.rb +1 -5
- data/lib/milk_tea/core/lowering/expressions.rb +47 -3
- data/lib/milk_tea/core/lowering/proc.rb +1 -5
- data/lib/milk_tea/core/lowering/resolve.rb +26 -2
- data/lib/milk_tea/core/lowering/scans.rb +3 -1
- data/lib/milk_tea/core/lowering/utils.rb +7 -28
- data/lib/milk_tea/core/parser/statements.rb +18 -12
- data/lib/milk_tea/core/pretty_printer/ast_formatter.rb +3 -11
- data/lib/milk_tea/core/semantic_analyzer/analysis_context.rb +2 -3
- data/lib/milk_tea/core/semantic_analyzer/flow_refinement.rb +1 -1
- data/lib/milk_tea/core/semantic_analyzer/function_binding.rb +1 -2
- data/lib/milk_tea/core/semantic_analyzer/nullability.rb +2 -4
- data/lib/milk_tea/core/semantic_analyzer/statements.rb +2 -8
- data/lib/milk_tea/core/semantic_analyzer/type_compatibility.rb +29 -2
- data/lib/milk_tea/core/types.rb +0 -6
- data/lib/milk_tea/tooling/linter/imports_platform.rb +2 -4
- data/lib/milk_tea/tooling/linter/release_rules.rb +1 -6
- data/lib/milk_tea/tooling/linter/source_helpers.rb +0 -6
- data/lib/milk_tea/tooling/linter/visitors.rb +4 -8
- data/lib/milk_tea/tooling/sexpr_dumper.rb +2 -0
- data/std/asset_pack.mt +1 -1
- data/std/async/libuv_runtime.mt +6 -6
- data/std/async/mailbox.mt +4 -4
- data/std/{cell.mt → box.mt} +9 -9
- data/std/cookie.mt +2 -2
- data/std/crypto.mt +1 -1
- data/std/curl/runtime.mt +10 -10
- data/std/fs.linux.mt +26 -26
- data/std/fs.windows.mt +22 -22
- data/std/goap.mt +2 -2
- data/std/http/server.mt +21 -21
- data/std/http.mt +14 -14
- data/std/jobs.mt +4 -4
- data/std/json.mt +5 -5
- data/std/log.mt +1 -1
- data/std/mem/tracking.mt +1 -1
- data/std/net/channel.mt +4 -4
- data/std/net/clock.mt +6 -6
- data/std/net/discovery.mt +7 -7
- data/std/net/lobby.mt +10 -10
- data/std/net/manager.mt +1 -1
- data/std/net/mux.mt +4 -4
- data/std/net/nat.mt +4 -4
- data/std/net/packet.mt +3 -3
- data/std/net/punch.mt +3 -3
- data/std/net/rpc.mt +3 -3
- data/std/net/session.mt +15 -15
- data/std/net/stun.mt +4 -4
- data/std/net/turn.mt +4 -4
- data/std/oauth2.mt +12 -12
- data/std/path.mt +8 -8
- data/std/process.mt +4 -4
- data/std/raylib/packed_assets.mt +5 -5
- data/std/serialize.mt +1 -1
- data/std/tar.mt +10 -10
- data/std/terminal.mt +18 -18
- data/std/tls.mt +8 -8
- data/std/uri.mt +1 -1
- data/std/utility.mt +1 -1
- metadata +3 -3
|
@@ -1506,10 +1506,54 @@ module MilkTea
|
|
|
1506
1506
|
return false unless receiver_type.is_a?(Types::VariantArmPayload)
|
|
1507
1507
|
|
|
1508
1508
|
outer = receiver_type.variant_type
|
|
1509
|
-
return
|
|
1510
|
-
return field_type == outer if outer.is_a?(Types::VariantInstance)
|
|
1509
|
+
return false unless outer.is_a?(Types::Variant) || outer.is_a?(Types::VariantInstance)
|
|
1511
1510
|
|
|
1512
|
-
|
|
1511
|
+
# The C backend pointer-breaks every cyclic field, including cycles that
|
|
1512
|
+
# run through generic instantiations such as `Option[Atom]` inside `Atom`.
|
|
1513
|
+
# Deref the access whenever the field type can reach the outer variant.
|
|
1514
|
+
type_reaches_target?(field_type, outer)
|
|
1515
|
+
end
|
|
1516
|
+
|
|
1517
|
+
def type_reaches_target?(type, target)
|
|
1518
|
+
type_reaches_target_with_visited?(type, target, {})
|
|
1519
|
+
end
|
|
1520
|
+
|
|
1521
|
+
def type_reaches_target_with_visited?(type, target, visited)
|
|
1522
|
+
return true if type == target
|
|
1523
|
+
return false if visited[type.object_id]
|
|
1524
|
+
|
|
1525
|
+
visited[type.object_id] = true
|
|
1526
|
+
reachability_children(type).any? do |child|
|
|
1527
|
+
type_reaches_target_with_visited?(child, target, visited)
|
|
1528
|
+
end
|
|
1529
|
+
end
|
|
1530
|
+
|
|
1531
|
+
# Structural expansion used by cyclic-field reachability. Mirrors the
|
|
1532
|
+
# CBackend's `aggregate_type_dependencies` so the deref injected for a
|
|
1533
|
+
# pointer-broken cyclic field agrees with the emitted C struct layout.
|
|
1534
|
+
def reachability_children(type)
|
|
1535
|
+
case type
|
|
1536
|
+
when Types::Nullable
|
|
1537
|
+
[type.base]
|
|
1538
|
+
when Types::GenericInstance
|
|
1539
|
+
if pointer_type?(type)
|
|
1540
|
+
[]
|
|
1541
|
+
elsif array_type?(type)
|
|
1542
|
+
[array_element_type(type)]
|
|
1543
|
+
else
|
|
1544
|
+
[]
|
|
1545
|
+
end
|
|
1546
|
+
when Types::Span
|
|
1547
|
+
[type.element_type]
|
|
1548
|
+
when Types::Struct, Types::StructInstance, Types::Union
|
|
1549
|
+
type.fields.values
|
|
1550
|
+
when Types::Variant, Types::VariantInstance
|
|
1551
|
+
type.arm_names.flat_map { |name| type.arm(name).values }
|
|
1552
|
+
when Types::VariantArmPayload
|
|
1553
|
+
type.fields.values
|
|
1554
|
+
else
|
|
1555
|
+
[]
|
|
1556
|
+
end
|
|
1513
1557
|
end
|
|
1514
1558
|
|
|
1515
1559
|
def lower_compile_time_handle_member(handle, member, type)
|
|
@@ -180,11 +180,7 @@ module MilkTea
|
|
|
180
180
|
when AST::ReturnStmt
|
|
181
181
|
collect_proc_captures_from_expression(statement.value, env, local_scopes, captures) if statement.value
|
|
182
182
|
when AST::DeferStmt
|
|
183
|
-
|
|
184
|
-
collect_proc_captures_from_statements(statement.body, env, local_scopes + [{}], captures)
|
|
185
|
-
else
|
|
186
|
-
collect_proc_captures_from_expression(statement.expression, env, local_scopes, captures)
|
|
187
|
-
end
|
|
183
|
+
collect_proc_captures_from_statements(statement.body, env, local_scopes + [{}], captures)
|
|
188
184
|
when AST::ExpressionStmt
|
|
189
185
|
collect_proc_captures_from_expression(statement.expression, env, local_scopes, captures)
|
|
190
186
|
when AST::BreakStmt, AST::ContinueStmt, AST::PassStmt
|
|
@@ -1137,9 +1137,33 @@ module MilkTea
|
|
|
1137
1137
|
return unless left_type.is_a?(Types::Primitive) && right_type.is_a?(Types::Primitive)
|
|
1138
1138
|
return unless left_type.integer? && right_type.integer?
|
|
1139
1139
|
return unless left_type.fixed_width_integer? && right_type.fixed_width_integer?
|
|
1140
|
-
return unless left_type.signed_integer? == right_type.signed_integer?
|
|
1141
1140
|
|
|
1142
|
-
|
|
1141
|
+
# Mirrors the semantic analyzer's rule: same signedness picks the wider
|
|
1142
|
+
# type; mixed signed/unsigned promotes to the narrowest signed type that
|
|
1143
|
+
# holds both operands' full ranges (a strictly-wider signed type covers
|
|
1144
|
+
# an unsigned operand, otherwise widen to the next signed width). Mixing
|
|
1145
|
+
# with a 64-bit unsigned type has no safe signed common type.
|
|
1146
|
+
if left_type.signed_integer? == right_type.signed_integer?
|
|
1147
|
+
return left_type.integer_width >= right_type.integer_width ? left_type : right_type
|
|
1148
|
+
end
|
|
1149
|
+
|
|
1150
|
+
signed_type, unsigned_type = if left_type.signed_integer?
|
|
1151
|
+
[left_type, right_type]
|
|
1152
|
+
else
|
|
1153
|
+
[right_type, left_type]
|
|
1154
|
+
end
|
|
1155
|
+
|
|
1156
|
+
return signed_type if signed_type.integer_width > unsigned_type.integer_width
|
|
1157
|
+
|
|
1158
|
+
signed_type_above_width(unsigned_type.integer_width)
|
|
1159
|
+
end
|
|
1160
|
+
|
|
1161
|
+
def signed_type_above_width(width)
|
|
1162
|
+
case width
|
|
1163
|
+
when 8 then @ctx.types.fetch("short")
|
|
1164
|
+
when 16 then @ctx.types.fetch("int")
|
|
1165
|
+
when 32 then @ctx.types.fetch("long")
|
|
1166
|
+
end
|
|
1143
1167
|
end
|
|
1144
1168
|
|
|
1145
1169
|
def wider_float_type(left_type, right_type)
|
|
@@ -144,8 +144,10 @@ module MilkTea
|
|
|
144
144
|
(expression && expression_uses_pattern?(expression, &predicate)) || block_uses_expression_pattern?(statement.body, &predicate)
|
|
145
145
|
when AST::ReturnStmt
|
|
146
146
|
statement.value && expression_uses_pattern?(statement.value, &predicate)
|
|
147
|
-
when AST::
|
|
147
|
+
when AST::ExpressionStmt
|
|
148
148
|
expression_uses_pattern?(statement.expression, &predicate)
|
|
149
|
+
when AST::DeferStmt
|
|
150
|
+
block_uses_expression_pattern?(statement.body, &predicate)
|
|
149
151
|
else
|
|
150
152
|
false
|
|
151
153
|
end
|
|
@@ -760,32 +760,6 @@ module MilkTea
|
|
|
760
760
|
end
|
|
761
761
|
end
|
|
762
762
|
|
|
763
|
-
def lower_defer_cleanup_expression(expression, env:)
|
|
764
|
-
prepared_setup, prepared_expression, prepared_cleanups = prepare_expression_with_cleanups(
|
|
765
|
-
expression,
|
|
766
|
-
env:,
|
|
767
|
-
expected_type: infer_expression_type(expression, env:),
|
|
768
|
-
allow_root_statement_foreign: true,
|
|
769
|
-
)
|
|
770
|
-
|
|
771
|
-
lowered = []
|
|
772
|
-
lowered.concat(prepared_setup)
|
|
773
|
-
if (foreign_call = foreign_call_info(prepared_expression, env))
|
|
774
|
-
setup, = lower_foreign_call_statement(
|
|
775
|
-
foreign_call,
|
|
776
|
-
env:,
|
|
777
|
-
expected_type: foreign_call[:binding].type.return_type,
|
|
778
|
-
statement_position: true,
|
|
779
|
-
discard_result: true,
|
|
780
|
-
)
|
|
781
|
-
lowered.concat(setup)
|
|
782
|
-
else
|
|
783
|
-
lowered << IR::ExpressionStmt.new(expression: lower_expression(prepared_expression, env:))
|
|
784
|
-
end
|
|
785
|
-
lowered.concat(prepared_cleanups.flat_map(&:itself))
|
|
786
|
-
lowered
|
|
787
|
-
end
|
|
788
|
-
|
|
789
763
|
def lower_defer_cleanup_body(statements, env:, return_type:)
|
|
790
764
|
lower_block(statements, env:, active_defers: [], return_type:, loop_flow: nil, allow_return: false)
|
|
791
765
|
end
|
|
@@ -943,7 +917,12 @@ module MilkTea
|
|
|
943
917
|
payload_type = Types::VariantArmPayload.new(storage_type, arm_name, storage_type.arm(arm_name))
|
|
944
918
|
data_expr = IR::Member.new(receiver: storage_expr, member: "data", type: nil)
|
|
945
919
|
arm_expr = IR::Member.new(receiver: data_expr, member: arm_name, type: payload_type)
|
|
946
|
-
IR::Member.new(receiver: arm_expr, member: field_name, type: field_type)
|
|
920
|
+
member_expr = IR::Member.new(receiver: arm_expr, member: field_name, type: field_type)
|
|
921
|
+
if type_reaches_target?(field_type, payload_type.variant_type)
|
|
922
|
+
return IR::Unary.new(operator: "*", operand: member_expr, type: field_type)
|
|
923
|
+
end
|
|
924
|
+
|
|
925
|
+
member_expr
|
|
947
926
|
end
|
|
948
927
|
|
|
949
928
|
def infer_result_propagation_type(expression, env:)
|
|
@@ -1156,7 +1135,7 @@ module MilkTea
|
|
|
1156
1135
|
cached = cache[text]
|
|
1157
1136
|
return cached if cached
|
|
1158
1137
|
|
|
1159
|
-
identifier = text.gsub(/[^A-Za-z0-9_]+/, "_").gsub(/_+/, "_").sub(/_+$/, "").sub(/^_
|
|
1138
|
+
identifier = text.gsub(/[^A-Za-z0-9_]+/, "_").gsub(/_+/, "_").sub(/_+$/, "").sub(/^_+/, "")
|
|
1160
1139
|
cache[text] = identifier.empty? ? "value" : identifier
|
|
1161
1140
|
end
|
|
1162
1141
|
|
|
@@ -279,6 +279,18 @@ module MilkTea
|
|
|
279
279
|
check(:colon) && @current + 1 < @tokens.length && @tokens[@current + 1].type != :newline
|
|
280
280
|
end
|
|
281
281
|
|
|
282
|
+
def parse_inline_or_block_body(message)
|
|
283
|
+
if inline_block_body?
|
|
284
|
+
consume(:colon, "expected ':' #{message}")
|
|
285
|
+
@in_inline_block_body = true
|
|
286
|
+
result = [parse_statement]
|
|
287
|
+
@in_inline_block_body = false
|
|
288
|
+
result
|
|
289
|
+
else
|
|
290
|
+
parse_block
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
|
|
282
294
|
def parse_match_stmt
|
|
283
295
|
token = previous
|
|
284
296
|
line = token.line
|
|
@@ -456,7 +468,7 @@ module MilkTea
|
|
|
456
468
|
consume(:in, "expected 'in' in for loop")
|
|
457
469
|
iterables = [parse_expression]
|
|
458
470
|
iterables << parse_expression while match(:comma)
|
|
459
|
-
body =
|
|
471
|
+
body = parse_inline_or_block_body("after 'in' iterables")
|
|
460
472
|
AST::ForStmt.new(bindings:, iterables:, body:, line:, column: bindings.first.column)
|
|
461
473
|
rescue ParseError => e
|
|
462
474
|
raise unless @recovery_errors
|
|
@@ -530,7 +542,7 @@ module MilkTea
|
|
|
530
542
|
token = previous
|
|
531
543
|
line = token.line
|
|
532
544
|
condition = parse_expression
|
|
533
|
-
body =
|
|
545
|
+
body = parse_inline_or_block_body("after while condition")
|
|
534
546
|
AST::WhileStmt.new(condition:, body:, line:, column: token.column, length: token.lexeme.length)
|
|
535
547
|
rescue ParseError => e
|
|
536
548
|
raise unless @recovery_errors
|
|
@@ -580,14 +592,8 @@ module MilkTea
|
|
|
580
592
|
def parse_defer_stmt
|
|
581
593
|
token = previous
|
|
582
594
|
line = token.line
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
AST::DeferStmt.new(expression: nil, body:, line:, column: token.column, length: token.lexeme.length)
|
|
586
|
-
else
|
|
587
|
-
expression = parse_expression
|
|
588
|
-
consume_end_of_statement unless block_expression?(expression)
|
|
589
|
-
AST::DeferStmt.new(expression:, body: nil, line:, column: token.column, length: token.lexeme.length)
|
|
590
|
-
end
|
|
595
|
+
body = parse_inline_or_block_body("after defer")
|
|
596
|
+
AST::DeferStmt.new(body:, line:, column: token.column, length: token.lexeme.length)
|
|
591
597
|
end
|
|
592
598
|
|
|
593
599
|
def parse_when_decl
|
|
@@ -690,7 +696,7 @@ module MilkTea
|
|
|
690
696
|
consume(:in, "expected 'in' in for loop")
|
|
691
697
|
iterables = [parse_expression]
|
|
692
698
|
iterables << parse_expression while match(:comma)
|
|
693
|
-
body =
|
|
699
|
+
body = parse_inline_or_block_body("after 'in' iterables")
|
|
694
700
|
AST::ForStmt.new(bindings:, iterables:, body:, inline: true, line:, column: bindings.first.column)
|
|
695
701
|
rescue ParseError => e
|
|
696
702
|
raise unless @recovery_errors
|
|
@@ -705,7 +711,7 @@ module MilkTea
|
|
|
705
711
|
def parse_inline_while_stmt(inline_token)
|
|
706
712
|
line = inline_token.line
|
|
707
713
|
condition = parse_expression
|
|
708
|
-
body =
|
|
714
|
+
body = parse_inline_or_block_body("after inline while condition")
|
|
709
715
|
AST::WhileStmt.new(condition:, body:, inline: true, line:, column: inline_token.column, length: inline_token.lexeme.length)
|
|
710
716
|
rescue ParseError => e
|
|
711
717
|
raise unless @recovery_errors
|
|
@@ -521,13 +521,9 @@ module MilkTea
|
|
|
521
521
|
when AST::ReturnStmt
|
|
522
522
|
line(statement.value ? "return #{render_expression(statement.value)}" : "return")
|
|
523
523
|
when AST::DeferStmt
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
statement.body.each { |nested| emit_statement(nested) }
|
|
528
|
-
end
|
|
529
|
-
else
|
|
530
|
-
line("defer #{render_expression(statement.expression)}")
|
|
524
|
+
line("defer:")
|
|
525
|
+
with_indent do
|
|
526
|
+
statement.body.each { |nested| emit_statement(nested) }
|
|
531
527
|
end
|
|
532
528
|
when AST::ExpressionStmt
|
|
533
529
|
line(render_expression(statement.expression))
|
|
@@ -649,10 +645,6 @@ module MilkTea
|
|
|
649
645
|
"continue"
|
|
650
646
|
when AST::ReturnStmt
|
|
651
647
|
statement.value ? "return #{render_expression(statement.value)}" : "return"
|
|
652
|
-
when AST::DeferStmt
|
|
653
|
-
return nil if statement.body
|
|
654
|
-
|
|
655
|
-
"defer #{render_expression(statement.expression)}"
|
|
656
648
|
when AST::ExpressionStmt
|
|
657
649
|
render_expression(statement.expression)
|
|
658
650
|
else
|
|
@@ -180,8 +180,7 @@ module MilkTea
|
|
|
180
180
|
when AST::UnsafeStmt
|
|
181
181
|
statement.body.each { |s| validate_async_statement!(s) }
|
|
182
182
|
when AST::DeferStmt
|
|
183
|
-
|
|
184
|
-
statement.body&.each { |s| validate_async_statement!(s) }
|
|
183
|
+
statement.body.each { |s| validate_async_statement!(s) }
|
|
185
184
|
when AST::WhenStmt
|
|
186
185
|
statement.branches.each { |branch| branch.body.each { |s| validate_async_statement!(s) } }
|
|
187
186
|
statement.else_body&.each { |s| validate_async_statement!(s) }
|
|
@@ -230,7 +229,7 @@ module MilkTea
|
|
|
230
229
|
when AST::ReturnStmt
|
|
231
230
|
statement.value && expression_contains_await?(statement.value)
|
|
232
231
|
when AST::DeferStmt
|
|
233
|
-
|
|
232
|
+
statements_contain_await?(statement.body)
|
|
234
233
|
when AST::ExpressionStmt
|
|
235
234
|
expression_contains_await?(statement.expression)
|
|
236
235
|
else
|
|
@@ -209,7 +209,7 @@ module MilkTea
|
|
|
209
209
|
end
|
|
210
210
|
end
|
|
211
211
|
when AST::DeferStmt
|
|
212
|
-
lines.concat(statement_list_lines(statement.body))
|
|
212
|
+
lines.concat(statement_list_lines(statement.body))
|
|
213
213
|
when AST::Assignment
|
|
214
214
|
lines << expression_end_line(statement.value)
|
|
215
215
|
when AST::ReturnStmt
|
|
@@ -375,9 +375,8 @@ module MilkTea
|
|
|
375
375
|
body_names = names.dup
|
|
376
376
|
stmt.body&.each { |s| check_stmt_names(s, scopes, binding, body_names) }
|
|
377
377
|
when AST::DeferStmt
|
|
378
|
-
check_expr_names(stmt.expression, scopes, binding, names) if stmt.expression
|
|
379
378
|
body_names = names.dup
|
|
380
|
-
stmt.body
|
|
379
|
+
stmt.body.each { |s| check_stmt_names(s, scopes, binding, body_names) }
|
|
381
380
|
when AST::WhenStmt
|
|
382
381
|
check_expr_names(stmt.discriminant, scopes, binding, names)
|
|
383
382
|
stmt.branches.each do |b|
|
|
@@ -154,8 +154,7 @@ module MilkTea
|
|
|
154
154
|
statement.iterables.each { |iterable| preassign_local_binding_ids_in_expression(iterable) }
|
|
155
155
|
preassign_local_binding_ids_in_statements(statement.body || [])
|
|
156
156
|
when AST::DeferStmt
|
|
157
|
-
|
|
158
|
-
preassign_local_binding_ids_in_statements(statement.body || []) if statement.body
|
|
157
|
+
preassign_local_binding_ids_in_statements(statement.body)
|
|
159
158
|
when AST::ReturnStmt
|
|
160
159
|
preassign_local_binding_ids_in_expression(statement.value) if statement.value
|
|
161
160
|
when AST::StaticAssert
|
|
@@ -319,8 +318,7 @@ module MilkTea
|
|
|
319
318
|
end
|
|
320
319
|
walk_statements_for_precheck_resolution(statement.body || [], for_scopes, declaration_ids, identifier_ids)
|
|
321
320
|
when AST::DeferStmt
|
|
322
|
-
|
|
323
|
-
walk_statements_for_precheck_resolution(statement.body || [], block_scopes, declaration_ids, identifier_ids) if statement.body
|
|
321
|
+
walk_statements_for_precheck_resolution(statement.body, block_scopes, declaration_ids, identifier_ids)
|
|
324
322
|
when AST::ExpressionStmt
|
|
325
323
|
walk_expression_for_precheck_resolution(statement.expression, block_scopes, identifier_ids, declaration_ids)
|
|
326
324
|
when AST::ReturnStmt
|
|
@@ -193,14 +193,8 @@ module MilkTea
|
|
|
193
193
|
line: statement.line,
|
|
194
194
|
)
|
|
195
195
|
when AST::DeferStmt
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
check_block(statement.body, scopes:, return_type:, allow_return: false)
|
|
199
|
-
end
|
|
200
|
-
else
|
|
201
|
-
validate_consuming_foreign_expression!(statement.expression, scopes:, root_allowed: true)
|
|
202
|
-
validate_hoistable_foreign_expression!(statement.expression, scopes:, root_hoistable: false)
|
|
203
|
-
infer_expression(statement.expression, scopes:)
|
|
196
|
+
with_loop_barrier do
|
|
197
|
+
check_block(statement.body, scopes:, return_type:, allow_return: false)
|
|
204
198
|
end
|
|
205
199
|
when AST::ExpressionStmt
|
|
206
200
|
validate_consuming_foreign_expression!(statement.expression, scopes:, root_allowed: true)
|
|
@@ -187,9 +187,36 @@ module MilkTea
|
|
|
187
187
|
return unless left_type.integer? && right_type.integer?
|
|
188
188
|
return left_type if left_type == right_type
|
|
189
189
|
return unless left_type.fixed_width_integer? && right_type.fixed_width_integer?
|
|
190
|
-
return unless left_type.signed_integer? == right_type.signed_integer?
|
|
191
190
|
|
|
192
|
-
|
|
191
|
+
# Same signedness: the wider type wins (both operands are losslessly
|
|
192
|
+
# assignable to it).
|
|
193
|
+
if left_type.signed_integer? == right_type.signed_integer?
|
|
194
|
+
return left_type.integer_width >= right_type.integer_width ? left_type : right_type
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Mixed signed/unsigned: promote to the narrowest signed type that holds
|
|
198
|
+
# both operands' full ranges, mirroring the lossless assignment rule. A
|
|
199
|
+
# strictly-wider signed type covers an unsigned operand; equal-width or
|
|
200
|
+
# wider unsigned operands widen to the next signed width. Mixing with a
|
|
201
|
+
# 64-bit unsigned type has no safe signed common type, so callers fall
|
|
202
|
+
# back to requiring an explicit cast.
|
|
203
|
+
signed_type, unsigned_type = if left_type.signed_integer?
|
|
204
|
+
[left_type, right_type]
|
|
205
|
+
else
|
|
206
|
+
[right_type, left_type]
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
return signed_type if signed_type.integer_width > unsigned_type.integer_width
|
|
210
|
+
|
|
211
|
+
signed_type_above_width(unsigned_type.integer_width)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def signed_type_above_width(width)
|
|
215
|
+
case width
|
|
216
|
+
when 8 then @ctx.types.fetch("short")
|
|
217
|
+
when 16 then @ctx.types.fetch("int")
|
|
218
|
+
when 32 then @ctx.types.fetch("long")
|
|
219
|
+
end
|
|
193
220
|
end
|
|
194
221
|
|
|
195
222
|
def wider_float_type(left_type, right_type)
|
data/lib/milk_tea/core/types.rb
CHANGED
|
@@ -850,9 +850,6 @@ module MilkTea
|
|
|
850
850
|
end
|
|
851
851
|
|
|
852
852
|
def field_c_name(name)
|
|
853
|
-
stripped = name.delete_suffix("_")
|
|
854
|
-
return stripped if stripped != name && MilkTea::KEYWORDS.key?(stripped)
|
|
855
|
-
|
|
856
853
|
name
|
|
857
854
|
end
|
|
858
855
|
|
|
@@ -961,9 +958,6 @@ module MilkTea
|
|
|
961
958
|
end
|
|
962
959
|
|
|
963
960
|
def field_c_name(name)
|
|
964
|
-
stripped = name.delete_suffix("_")
|
|
965
|
-
return stripped if stripped != name && MilkTea::KEYWORDS.key?(stripped)
|
|
966
|
-
|
|
967
961
|
name
|
|
968
962
|
end
|
|
969
963
|
|
|
@@ -484,8 +484,7 @@ module MilkTea
|
|
|
484
484
|
when AST::UnsafeStmt
|
|
485
485
|
stmt.body.each { |child| collect_indirect_import_uses_from_stmt(child, used, binding_resolution, import_module_names) }
|
|
486
486
|
when AST::DeferStmt
|
|
487
|
-
|
|
488
|
-
stmt.body&.each { |child| collect_indirect_import_uses_from_stmt(child, used, binding_resolution, import_module_names) }
|
|
487
|
+
stmt.body.each { |child| collect_indirect_import_uses_from_stmt(child, used, binding_resolution, import_module_names) }
|
|
489
488
|
when AST::ReturnStmt
|
|
490
489
|
collect_indirect_import_uses_from_expr(stmt.value, used, binding_resolution, import_module_names) if stmt.value
|
|
491
490
|
when AST::ExpressionStmt
|
|
@@ -766,8 +765,7 @@ module MilkTea
|
|
|
766
765
|
when AST::UnsafeStmt
|
|
767
766
|
stmt.body.each { |s| collect_names_from_statement(s, used) }
|
|
768
767
|
when AST::DeferStmt
|
|
769
|
-
|
|
770
|
-
stmt.body&.each { |s| collect_names_from_statement(s, used) }
|
|
768
|
+
stmt.body.each { |s| collect_names_from_statement(s, used) }
|
|
771
769
|
when AST::ReturnStmt
|
|
772
770
|
collect_names_from_expr(stmt.value, used) if stmt.value
|
|
773
771
|
when AST::ExpressionStmt
|
|
@@ -169,9 +169,6 @@ module MilkTea
|
|
|
169
169
|
when AST::UnsafeStmt
|
|
170
170
|
_collect_own_released_names(stmt.body, result)
|
|
171
171
|
when AST::DeferStmt
|
|
172
|
-
if stmt.expression
|
|
173
|
-
_collect_heap_release_names(stmt.expression, result)
|
|
174
|
-
end
|
|
175
172
|
_collect_own_released_names(stmt.body, result) if stmt.body.is_a?(Array)
|
|
176
173
|
end
|
|
177
174
|
end
|
|
@@ -476,7 +473,6 @@ module MilkTea
|
|
|
476
473
|
when AST::UnsafeStmt
|
|
477
474
|
_collect_released_names(stmt.body, result)
|
|
478
475
|
when AST::DeferStmt
|
|
479
|
-
_collect_released_names_in_expr(stmt.expression, result) if stmt.expression
|
|
480
476
|
_collect_released_names(stmt.body, result) if stmt.body.is_a?(Array)
|
|
481
477
|
end
|
|
482
478
|
end
|
|
@@ -611,9 +607,8 @@ module MilkTea
|
|
|
611
607
|
def release_call_in_stmt?(stmt, name)
|
|
612
608
|
return false unless stmt
|
|
613
609
|
|
|
614
|
-
# DeferStmt:
|
|
610
|
+
# DeferStmt: block form `defer: …` (inline defers are a single-statement body)
|
|
615
611
|
if stmt.is_a?(AST::DeferStmt)
|
|
616
|
-
return true if stmt.expression && _expr_has_release?(stmt.expression, name)
|
|
617
612
|
return stmt.body.is_a?(Array) && stmt.body.any? { |s| release_call_in_stmt?(s, name) }
|
|
618
613
|
end
|
|
619
614
|
|
|
@@ -240,8 +240,6 @@ module MilkTea
|
|
|
240
240
|
expression_column(statement.expression)
|
|
241
241
|
when AST::ReturnStmt
|
|
242
242
|
expression_column(statement.value)
|
|
243
|
-
when AST::DeferStmt
|
|
244
|
-
expression_column(statement.expression)
|
|
245
243
|
when AST::ExpressionStmt
|
|
246
244
|
expression_column(statement.expression) || source_statement_span(statement.line)&.first
|
|
247
245
|
else
|
|
@@ -267,8 +265,6 @@ module MilkTea
|
|
|
267
265
|
expression_length(statement.expression)
|
|
268
266
|
when AST::ReturnStmt
|
|
269
267
|
expression_length(statement.value)
|
|
270
|
-
when AST::DeferStmt
|
|
271
|
-
expression_length(statement.expression)
|
|
272
268
|
when AST::ExpressionStmt
|
|
273
269
|
expression_length(statement.expression) || source_statement_span(statement.line)&.last
|
|
274
270
|
else
|
|
@@ -326,8 +322,6 @@ module MilkTea
|
|
|
326
322
|
walk_expression_tree(statement.expression, &block)
|
|
327
323
|
when AST::ReturnStmt
|
|
328
324
|
walk_expression_tree(statement.value, &block)
|
|
329
|
-
when AST::DeferStmt
|
|
330
|
-
walk_expression_tree(statement.expression, &block)
|
|
331
325
|
when AST::ExpressionStmt
|
|
332
326
|
walk_expression_tree(statement.expression, &block)
|
|
333
327
|
when AST::StaticAssert
|
|
@@ -225,8 +225,7 @@ module MilkTea
|
|
|
225
225
|
visit_expression(statement.value) if statement.value
|
|
226
226
|
flag_redundant_widening_cast(statement.value) if statement.value
|
|
227
227
|
when AST::DeferStmt
|
|
228
|
-
|
|
229
|
-
with_scope { visit_statement_list(statement.body) } if statement.body
|
|
228
|
+
with_scope { visit_statement_list(statement.body) }
|
|
230
229
|
when AST::ExpressionStmt
|
|
231
230
|
visit_expression(statement.expression)
|
|
232
231
|
check_useless_expression(statement)
|
|
@@ -1252,8 +1251,7 @@ module MilkTea
|
|
|
1252
1251
|
when AST::UnsafeStmt
|
|
1253
1252
|
stmt.body.each { |s| collect_borrows_from_stmt(s, names) }
|
|
1254
1253
|
when AST::DeferStmt
|
|
1255
|
-
|
|
1256
|
-
stmt.body&.each { |s| collect_borrows_from_stmt(s, names) }
|
|
1254
|
+
stmt.body.each { |s| collect_borrows_from_stmt(s, names) }
|
|
1257
1255
|
when AST::WhenStmt
|
|
1258
1256
|
collect_borrows_from_expr(stmt.discriminant, names)
|
|
1259
1257
|
stmt.branches.each { |b| b.body.each { |s| collect_borrows_from_stmt(s, names) } }
|
|
@@ -1319,7 +1317,7 @@ module MilkTea
|
|
|
1319
1317
|
when AST::UnsafeStmt
|
|
1320
1318
|
stmt.body.each { |s| collect_writes_from_stmt(s, names) }
|
|
1321
1319
|
when AST::DeferStmt
|
|
1322
|
-
stmt.body
|
|
1320
|
+
stmt.body.each { |s| collect_writes_from_stmt(s, names) }
|
|
1323
1321
|
end
|
|
1324
1322
|
end
|
|
1325
1323
|
|
|
@@ -1376,9 +1374,7 @@ module MilkTea
|
|
|
1376
1374
|
stmt.body.each { |s| location = find_borrow_location_in_stmt(s, name); return location if location }
|
|
1377
1375
|
nil
|
|
1378
1376
|
when AST::DeferStmt
|
|
1379
|
-
location =
|
|
1380
|
-
return location if location
|
|
1381
|
-
stmt.body&.each { |s| location = find_borrow_location_in_stmt(s, name); return location if location }
|
|
1377
|
+
stmt.body.each { |s| location = find_borrow_location_in_stmt(s, name); return location if location }
|
|
1382
1378
|
nil
|
|
1383
1379
|
when AST::WhenStmt
|
|
1384
1380
|
location = find_borrow_location_in_expr(stmt.discriminant, name)
|
|
@@ -38,6 +38,7 @@ module MilkTea
|
|
|
38
38
|
when Float then buf << format_float(value)
|
|
39
39
|
when String then emit_string(value, buf)
|
|
40
40
|
when Symbol then buf << ":" << value.to_s.tr("_", "-")
|
|
41
|
+
when Hash, Set then nil
|
|
41
42
|
else buf << escape_string(value.to_s)
|
|
42
43
|
end
|
|
43
44
|
end
|
|
@@ -50,6 +51,7 @@ module MilkTea
|
|
|
50
51
|
buf << "(" << type_name
|
|
51
52
|
members.each do |field|
|
|
52
53
|
val = node.public_send(field)
|
|
54
|
+
next if val.is_a?(Hash) || val.is_a?(Set)
|
|
53
55
|
buf << " :" << field.to_s << " "
|
|
54
56
|
emit_value(val, buf)
|
|
55
57
|
end
|
data/std/asset_pack.mt
CHANGED
|
@@ -187,7 +187,7 @@ function read_entry_metadata(file: stdio.File?) -> Result[EntryMetadata, Error]:
|
|
|
187
187
|
|
|
188
188
|
function read_path_matches(file: stdio.File?, path_length: ptr_uint, logical_path: str) -> Result[bool, Error]:
|
|
189
189
|
let path_buffer = heap.must_alloc[ubyte](path_length)
|
|
190
|
-
defer heap.release(path_buffer)
|
|
190
|
+
defer: heap.release(path_buffer)
|
|
191
191
|
|
|
192
192
|
if not read_exact(file, path_buffer, path_length):
|
|
193
193
|
return Result[bool, Error].failure(error= Error.malformed_index)
|
data/std/async/libuv_runtime.mt
CHANGED
|
@@ -475,7 +475,7 @@ public function result[T](task: Task[T]) -> T:
|
|
|
475
475
|
if not completed[T](task):
|
|
476
476
|
fatal(c"async.result called before task completed")
|
|
477
477
|
|
|
478
|
-
defer task.release(task.frame)
|
|
478
|
+
defer: task.release(task.frame)
|
|
479
479
|
return task.take_result(task.frame)
|
|
480
480
|
|
|
481
481
|
|
|
@@ -484,7 +484,7 @@ public function wait_on[T](runtime: Runtime, task: Task[T]) -> T:
|
|
|
484
484
|
while not task.ready(task.frame):
|
|
485
485
|
runtime_poll(runtime)
|
|
486
486
|
|
|
487
|
-
defer task.release(task.frame)
|
|
487
|
+
defer: task.release(task.frame)
|
|
488
488
|
return task.take_result(task.frame)
|
|
489
489
|
|
|
490
490
|
|
|
@@ -503,7 +503,7 @@ public function wait[T](root: proc() -> Task[T]) -> T:
|
|
|
503
503
|
|
|
504
504
|
var runtime = runtime_create()
|
|
505
505
|
runtime_activate(runtime)
|
|
506
|
-
defer runtime_release(ref_of(runtime))
|
|
506
|
+
defer: runtime_release(ref_of(runtime))
|
|
507
507
|
return wait_on[T](runtime, root())
|
|
508
508
|
|
|
509
509
|
|
|
@@ -514,7 +514,7 @@ public function run(root: proc() -> Task[void]) -> void:
|
|
|
514
514
|
|
|
515
515
|
var runtime = runtime_create()
|
|
516
516
|
runtime_activate(runtime)
|
|
517
|
-
defer runtime_release(ref_of(runtime))
|
|
517
|
+
defer: runtime_release(ref_of(runtime))
|
|
518
518
|
run_on(runtime, root())
|
|
519
519
|
|
|
520
520
|
|
|
@@ -524,7 +524,7 @@ public function with_runtime[T](body: proc(runtime: Runtime) -> T) -> T:
|
|
|
524
524
|
|
|
525
525
|
var runtime = runtime_create()
|
|
526
526
|
runtime_activate(runtime)
|
|
527
|
-
defer runtime_release(ref_of(runtime))
|
|
527
|
+
defer: runtime_release(ref_of(runtime))
|
|
528
528
|
return body(runtime)
|
|
529
529
|
|
|
530
530
|
|
|
@@ -535,5 +535,5 @@ public function run_with_runtime(body: proc(runtime: Runtime) -> void) -> void:
|
|
|
535
535
|
|
|
536
536
|
var runtime = runtime_create()
|
|
537
537
|
runtime_activate(runtime)
|
|
538
|
-
defer runtime_release(ref_of(runtime))
|
|
538
|
+
defer: runtime_release(ref_of(runtime))
|
|
539
539
|
body(runtime)
|
data/std/async/mailbox.mt
CHANGED
|
@@ -138,7 +138,7 @@ extending Mailbox[T]:
|
|
|
138
138
|
|
|
139
139
|
var mutex = unsafe: read(state).mutex
|
|
140
140
|
mutex.lock()
|
|
141
|
-
defer mutex.unlock()
|
|
141
|
+
defer: mutex.unlock()
|
|
142
142
|
|
|
143
143
|
let handle = unsafe: read(state).handle else:
|
|
144
144
|
return Result[bool, Error].failure(error = mailbox_error("mailbox is closed"))
|
|
@@ -161,7 +161,7 @@ extending Mailbox[T]:
|
|
|
161
161
|
|
|
162
162
|
var mutex = unsafe: read(state).mutex
|
|
163
163
|
mutex.lock()
|
|
164
|
-
defer mutex.unlock()
|
|
164
|
+
defer: mutex.unlock()
|
|
165
165
|
return unsafe: read(state).queue.pop_front()
|
|
166
166
|
|
|
167
167
|
|
|
@@ -171,7 +171,7 @@ extending Mailbox[T]:
|
|
|
171
171
|
|
|
172
172
|
var mutex = unsafe: read(state).mutex
|
|
173
173
|
mutex.lock()
|
|
174
|
-
defer mutex.unlock()
|
|
174
|
+
defer: mutex.unlock()
|
|
175
175
|
|
|
176
176
|
var drained = vec.Vec[T].with_capacity(unsafe: read(state).queue.len())
|
|
177
177
|
while true:
|
|
@@ -187,5 +187,5 @@ extending Mailbox[T]:
|
|
|
187
187
|
|
|
188
188
|
var mutex = unsafe: read(state).mutex
|
|
189
189
|
mutex.lock()
|
|
190
|
-
defer mutex.unlock()
|
|
190
|
+
defer: mutex.unlock()
|
|
191
191
|
return unsafe: read(state).queue.is_empty()
|