mt-lang 0.2.22 → 0.3.0

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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +24 -1
  3. data/docs/index.html +2 -1
  4. data/docs/language-design.md +2 -0
  5. data/docs/language-manual.md +16 -1
  6. data/lib/milk_tea/base.rb +1 -1
  7. data/lib/milk_tea/core/ast.rb +2 -2
  8. data/lib/milk_tea/core/c_backend/expressions.rb +11 -0
  9. data/lib/milk_tea/core/c_backend/type_collectors.rb +49 -0
  10. data/lib/milk_tea/core/c_backend/type_declaration.rb +7 -0
  11. data/lib/milk_tea/core/c_backend/type_system.rb +12 -0
  12. data/lib/milk_tea/core/c_backend.rb +8 -0
  13. data/lib/milk_tea/core/compatibility_helpers.rb +4 -0
  14. data/lib/milk_tea/core/compile_time.rb +16 -0
  15. data/lib/milk_tea/core/ir.rb +1 -0
  16. data/lib/milk_tea/core/keywords.rb +1 -1
  17. data/lib/milk_tea/core/lowering/block.rb +48 -16
  18. data/lib/milk_tea/core/lowering/calls.rb +75 -1
  19. data/lib/milk_tea/core/lowering/declarations.rb +7 -0
  20. data/lib/milk_tea/core/lowering/expressions.rb +39 -8
  21. data/lib/milk_tea/core/lowering/functions.rb +1 -1
  22. data/lib/milk_tea/core/lowering/resolve.rb +70 -5
  23. data/lib/milk_tea/core/lowering/utils.rb +26 -0
  24. data/lib/milk_tea/core/module_binder.rb +4 -0
  25. data/lib/milk_tea/core/parser/expressions.rb +11 -3
  26. data/lib/milk_tea/core/parser/statements.rb +2 -2
  27. data/lib/milk_tea/core/parser/types.rb +8 -1
  28. data/lib/milk_tea/core/semantic_analyzer/calls.rb +97 -4
  29. data/lib/milk_tea/core/semantic_analyzer/expressions.rb +52 -2
  30. data/lib/milk_tea/core/semantic_analyzer/function_binding.rb +7 -0
  31. data/lib/milk_tea/core/semantic_analyzer/generics.rb +40 -0
  32. data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +11 -0
  33. data/lib/milk_tea/core/semantic_analyzer/statements.rb +21 -4
  34. data/lib/milk_tea/core/semantic_analyzer/top_level.rb +23 -0
  35. data/lib/milk_tea/core/semantic_analyzer/type_compatibility.rb +37 -0
  36. data/lib/milk_tea/core/types/layout.rb +7 -0
  37. data/lib/milk_tea/core/types/predicates.rb +44 -3
  38. data/lib/milk_tea/core/types/registry.rb +4 -0
  39. data/lib/milk_tea/core/types/types.rb +42 -0
  40. data/lib/milk_tea/core/types/visitor.rb +2 -0
  41. data/lib/milk_tea/lsp/server/completion.rb +1 -1
  42. data/lib/milk_tea/lsp/server/hover.rb +8 -1
  43. data/std/raylib.mt +14 -14
  44. metadata +2 -2
@@ -86,7 +86,7 @@ module MilkTea
86
86
  end
87
87
 
88
88
  begin
89
- return resolve_type_ref_for_analysis(type_name, analysis)
89
+ return method_dispatch_receiver_type(resolve_type_ref_for_analysis(type_name, analysis))
90
90
  rescue LoweringError => error
91
91
  receiver_type_param_names = methods_receiver_type_argument_names!(type_name)
92
92
  raise error if receiver_type_param_names.empty?
@@ -99,6 +99,9 @@ module MilkTea
99
99
  end
100
100
 
101
101
  def lower_array_to_span_expression(expression, target_type)
102
+ array_type = expression.type
103
+ array_type = referenced_type(array_type) if ref_type?(array_type)
104
+
102
105
  IR::AggregateLiteral.new(
103
106
  type: target_type,
104
107
  fields: [
@@ -115,7 +118,7 @@ module MilkTea
115
118
  ),
116
119
  IR::AggregateField.new(
117
120
  name: "len",
118
- value: IR::IntegerLiteral.new(value: array_length(expression.type), type: @ctx.types.fetch("ptr_uint")),
121
+ value: IR::IntegerLiteral.new(value: array_length(array_type), type: @ctx.types.fetch("ptr_uint")),
119
122
  ),
120
123
  ],
121
124
  )
@@ -549,6 +552,8 @@ module MilkTea
549
552
  when :atomic_compare_exchange then @ctx.types.fetch("bool")
550
553
  end
551
554
  return [precomputed, nil, callee.receiver, Types::Registry.function(nil, params: [], return_type: ret)]
555
+ when :simd_lane_with
556
+ return [precomputed, nil, callee.receiver, Types::Registry.function(nil, params: [], return_type: resolved_receiver_type)]
552
557
  end
553
558
  end
554
559
 
@@ -571,6 +576,13 @@ module MilkTea
571
576
  return [atomic_method, nil, callee.receiver, Types::Registry.function(nil, params: [], return_type: ret)]
572
577
  end
573
578
 
579
+ if (simd_method = simd_method_kind(resolved_receiver_type, callee.member))
580
+ ret = case simd_method
581
+ when :simd_lane_with then resolved_receiver_type
582
+ end
583
+ return [simd_method, nil, callee.receiver, Types::Registry.function(nil, params: [], return_type: ret)]
584
+ end
585
+
574
586
  field_receiver_type = infer_field_receiver_type(callee.receiver, env:)
575
587
  if array_type?(field_receiver_type) && callee.member == "as_span"
576
588
  return [:array_as_span, nil, callee.receiver, Types::Registry.span(array_element_type(field_receiver_type))]
@@ -592,6 +604,11 @@ module MilkTea
592
604
  return [:array, nil, nil, array_type]
593
605
  end
594
606
 
607
+ if callee.callee.is_a?(AST::Identifier) && callee.callee.name == "simd"
608
+ simd_type = resolve_type_ref(AST::TypeRef.new(name: AST::QualifiedName.new(parts: ["simd"]), arguments: callee.arguments, nullable: false))
609
+ return [:simd, nil, nil, simd_type]
610
+ end
611
+
595
612
  if callee.callee.is_a?(AST::Identifier) && callee.callee.name == "span"
596
613
  span_type = resolve_type_ref(AST::TypeRef.new(name: AST::QualifiedName.new(parts: ["span"]), arguments: callee.arguments, nullable: false))
597
614
  return [:struct_literal, nil, nil, span_type]
@@ -663,7 +680,7 @@ module MilkTea
663
680
 
664
681
  if (type_ref = type_ref_from_specialization(callee))
665
682
  specialized_type = resolve_type_ref(type_ref)
666
- return [:struct_literal, nil, nil, specialized_type] if specialized_type.is_a?(Types::Struct) || task_type?(specialized_type) || specialized_type.is_a?(Types::Vector) || specialized_type.is_a?(Types::Matrix) || specialized_type.is_a?(Types::Quaternion)
683
+ return [:struct_literal, nil, nil, specialized_type] if specialized_type.is_a?(Types::Struct) || task_type?(specialized_type) || specialized_type.is_a?(Types::Vector) || specialized_type.is_a?(Types::Matrix) || specialized_type.is_a?(Types::Quaternion) || specialized_type.is_a?(Types::Simd)
667
684
  end
668
685
 
669
686
  raise LoweringError, "unsupported specialization callee"
@@ -838,7 +855,7 @@ module MilkTea
838
855
  :reinterpret, :zero, :hash, :equal, :order,
839
856
  :dyn_method
840
857
  callee_type.return_type
841
- when :struct_literal, :struct_with, :array, :variant_arm_ctor, :adapt
858
+ when :struct_literal, :struct_with, :array, :simd, :variant_arm_ctor, :adapt
842
859
  callee_type
843
860
  when :ref_of
844
861
  argument_type = infer_expression_type(expression.arguments.fetch(0).value, env:)
@@ -867,7 +884,8 @@ module MilkTea
867
884
  receiver_type.element_type
868
885
  end
869
886
  Types::Registry.nullable(Types::Registry.generic_instance("ptr", [elem_type]))
870
- when :atomic_load, :atomic_add, :atomic_sub, :atomic_exchange, :atomic_store, :atomic_compare_exchange
887
+ when :atomic_load, :atomic_add, :atomic_sub, :atomic_exchange, :atomic_store, :atomic_compare_exchange,
888
+ :simd_lane_with
871
889
  callee_type.return_type
872
890
  else
873
891
  raise LoweringError, "unsupported call kind #{kind}"
@@ -1794,12 +1812,16 @@ module MilkTea
1794
1812
  @lowerer = lowerer
1795
1813
  end
1796
1814
 
1815
+ def types
1816
+ @lowerer.instance_variable_get(:@ctx).types
1817
+ end
1818
+
1797
1819
  def evaluate_compile_time_const_value(expression, scopes: nil)
1798
1820
  @lowerer.send(:compile_time_const_value, expression, env: @lowerer.send(:empty_env))
1799
1821
  end
1800
1822
 
1801
1823
  def top_level_function(name)
1802
- @lowerer.instance_variable_get(:@ctx.functions)&.[](name)
1824
+ @lowerer.instance_variable_get(:@ctx).functions&.[](name)
1803
1825
  end
1804
1826
 
1805
1827
  def raise_sema_error(message)
@@ -2185,6 +2207,46 @@ module MilkTea
2185
2207
  raise LoweringError, "cannot use method #{binding.name} with receiver #{receiver_type}"
2186
2208
  end
2187
2209
  end
2210
+ when Types::Span
2211
+ return {} unless receiver_type.is_a?(Types::Span)
2212
+
2213
+ substitutions = {}
2214
+ if declared_receiver_type.element_type.is_a?(Types::TypeVar)
2215
+ substitutions[declared_receiver_type.element_type.name] = receiver_type.element_type
2216
+ elsif declared_receiver_type.element_type != receiver_type.element_type
2217
+ raise LoweringError, "cannot use method #{binding.name} with receiver #{receiver_type}"
2218
+ end
2219
+ substitutions
2220
+ when Types::Task
2221
+ return {} unless receiver_type.is_a?(Types::Task)
2222
+
2223
+ substitutions = {}
2224
+ if declared_receiver_type.result_type.is_a?(Types::TypeVar)
2225
+ substitutions[declared_receiver_type.result_type.name] = receiver_type.result_type
2226
+ elsif declared_receiver_type.result_type != receiver_type.result_type
2227
+ raise LoweringError, "cannot use method #{binding.name} with receiver #{receiver_type}"
2228
+ end
2229
+ substitutions
2230
+ when Types::SoA
2231
+ return {} unless receiver_type.is_a?(Types::SoA)
2232
+
2233
+ substitutions = {}
2234
+ if declared_receiver_type.element_type.is_a?(Types::TypeVar)
2235
+ substitutions[declared_receiver_type.element_type.name] = receiver_type.element_type
2236
+ elsif declared_receiver_type.element_type != receiver_type.element_type
2237
+ raise LoweringError, "cannot use method #{binding.name} with receiver #{receiver_type}"
2238
+ end
2239
+ substitutions
2240
+ when Types::Simd
2241
+ return {} unless receiver_type.is_a?(Types::Simd)
2242
+
2243
+ substitutions = {}
2244
+ if declared_receiver_type.element_type.is_a?(Types::TypeVar)
2245
+ substitutions[declared_receiver_type.element_type.name] = receiver_type.element_type
2246
+ elsif declared_receiver_type.element_type != receiver_type.element_type
2247
+ raise LoweringError, "cannot use method #{binding.name} with receiver #{receiver_type}"
2248
+ end
2249
+ substitutions
2188
2250
  else
2189
2251
  {}
2190
2252
  end
@@ -2393,6 +2455,9 @@ module MilkTea
2393
2455
  elsif name == "SoA"
2394
2456
  validate_generic_type!(name, args)
2395
2457
  Types::Registry.soa(args.fetch(0), count: args.fetch(1).value)
2458
+ elsif name == "simd"
2459
+ validate_generic_type!(name, args)
2460
+ Types::Registry.simd(args.fetch(0), lane_count: args.fetch(1).value)
2396
2461
  else
2397
2462
  validate_generic_type!(name, args)
2398
2463
  args = [type_ref.lifetime] + args if name == "ref" && type_ref.lifetime
@@ -9,6 +9,14 @@ module MilkTea
9
9
  range_expr?(expression)
10
10
  end
11
11
 
12
+ def lower_range_match_condition(range_pattern, scrutinee_ir, bool_type, env:)
13
+ start_ir = lower_expression(range_pattern.start_expr, env:, expected_type: nil)
14
+ end_ir = lower_expression(range_pattern.end_expr, env:, expected_type: nil)
15
+ ge = IR::Binary.new(operator: ">=", left: scrutinee_ir, right: start_ir, type: bool_type)
16
+ le = IR::Binary.new(operator: "<=", left: scrutinee_ir, right: end_ir, type: bool_type)
17
+ IR::Binary.new(operator: "and", left: ge, right: le, type: bool_type)
18
+ end
19
+
12
20
  def range_start_of(iterable)
13
21
  iterable.start_expr
14
22
  end
@@ -80,6 +88,10 @@ module MilkTea
80
88
  type.arguments[1].is_a?(Types::LiteralTypeArg)
81
89
  end
82
90
 
91
+ def simd_type?(type)
92
+ type.is_a?(Types::Simd)
93
+ end
94
+
83
95
  def array_element_type(type)
84
96
  return unless array_type?(type)
85
97
 
@@ -321,6 +333,10 @@ module MilkTea
321
333
  return receiver_type.element_type
322
334
  end
323
335
 
336
+ if simd_type?(receiver_type)
337
+ return receiver_type.element_type
338
+ end
339
+
324
340
  if pointer_type?(receiver_type)
325
341
  return pointee_type(receiver_type)
326
342
  end
@@ -417,6 +433,16 @@ module MilkTea
417
433
  if type == @ctx.types.fetch("str") || type == @ctx.types.fetch("cstr")
418
434
  return IR::StringLiteral.new(value:, type:, cstring: type == @ctx.types.fetch("cstr"))
419
435
  end
436
+ when Hash
437
+ return nil unless type.is_a?(Types::Struct)
438
+ fields = value.map do |name, field_value|
439
+ field_type = type.field(name)
440
+ return nil unless field_type
441
+ lowered = lower_compile_time_literal(field_value, field_type)
442
+ return nil unless lowered
443
+ IR::AggregateField.new(name:, value: lowered)
444
+ end
445
+ return IR::AggregateLiteral.new(type:, fields:)
420
446
  end
421
447
 
422
448
  nil
@@ -145,6 +145,10 @@ module MilkTea
145
145
  return true if receiver_type.is_a?(Types::Matrix)
146
146
  return true if receiver_type.is_a?(Types::Quaternion)
147
147
  return true if receiver_type.is_a?(Types::SoA)
148
+ return true if receiver_type.is_a?(Types::Simd)
149
+ return true if receiver_type.is_a?(Types::Span)
150
+ return true if receiver_type.is_a?(Types::Task)
151
+ return true if receiver_type.is_a?(Types::Dyn)
148
152
  return true if exported_types.value?(receiver_type)
149
153
  return true if imported_receiver_type?(receiver_type, analysis.imports)
150
154
  return exported_method_receiver?(receiver_type.base, analysis, exported_types) if receiver_type.is_a?(Types::Nullable)
@@ -56,14 +56,22 @@ module MilkTea
56
56
  arms
57
57
  end
58
58
 
59
+ def parse_match_arm_pattern
60
+ pattern = parse_bitwise_xor
61
+ return pattern unless (pattern.is_a?(AST::IntegerLiteral) || pattern.is_a?(AST::CharLiteral)) && match(:dot_dot)
62
+
63
+ end_expr = parse_bitwise_xor
64
+ AST::RangeExpr.new(start_expr: pattern, end_expr:, line: previous.line, column: previous.column)
65
+ end
66
+
59
67
  def parse_match_expression_arm
60
68
  patterns = []
61
69
  if match(:else)
62
70
  patterns << AST::Identifier.new(name: "_", line: previous.line, column: previous.column)
63
71
  else
64
- patterns << parse_bitwise_xor
72
+ patterns << parse_match_arm_pattern
65
73
  while match(:pipe)
66
- patterns << parse_bitwise_xor
74
+ patterns << parse_match_arm_pattern
67
75
  end
68
76
  end
69
77
  binding_token = nil
@@ -550,7 +558,7 @@ module MilkTea
550
558
  end
551
559
 
552
560
  def builtin_specialization_target?(expression)
553
- expression.is_a?(AST::Identifier) && %w[array reinterpret span zero ptr const_ptr own ref adapt equal hash order].include?(expression.name)
561
+ expression.is_a?(AST::Identifier) && %w[array reinterpret span zero ptr const_ptr own ref adapt equal hash order simd SoA].include?(expression.name)
554
562
  end
555
563
 
556
564
  def parse_diagnostic_hint?(error)
@@ -332,9 +332,9 @@ module MilkTea
332
332
  if match(:else)
333
333
  patterns << AST::Identifier.new(name: "_", line: previous.line, column: previous.column)
334
334
  else
335
- patterns << parse_bitwise_xor
335
+ patterns << parse_match_arm_pattern
336
336
  while match(:pipe)
337
- patterns << parse_bitwise_xor
337
+ patterns << parse_match_arm_pattern
338
338
  end
339
339
  end
340
340
  binding_name = if match(:as)
@@ -46,8 +46,9 @@ module MilkTea
46
46
  raise error(name_token, "expected ':' and parameter type") unless match(:colon)
47
47
 
48
48
  param_type = parse_type_ref
49
+ default_value = parse_param_default_value
49
50
 
50
- AST::Param.new(name: name_token.lexeme, type: param_type, line: name_token.line, column: name_token.column)
51
+ AST::Param.new(name: name_token.lexeme, type: param_type, line: name_token.line, column: name_token.column, default_value:)
51
52
  rescue ParseError => e
52
53
  raise unless @recovery_errors
53
54
 
@@ -57,6 +58,12 @@ module MilkTea
57
58
  AST::Param.new(name: param_name, type: error_type, line: name_token&.line || 1, column: name_token&.column || 1)
58
59
  end
59
60
 
61
+ def parse_param_default_value
62
+ return nil unless match(:equal)
63
+
64
+ parse_expression
65
+ end
66
+
60
67
  def parse_foreign_param
61
68
  mode = if foreign_param_qualifier_mode?
62
69
  advance.type
@@ -53,6 +53,24 @@ module MilkTea
53
53
  struct_type
54
54
  end
55
55
 
56
+ def check_simd_construction(simd_type, arguments, scopes:)
57
+ raise_sema_error("simd construction requires exactly #{simd_type.lane_count} positional arguments, got #{arguments.length}") unless arguments.length == simd_type.lane_count
58
+ raise_sema_error("simd construction does not accept named arguments") if arguments.any?(&:name)
59
+
60
+ element_type = simd_type.element_type
61
+ arguments.each do |argument|
62
+ actual_type = infer_expression(argument.value, scopes:, expected_type: element_type)
63
+ ensure_assignable!(
64
+ actual_type,
65
+ element_type,
66
+ "simd lane expects #{element_type}, got #{actual_type}",
67
+ expression: argument.value,
68
+ contextual_int_to_float: contextual_int_to_float_target?(element_type),
69
+ )
70
+ end
71
+ simd_type
72
+ end
73
+
56
74
  def check_struct_with_call(struct_type, _receiver_expression, arguments, scopes:)
57
75
  check_aggregate_field_arguments(struct_type, arguments, scopes:, context: "struct.with()")
58
76
  struct_type
@@ -584,6 +602,27 @@ module MilkTea
584
602
  end
585
603
  end
586
604
 
605
+ def check_simd_method_call(kind, receiver_type, _receiver, arguments, scopes:)
606
+ raise_sema_error("simd methods do not support named arguments") if arguments.any?(&:name)
607
+
608
+ case kind
609
+ when :simd_lane_with
610
+ raise_sema_error("with expects exactly 2 arguments, got #{arguments.length}") unless arguments.length == 2
611
+
612
+ index_arg = arguments[0].value
613
+ index_type = infer_expression(index_arg, scopes:)
614
+ raise_sema_error("with index must be an integer, got #{index_type}") unless index_type.integer?
615
+
616
+ value_type = infer_expression(arguments[1].value, scopes:, expected_type: receiver_type.element_type)
617
+ ensure_assignable!(
618
+ value_type,
619
+ receiver_type.element_type,
620
+ "with expects lane value of type #{receiver_type.element_type}, got #{value_type}",
621
+ )
622
+ receiver_type
623
+ end
624
+ end
625
+
587
626
  def event_listener_type(event_type)
588
627
  params = []
589
628
  params << Types::Registry.parameter("value", event_type.payload_type) if event_type.payload_type
@@ -620,6 +659,12 @@ module MilkTea
620
659
  ATOMIC_METHOD_KINDS[name]
621
660
  end
622
661
 
662
+ def simd_method_kind(receiver_type, name)
663
+ return unless simd_type?(receiver_type)
664
+
665
+ SIMD_METHOD_KINDS[name]
666
+ end
667
+
623
668
  def check_atomic_method_call(kind, receiver_type, receiver, arguments, scopes:)
624
669
  elem_type = atomic_element_type(receiver_type)
625
670
  raise_sema_error("atomic methods do not support named arguments") if arguments.any?(&:name)
@@ -740,10 +785,14 @@ module MilkTea
740
785
  end
741
786
 
742
787
  def check_function_call(binding, arguments, scopes:)
743
- arguments = canonicalize_call_arguments(arguments, binding.type.params, binding.name)
788
+ arguments = canonicalize_call_arguments(arguments, binding.type.params, binding.name, binding)
789
+ fill_positional_defaults!(arguments, binding)
790
+
744
791
  expected_params = binding.type.params
745
- unless call_arity_matches?(binding.type, arguments.length)
746
- raise_sema_error(arity_error_message(binding.type, binding.name, arguments.length))
792
+ required_count = count_required_params(binding)
793
+ variadic = binding.type.is_a?(Types::Function) && binding.type.variadic
794
+ unless variadic ? arguments.length >= required_count : arguments.length <= expected_params.length && arguments.length >= required_count
795
+ raise_sema_error(arity_error_message(binding.type, binding.name, arguments.length, required_count:))
747
796
  end
748
797
 
749
798
  expected_params.each_with_index do |parameter, index|
@@ -963,7 +1012,7 @@ module MilkTea
963
1012
  resolve_interface_ref(interface_ref)
964
1013
  end
965
1014
 
966
- def canonicalize_call_arguments(arguments, params, context_name)
1015
+ def canonicalize_call_arguments(arguments, params, context_name, binding = nil)
967
1016
  return arguments unless arguments.any?(&:name)
968
1017
 
969
1018
  named_seen = false
@@ -985,8 +1034,52 @@ module MilkTea
985
1034
  end
986
1035
  end
987
1036
 
1037
+ fill_parameter_defaults!(by_position, params, binding, context_name)
1038
+
988
1039
  by_position.reject(&:nil?)
989
1040
  end
1041
+
1042
+ def fill_parameter_defaults!(by_position, params, binding, context_name)
1043
+ return unless binding
1044
+
1045
+ ast_params = binding.ast.params
1046
+ return unless ast_params.any? { |p| p.respond_to?(:default_value) && p.default_value }
1047
+
1048
+ params.each_with_index do |param, idx|
1049
+ next unless by_position[idx].nil?
1050
+ next unless idx < ast_params.length
1051
+
1052
+ ast_param = ast_params[idx]
1053
+ next unless ast_param.respond_to?(:default_value) && ast_param.default_value
1054
+
1055
+ by_position[idx] = AST::Argument.new(name: nil, value: ast_param.default_value)
1056
+ end
1057
+ end
1058
+
1059
+ def fill_positional_defaults!(arguments, binding)
1060
+ return unless binding.ast.params.any? { |p| p.respond_to?(:default_value) && p.default_value }
1061
+
1062
+ ast_params = binding.ast.params
1063
+ while arguments.length < ast_params.length
1064
+ ast_param = ast_params[arguments.length]
1065
+ if ast_param.respond_to?(:default_value) && ast_param.default_value
1066
+ arguments << AST::Argument.new(name: nil, value: ast_param.default_value)
1067
+ else
1068
+ break
1069
+ end
1070
+ end
1071
+ end
1072
+
1073
+ def count_required_params(binding)
1074
+ return binding.type.params.length unless binding.ast.params.any? { |p| p.respond_to?(:default_value) && p.default_value }
1075
+
1076
+ seen_default = false
1077
+ binding.ast.params.count do |p|
1078
+ has_default = p.respond_to?(:default_value) && p.default_value
1079
+ seen_default = true if has_default
1080
+ !has_default && !seen_default
1081
+ end
1082
+ end
990
1083
  end
991
1084
  end
992
1085
  end
@@ -446,6 +446,10 @@ module MilkTea
446
446
  return receiver_type.element_type
447
447
  end
448
448
 
449
+ if simd_type?(receiver_type)
450
+ return receiver_type.element_type
451
+ end
452
+
449
453
  if array_type?(receiver_type) && !unsafe_context? && !addressable_storage_expression?(expression.receiver, scopes:)
450
454
  raise_sema_error("safe array indexing requires an addressable array value; bind it to a local first")
451
455
  end
@@ -489,6 +493,10 @@ module MilkTea
489
493
 
490
494
  operand_type
491
495
  when "~"
496
+ if simd_type?(operand_type)
497
+ raise_sema_error("operator ~ on simd requires integer element type, got #{operand_type.element_type}") unless operand_type.element_type.integer?
498
+ return operand_type
499
+ end
492
500
  raise_sema_error("operator ~ requires an integer or flags operand, got #{operand_type}") unless bitwise_type?(operand_type)
493
501
 
494
502
  operand_type
@@ -596,6 +604,9 @@ module MilkTea
596
604
  ensure_assignable!(right_type, @ctx.types.fetch("bool"), "operator #{expression.operator} requires bool operands")
597
605
  @ctx.types.fetch("bool")
598
606
  when "|", "&", "^"
607
+ simd_result = simd_bitwise_result(left_type, right_type)
608
+ return simd_result if simd_result
609
+
599
610
  # For Flags/Enum types, the operands must match and be bitwise-capable.
600
611
  unless left_type == right_type && (bitwise_type?(left_type) || left_type.is_a?(Types::Flags))
601
612
  raise_sema_error("operator #{expression.operator} requires matching integer or flags types, got #{left_type} and #{right_type}")
@@ -626,6 +637,9 @@ module MilkTea
626
637
 
627
638
  result_type
628
639
  when "%"
640
+ simd_result = simd_mod_result(left_type, right_type)
641
+ return simd_result if simd_result
642
+
629
643
  result_type = common_integer_type(left_type, right_type)
630
644
  unless result_type
631
645
  raise_sema_error("operator % requires compatible integer types, got #{left_type} and #{right_type}")
@@ -633,6 +647,9 @@ module MilkTea
633
647
 
634
648
  result_type
635
649
  when "<<", ">>"
650
+ simd_result = simd_shift_result(left_type, right_type)
651
+ return simd_result if simd_result
652
+
636
653
  unless left_type.is_a?(Types::Primitive) && left_type.integer? && right_type.is_a?(Types::Primitive) && right_type.integer?
637
654
  raise_sema_error("operator #{expression.operator} requires integer operands, got #{left_type} and #{right_type}")
638
655
  end
@@ -787,8 +804,26 @@ module MilkTea
787
804
  next
788
805
  end
789
806
 
807
+ if arm.pattern.is_a?(AST::RangeExpr)
808
+ start_val = arm.pattern.start_expr
809
+ end_val = arm.pattern.end_expr
810
+ unless (start_val.is_a?(AST::IntegerLiteral) || start_val.is_a?(AST::CharLiteral)) &&
811
+ (end_val.is_a?(AST::IntegerLiteral) || end_val.is_a?(AST::CharLiteral))
812
+ raise_sema_error("range match arm bounds must be integer or char literals, got #{start_val.class.name}..#{end_val.class.name}")
813
+ end
814
+
815
+ raise_sema_error("range match arm start #{start_val.value} must be <= end #{end_val.value}") if start_val.value > end_val.value
816
+
817
+ range_key = [start_val.value, end_val.value]
818
+ raise_sema_error("duplicate match arm range #{range_key[0]}..#{range_key[1]}") if covered_values.key?(range_key)
819
+
820
+ covered_values[range_key] = true
821
+ arm_entries << [infer_match_expression_arm_value(arm, scopes:, expected_type:), arm.value]
822
+ next
823
+ end
824
+
790
825
  unless arm.pattern.is_a?(AST::IntegerLiteral) || arm.pattern.is_a?(AST::CharLiteral)
791
- raise_sema_error("match arm for integer scrutinee must be an integer literal, char literal, or _, got #{arm.pattern.class.name}")
826
+ raise_sema_error("match arm for integer scrutinee must be an integer literal, char literal, range, or _, got #{arm.pattern.class.name}")
792
827
  end
793
828
 
794
829
  value = arm.pattern.value
@@ -1049,8 +1084,12 @@ module MilkTea
1049
1084
  check_event_method_call(callable_kind, receiver, expression.arguments, scopes:)
1050
1085
  when :atomic_load, :atomic_store, :atomic_add, :atomic_sub, :atomic_exchange, :atomic_compare_exchange
1051
1086
  check_atomic_method_call(callable_kind, callable, receiver, expression.arguments, scopes:)
1087
+ when :simd_lane_with
1088
+ check_simd_method_call(callable_kind, callable, receiver, expression.arguments, scopes:)
1052
1089
  when :struct
1053
1090
  check_aggregate_construction(callable, expression.arguments, scopes:)
1091
+ when :simd
1092
+ check_simd_construction(callable, expression.arguments, scopes:)
1054
1093
  when :struct_with
1055
1094
  check_struct_with_call(callable, receiver, expression.arguments, scopes:)
1056
1095
  when :variant_arm_ctor
@@ -1435,6 +1474,10 @@ module MilkTea
1435
1474
  return [atomic_method, method_receiver_type, callee.receiver]
1436
1475
  end
1437
1476
 
1477
+ if (simd_method = simd_method_kind(method_receiver_type, callee.member))
1478
+ return [simd_method, method_receiver_type, callee.receiver]
1479
+ end
1480
+
1438
1481
  field_receiver_type = infer_field_receiver_type(callee.receiver, scopes:)
1439
1482
  if array_type?(field_receiver_type) && callee.member == "as_span"
1440
1483
  return [:array_as_span, field_receiver_type, callee.receiver]
@@ -1467,6 +1510,13 @@ module MilkTea
1467
1510
  return [:array, array_type, nil]
1468
1511
  end
1469
1512
 
1513
+ if callee.callee.is_a?(AST::Identifier) && callee.callee.name == "simd"
1514
+ raise_sema_error("simd requires exactly two type arguments") unless callee.arguments.length == 2
1515
+
1516
+ simd_type = resolve_type_ref(AST::TypeRef.new(name: AST::QualifiedName.new(parts: ["simd"]), arguments: callee.arguments, nullable: false))
1517
+ return [:simd, simd_type, nil]
1518
+ end
1519
+
1470
1520
  if callee.callee.is_a?(AST::Identifier) && callee.callee.name == "span"
1471
1521
  raise_sema_error("span requires exactly one type argument") unless callee.arguments.length == 1
1472
1522
 
@@ -1526,7 +1576,7 @@ module MilkTea
1526
1576
 
1527
1577
  if (type_ref = type_ref_from_specialization(callee))
1528
1578
  specialized_type = resolve_type_ref(type_ref)
1529
- return [:struct, specialized_type, nil] if specialized_type.is_a?(Types::Struct) || task_type?(specialized_type) || specialized_type.is_a?(Types::Vector) || specialized_type.is_a?(Types::Matrix) || specialized_type.is_a?(Types::Quaternion)
1579
+ return [:struct, specialized_type, nil] if specialized_type.is_a?(Types::Struct) || task_type?(specialized_type) || specialized_type.is_a?(Types::Vector) || specialized_type.is_a?(Types::Matrix) || specialized_type.is_a?(Types::Quaternion) || specialized_type.is_a?(Types::Simd)
1530
1580
  end
1531
1581
 
1532
1582
  raise_sema_error("unsupported callable specialization #{describe_expression(callee)}")
@@ -85,6 +85,7 @@ module MilkTea
85
85
  end
86
86
 
87
87
  public_params = []
88
+ any_default = false
88
89
  decl.params.each do |param|
89
90
  begin
90
91
  ensure_non_reserved_primitive_name!(param.name, kind_label: "parameter", line: param.respond_to?(:line) ? param.line : decl.line, column: param.respond_to?(:column) ? param.column : nil)
@@ -94,6 +95,12 @@ module MilkTea
94
95
  validate_parameter_proc_type!(type, function_name: decl.name, parameter_name: param.name, external:, foreign:)
95
96
  raise_sema_error("parameter #{param.name} of #{decl.name} must pass event storage through ref[...] or pointers, got #{type}") if noncopyable_event_storage_type?(type)
96
97
 
98
+ has_default = param.respond_to?(:default_value) && param.default_value
99
+ raise_sema_error("external function #{decl.name} cannot have default parameter values") if external && has_default
100
+ raise_sema_error("foreign function #{decl.name} cannot have default parameter values") if foreign && has_default
101
+ raise_sema_error("default parameter #{param.name} of #{decl.name} must appear after required parameters") if !has_default && any_default
102
+ any_default = true if has_default
103
+
97
104
  if external && array_type?(type)
98
105
  raise_sema_error("external function #{decl.name} cannot take array parameters")
99
106
  end
@@ -45,6 +45,46 @@ module MilkTea
45
45
  raise_sema_error("cannot use method #{binding.name} with receiver #{receiver_type}")
46
46
  end
47
47
  end
48
+ when Types::Span
49
+ return {} unless receiver_type.is_a?(Types::Span)
50
+
51
+ substitutions = {}
52
+ if declared_receiver_type.element_type.is_a?(Types::TypeVar)
53
+ substitutions[declared_receiver_type.element_type.name] = receiver_type.element_type
54
+ elsif declared_receiver_type.element_type != receiver_type.element_type
55
+ raise_sema_error("cannot use method #{binding.name} with receiver #{receiver_type}")
56
+ end
57
+ substitutions
58
+ when Types::Task
59
+ return {} unless receiver_type.is_a?(Types::Task)
60
+
61
+ substitutions = {}
62
+ if declared_receiver_type.result_type.is_a?(Types::TypeVar)
63
+ substitutions[declared_receiver_type.result_type.name] = receiver_type.result_type
64
+ elsif declared_receiver_type.result_type != receiver_type.result_type
65
+ raise_sema_error("cannot use method #{binding.name} with receiver #{receiver_type}")
66
+ end
67
+ substitutions
68
+ when Types::SoA
69
+ return {} unless receiver_type.is_a?(Types::SoA)
70
+
71
+ substitutions = {}
72
+ if declared_receiver_type.element_type.is_a?(Types::TypeVar)
73
+ substitutions[declared_receiver_type.element_type.name] = receiver_type.element_type
74
+ elsif declared_receiver_type.element_type != receiver_type.element_type
75
+ raise_sema_error("cannot use method #{binding.name} with receiver #{receiver_type}")
76
+ end
77
+ substitutions
78
+ when Types::Simd
79
+ return {} unless receiver_type.is_a?(Types::Simd)
80
+
81
+ substitutions = {}
82
+ if declared_receiver_type.element_type.is_a?(Types::TypeVar)
83
+ substitutions[declared_receiver_type.element_type.name] = receiver_type.element_type
84
+ elsif declared_receiver_type.element_type != receiver_type.element_type
85
+ raise_sema_error("cannot use method #{binding.name} with receiver #{receiver_type}")
86
+ end
87
+ substitutions
48
88
  else
49
89
  {}
50
90
  end