mt-lang 0.3.16 → 0.3.20

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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/docs/language-design.md +3 -4
  3. data/docs/language-manual.md +3 -3
  4. data/lib/milk_tea/base.rb +1 -1
  5. data/lib/milk_tea/core/{binding_types.rb → bindings.rb} +1 -1
  6. data/lib/milk_tea/core/c_backend/expressions.rb +34 -23
  7. data/lib/milk_tea/core/c_backend/feature_detection.rb +25 -45
  8. data/lib/milk_tea/core/c_backend/type_collectors.rb +18 -30
  9. data/lib/milk_tea/core/c_backend/type_declaration.rb +0 -6
  10. data/lib/milk_tea/core/c_backend.rb +63 -54
  11. data/lib/milk_tea/core/compile_time.rb +279 -74
  12. data/lib/milk_tea/core/control_flow/constant_propagation.rb +1 -1
  13. data/lib/milk_tea/core/{compatibility_helpers.rb → intrinsics.rb} +9 -2
  14. data/lib/milk_tea/core/lexer.rb +55 -48
  15. data/lib/milk_tea/core/lowering/block.rb +9 -0
  16. data/lib/milk_tea/core/lowering/calls.rb +2 -0
  17. data/lib/milk_tea/core/lowering/declarations.rb +1 -1
  18. data/lib/milk_tea/core/lowering/functions.rb +11 -8
  19. data/lib/milk_tea/core/lowering/resolve.rb +10 -3
  20. data/lib/milk_tea/core/lowering/scans.rb +13 -18
  21. data/lib/milk_tea/core/lowering.rb +18 -18
  22. data/lib/milk_tea/core/module_binder.rb +9 -10
  23. data/lib/milk_tea/core/module_loader.rb +64 -57
  24. data/lib/milk_tea/core/module_path_resolver.rb +1 -4
  25. data/lib/milk_tea/core/parser/declarations.rb +43 -19
  26. data/lib/milk_tea/core/parser/expressions.rb +4 -7
  27. data/lib/milk_tea/core/parser/statements.rb +5 -5
  28. data/lib/milk_tea/core/parser.rb +43 -17
  29. data/lib/milk_tea/core/semantic_analyzer/calls.rb +24 -31
  30. data/lib/milk_tea/core/semantic_analyzer/expressions.rb +20 -23
  31. data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +117 -85
  32. data/lib/milk_tea/core/semantic_analyzer/statements.rb +19 -41
  33. data/lib/milk_tea/core/semantic_analyzer.rb +57 -38
  34. data/lib/milk_tea/core.rb +6 -2
  35. data/lib/milk_tea/dap/lldb_dap_backend.rb +153 -0
  36. data/lib/milk_tea/dap/server/lldb_backend.rb +1 -1
  37. data/lib/milk_tea/dap.rb +1 -1
  38. data/lib/milk_tea/lsp/server/semantic_tokens.rb +6 -0
  39. data/lib/milk_tea/lsp.rb +1 -7
  40. data/lib/milk_tea/{bindings/cli.rb → tooling/bindgen_cli.rb} +1 -1
  41. data/lib/milk_tea/tooling/cli/commands/bindgen.rb +11 -0
  42. data/lib/milk_tea/tooling/cli/commands/build.rb +37 -0
  43. data/lib/milk_tea/tooling/cli/commands/cache.rb +46 -0
  44. data/lib/milk_tea/tooling/cli/commands/check.rb +116 -0
  45. data/lib/milk_tea/tooling/cli/commands/command_base.rb +8 -0
  46. data/lib/milk_tea/tooling/cli/commands/completions.rb +48 -0
  47. data/lib/milk_tea/tooling/cli/commands/dap.rb +58 -0
  48. data/lib/milk_tea/tooling/cli/commands/debug.rb +77 -0
  49. data/lib/milk_tea/tooling/cli/commands/deps.rb +17 -0
  50. data/lib/milk_tea/tooling/cli/commands/docs.rb +58 -0
  51. data/lib/milk_tea/tooling/cli/commands/emit_c.rb +64 -0
  52. data/lib/milk_tea/tooling/cli/commands/format.rb +199 -0
  53. data/lib/milk_tea/tooling/cli/commands/lex.rb +46 -0
  54. data/lib/milk_tea/tooling/cli/commands/lint.rb +248 -0
  55. data/lib/milk_tea/tooling/cli/commands/lower.rb +50 -0
  56. data/lib/milk_tea/tooling/cli/commands/lsp.rb +43 -0
  57. data/lib/milk_tea/tooling/cli/commands/new.rb +26 -0
  58. data/lib/milk_tea/tooling/cli/commands/parse.rb +51 -0
  59. data/lib/milk_tea/tooling/cli/commands/run.rb +99 -0
  60. data/lib/milk_tea/tooling/cli/commands/snapshot.rb +117 -0
  61. data/lib/milk_tea/tooling/cli/commands/test.rb +557 -0
  62. data/lib/milk_tea/tooling/cli/commands/toolchain.rb +16 -0
  63. data/lib/milk_tea/tooling/cli.rb +101 -1893
  64. data/lib/milk_tea/tooling.rb +1 -1
  65. metadata +29 -9
  66. data/lib/milk_tea/core/compile_time/const_eval.rb +0 -182
  67. data/lib/milk_tea/core/module_loader/errors.rb +0 -23
  68. data/lib/milk_tea/dap/backends/lldb_dap.rb +0 -156
  69. /data/lib/milk_tea/core/lowering/{async.rb → async/frame_builder.rb} +0 -0
@@ -645,22 +645,13 @@ module MilkTea
645
645
  )
646
646
  end
647
647
 
648
- def event_method_kind(receiver_type, name)
649
- return unless event_type?(receiver_type)
648
+ def specialized_receiver_method_kind(receiver_type, name)
649
+ SPECIALIZED_RECEIVERS.each_value do |spec|
650
+ next unless send(spec[:predicate], receiver_type)
650
651
 
651
- EVENT_METHOD_KINDS[name]
652
- end
653
-
654
- def atomic_method_kind(receiver_type, name)
655
- return unless atomic_type?(receiver_type)
656
-
657
- ATOMIC_METHOD_KINDS[name]
658
- end
659
-
660
- def simd_method_kind(receiver_type, name)
661
- return unless simd_type?(receiver_type)
662
-
663
- SIMD_METHOD_KINDS[name]
652
+ return spec[:kinds][name]
653
+ end
654
+ nil
664
655
  end
665
656
 
666
657
  def check_atomic_method_call(kind, receiver_type, receiver, arguments, scopes:)
@@ -750,8 +741,8 @@ module MilkTea
750
741
 
751
742
  case expression
752
743
  when AST::Call
753
- callable_kind, callable, _receiver = resolve_callable(expression.callee, scopes:)
754
- callable_kind == :struct && callable == target_type
744
+ resolution = resolve_callable(expression.callee, scopes:)
745
+ resolution.kind == :struct && resolution.value == target_type
755
746
  when AST::Specialization
756
747
  return false unless expression.callee.is_a?(AST::Identifier)
757
748
  return false unless %w[zero default].include?(expression.callee.name)
@@ -772,12 +763,6 @@ module MilkTea
772
763
  name == "as_str" || name == "as_cstr"
773
764
  end
774
765
 
775
- def str_buffer_method_kind(receiver_type, name)
776
- return unless str_buffer_type?(receiver_type)
777
-
778
- STR_BUFFER_METHOD_KINDS[name]
779
- end
780
-
781
766
  def str_buffer_method_name(kind)
782
767
  STR_BUFFER_METHOD_NAMES.fetch(kind)
783
768
  end
@@ -1032,42 +1017,50 @@ module MilkTea
1032
1017
  end
1033
1018
  end
1034
1019
 
1035
- fill_parameter_defaults!(by_position, params, binding, context_name)
1020
+ fill_parameter_defaults!(by_position, params, binding)
1036
1021
 
1037
1022
  by_position.reject(&:nil?)
1038
1023
  end
1039
1024
 
1040
- def fill_parameter_defaults!(by_position, params, binding, context_name)
1025
+ def fill_parameter_defaults!(by_position, params, binding)
1041
1026
  return unless binding
1042
1027
 
1043
1028
  ast_params = binding.ast.params
1044
- return unless ast_params.any? { |p| p.respond_to?(:default_value) && p.default_value }
1029
+ return unless ast_params.any? { |p| param_has_default?(p) }
1045
1030
 
1046
1031
  params.each_with_index do |param, idx|
1047
1032
  next unless by_position[idx].nil?
1048
1033
  next unless idx < ast_params.length
1049
1034
 
1050
1035
  ast_param = ast_params[idx]
1051
- next unless ast_param.respond_to?(:default_value) && ast_param.default_value
1036
+ next unless param_has_default?(ast_param)
1052
1037
 
1053
- by_position[idx] = AST::Argument.new(name: nil, value: ast_param.default_value)
1038
+ by_position[idx] = default_arg_for(ast_param)
1054
1039
  end
1055
1040
  end
1056
1041
 
1057
1042
  def fill_positional_defaults!(arguments, binding)
1058
- return unless binding.ast.params.any? { |p| p.respond_to?(:default_value) && p.default_value }
1043
+ return unless binding.ast.params.any? { |p| param_has_default?(p) }
1059
1044
 
1060
1045
  ast_params = binding.ast.params
1061
1046
  while arguments.length < ast_params.length
1062
1047
  ast_param = ast_params[arguments.length]
1063
- if ast_param.respond_to?(:default_value) && ast_param.default_value
1064
- arguments << AST::Argument.new(name: nil, value: ast_param.default_value)
1048
+ if param_has_default?(ast_param)
1049
+ arguments << default_arg_for(ast_param)
1065
1050
  else
1066
1051
  break
1067
1052
  end
1068
1053
  end
1069
1054
  end
1070
1055
 
1056
+ def param_has_default?(ast_param)
1057
+ ast_param.respond_to?(:default_value) && ast_param.default_value
1058
+ end
1059
+
1060
+ def default_arg_for(ast_param)
1061
+ AST::Argument.new(name: nil, value: ast_param.default_value)
1062
+ end
1063
+
1071
1064
  def count_required_params(binding)
1072
1065
  return binding.type.params.length unless binding.ast.params.any? { |p| p.respond_to?(:default_value) && p.default_value }
1073
1066
 
@@ -199,8 +199,8 @@ module MilkTea
199
199
  when AST::Specialization
200
200
  if expression.callee.is_a?(AST::Identifier)
201
201
  if expression.callee.name == "zero"
202
- callable_kind, callable, = resolve_callable(expression, scopes:)
203
- return check_zero_call(callable, [], expected_type:) if callable_kind == :zero
202
+ resolution = resolve_callable(expression, scopes:)
203
+ return check_zero_call(resolution.value, [], expected_type:) if resolution.kind == :zero
204
204
  end
205
205
 
206
206
  if expression.callee.name == "default"
@@ -397,10 +397,7 @@ module MilkTea
397
397
  if char_array_removed_text_method?(method_receiver_type, expression.member)
398
398
  raise_sema_error("#{method_receiver_type}.#{expression.member} is not available; array[char, N] is raw storage, use str_buffer[N] or an explicit helper")
399
399
  end
400
- if str_buffer_type?(method_receiver_type) && str_buffer_method_kind(method_receiver_type, expression.member)
401
- raise_sema_error("method #{method_receiver_type}.#{expression.member} must be called")
402
- end
403
- if event_type?(method_receiver_type) && event_method_kind(method_receiver_type, expression.member)
400
+ if specialized_receiver_method_kind(method_receiver_type, expression.member)
404
401
  raise_sema_error("method #{method_receiver_type}.#{expression.member} must be called")
405
402
  end
406
403
 
@@ -923,7 +920,10 @@ module MilkTea
923
920
  end
924
921
 
925
922
  def infer_call(expression, scopes:, expected_type: nil)
926
- callable_kind, callable, receiver = resolve_callable(expression.callee, scopes:)
923
+ resolution = resolve_callable(expression.callee, scopes:)
924
+ callable_kind = resolution.kind
925
+ callable = resolution.value
926
+ receiver = resolution.receiver
927
927
  @resolved_call_kinds[@ctx.ast.node_ids[expression.callee.object_id]] = callable_kind
928
928
 
929
929
  case callable_kind
@@ -1152,7 +1152,9 @@ module MilkTea
1152
1152
  call = expression
1153
1153
  return unless call.is_a?(AST::Call)
1154
1154
 
1155
- callable_kind, callable, _receiver = resolve_callable(call.callee, scopes:)
1155
+ resolution = resolve_callable(call.callee, scopes:)
1156
+ callable_kind = resolution.kind
1157
+ callable = resolution.value
1156
1158
  return unless callable_kind == :function
1157
1159
 
1158
1160
  callable = specialize_function_binding(
@@ -1245,6 +1247,11 @@ module MilkTea
1245
1247
  end
1246
1248
 
1247
1249
  def resolve_callable(callee, scopes:)
1250
+ kind, value, receiver = resolve_callable_raw(callee, scopes:)
1251
+ CallableResolution.new(kind:, value:, receiver:)
1252
+ end
1253
+
1254
+ def resolve_callable_raw(callee, scopes:)
1248
1255
  case callee
1249
1256
  when AST::Identifier
1250
1257
  if (binding = lookup_value(callee.name, scopes))
@@ -1343,20 +1350,8 @@ module MilkTea
1343
1350
  raise_sema_error("#{method_receiver_type}.#{callee.member} is not available; array[char, N] is raw storage, use str_buffer[N] or an explicit helper")
1344
1351
  end
1345
1352
 
1346
- if (str_buffer_method = str_buffer_method_kind(method_receiver_type, callee.member))
1347
- return [str_buffer_method, method_receiver_type, callee.receiver]
1348
- end
1349
-
1350
- if (event_method = event_method_kind(method_receiver_type, callee.member))
1351
- return [event_method, method_receiver_type, callee.receiver]
1352
- end
1353
-
1354
- if (atomic_method = atomic_method_kind(method_receiver_type, callee.member))
1355
- return [atomic_method, method_receiver_type, callee.receiver]
1356
- end
1357
-
1358
- if (simd_method = simd_method_kind(method_receiver_type, callee.member))
1359
- return [simd_method, method_receiver_type, callee.receiver]
1353
+ if (kind = specialized_receiver_method_kind(method_receiver_type, callee.member))
1354
+ return [kind, method_receiver_type, callee.receiver]
1360
1355
  end
1361
1356
 
1362
1357
  field_receiver_type = infer_field_receiver_type(callee.receiver, scopes:)
@@ -1574,7 +1569,9 @@ module MilkTea
1574
1569
  end
1575
1570
 
1576
1571
  def resolve_callable_handle_argument(expression, scopes:)
1577
- callable_kind, callable, _receiver = resolve_callable(expression, scopes:)
1572
+ resolution = resolve_callable(expression, scopes:)
1573
+ callable_kind = resolution.kind
1574
+ callable = resolution.value
1578
1575
  raise_sema_error("callable_of expects a callable declaration name") unless callable_kind == :function
1579
1576
 
1580
1577
  Types::CallableHandle.new(describe_expression(expression), callable.ast)
@@ -211,123 +211,148 @@ module MilkTea
211
211
 
212
212
  def resolve_non_nullable_type(type_ref, type_params: {}, type_param_constraints: {}, nested_types: nil)
213
213
  if type_ref.is_a?(AST::FunctionType)
214
- params = type_ref.params.map do |param|
215
- Types::Registry.parameter(param.name, resolve_type_ref(param.type, type_params:, type_param_constraints:))
216
- end
217
- return Types::Registry.function(nil, params:, return_type: resolve_type_ref(type_ref.return_type, type_params:, type_param_constraints:))
214
+ return resolve_function_type_ref(type_ref, type_params:, type_param_constraints:)
218
215
  end
219
216
 
220
217
  if type_ref.is_a?(AST::ProcType)
221
- params = type_ref.params.map do |param|
222
- Types::Registry.parameter(param.name, resolve_type_ref(param.type, type_params:, type_param_constraints:))
223
- end
224
- return Types::Registry.proc(params:, return_type: resolve_type_ref(type_ref.return_type, type_params:, type_param_constraints:))
218
+ return resolve_proc_type_ref(type_ref, type_params:, type_param_constraints:)
225
219
  end
226
220
 
227
221
  if type_ref.is_a?(AST::DynType)
228
- interface = resolve_interface_ref(type_ref.interface)
229
- raise_sema_error("generic interface #{interface.name} requires type arguments") if interface.is_a?(GenericInterfaceBinding)
230
- type_arguments = interface.type_arguments || []
231
- type = Types::Dyn.new(interface, type_arguments)
232
- type = Types::Registry.nullable(type) if type_ref.nullable
233
- return type
222
+ return resolve_dyn_type_ref(type_ref)
234
223
  end
235
224
 
236
225
  if type_ref.is_a?(AST::TupleType)
237
- names = []
238
- element_types = []
239
- type_ref.element_types.each do |et|
240
- if et.is_a?(AST::Argument)
241
- names << et.name
242
- element_types << resolve_type_ref(et.value, type_params:, type_param_constraints:)
243
- else
244
- names << nil
245
- element_types << resolve_type_ref(et, type_params:, type_param_constraints:)
246
- end
247
- end
248
- has_named = names.any?
249
- return Types::Registry.tuple(element_types, field_names: has_named ? names : nil)
226
+ return resolve_tuple_type_ref(type_ref, type_params:, type_param_constraints:)
250
227
  end
251
228
 
252
229
  parts = type_ref.name.parts
253
230
 
254
231
  if type_ref.arguments.any?
255
- name = parts.join(".")
256
- arguments = type_ref.arguments.map { |argument| resolve_type_argument(argument.value, type_params:, type_param_constraints:) }
257
-
258
- if name != "ref" && arguments.any? { |argument| contains_ref_type?(argument) && !stored_ref_supported_type?(argument) }
259
- raise_sema_error("ref types cannot be nested inside #{name}", type_ref)
260
- end
232
+ return resolve_generic_instance_type_ref(type_ref, parts, type_params:, type_param_constraints:)
233
+ end
261
234
 
262
- if name == "Task"
263
- validate_generic_type!(name, arguments)
264
- return Types::Registry.task(arguments[0])
265
- end
235
+ if parts.length == 1 && type_ref.lifetime
236
+ raise_sema_error("lifetime annotations are only valid on ref types, got #{type_ref.name}", type_ref)
237
+ end
266
238
 
267
- if (generic_type = resolve_named_generic_type(parts))
268
- begin
269
- validate_generic_type_param_constraints!(generic_type, arguments, context: "type #{generic_type}", available_type_param_constraints: type_param_constraints)
270
- return generic_type.instantiate(arguments)
271
- rescue ArgumentError => error
272
- raise_sema_error(error.message)
273
- end
274
- end
239
+ if parts.length == 1
240
+ return resolve_single_part_type_ref(type_ref, parts.first, nested_types:, type_params:)
241
+ end
275
242
 
276
- # Handle types with lifetime params only (no type params)
277
- if arguments.all? { |a| a.is_a?(Types::LifetimeRef) }
278
- type = @ctx.types[name]
279
- if type.is_a?(Types::Struct) && type.lifetime_params&.any?
280
- lifetime_args = arguments.select { |a| a.is_a?(Types::LifetimeRef) }.map(&:name)
281
- if lifetime_args.to_set == type.lifetime_params.to_set
282
- return type
283
- end
284
- end
285
- end
243
+ resolve_multi_part_type_ref(type_ref, parts)
244
+ end
286
245
 
287
- validate_generic_type!(name, arguments)
288
- return Types::Registry.span(arguments.first) if name == "span"
246
+ def resolve_function_type_ref(type_ref, type_params:, type_param_constraints:)
247
+ params = type_ref.params.map do |param|
248
+ Types::Registry.parameter(param.name, resolve_type_ref(param.type, type_params:, type_param_constraints:))
249
+ end
250
+ Types::Registry.function(nil, params:, return_type: resolve_type_ref(type_ref.return_type, type_params:, type_param_constraints:))
251
+ end
289
252
 
290
- return Types::Registry.soa(arguments[0], count: arguments[1].value) if name == "SoA"
253
+ def resolve_proc_type_ref(type_ref, type_params:, type_param_constraints:)
254
+ params = type_ref.params.map do |param|
255
+ Types::Registry.parameter(param.name, resolve_type_ref(param.type, type_params:, type_param_constraints:))
256
+ end
257
+ Types::Registry.proc(params:, return_type: resolve_type_ref(type_ref.return_type, type_params:, type_param_constraints:))
258
+ end
291
259
 
292
- return Types::Registry.simd(arguments[0], lane_count: arguments[1].value) if name == "simd"
260
+ def resolve_dyn_type_ref(type_ref)
261
+ interface = resolve_interface_ref(type_ref.interface)
262
+ raise_sema_error("generic interface #{interface.name} requires type arguments") if interface.is_a?(GenericInterfaceBinding)
263
+ type_arguments = interface.type_arguments || []
264
+ type = Types::Dyn.new(interface, type_arguments)
265
+ type = Types::Registry.nullable(type) if type_ref.nullable
266
+ type
267
+ end
293
268
 
294
- arguments = [type_ref.lifetime] + arguments if name == "ref" && type_ref.lifetime
295
- return Types::Registry.generic_instance(name, arguments)
269
+ def resolve_tuple_type_ref(type_ref, type_params:, type_param_constraints:)
270
+ names = []
271
+ element_types = []
272
+ type_ref.element_types.each do |et|
273
+ if et.is_a?(AST::Argument)
274
+ names << et.name
275
+ element_types << resolve_type_ref(et.value, type_params:, type_param_constraints:)
276
+ else
277
+ names << nil
278
+ element_types << resolve_type_ref(et, type_params:, type_param_constraints:)
279
+ end
296
280
  end
281
+ has_named = names.any?
282
+ Types::Registry.tuple(element_types, field_names: has_named ? names : nil)
283
+ end
297
284
 
298
- if parts.length == 1 && type_ref.lifetime
299
- raise_sema_error("lifetime annotations are only valid on ref types, got #{type_ref.name}", type_ref)
300
- end
285
+ def resolve_generic_instance_type_ref(type_ref, parts, type_params:, type_param_constraints:)
286
+ name = parts.join(".")
287
+ arguments = type_ref.arguments.map { |argument| resolve_type_argument(argument.value, type_params:, type_param_constraints:) }
301
288
 
302
- if parts.length == 1
303
- return type_params.fetch(parts.first) if type_params.key?(parts.first)
289
+ if name != "ref" && arguments.any? { |argument| contains_ref_type?(argument) && !stored_ref_supported_type?(argument) }
290
+ raise_sema_error("ref types cannot be nested inside #{name}", type_ref)
291
+ end
304
292
 
305
- if nested_types && (type = nested_types[parts.first])
306
- return type
307
- end
293
+ if name == "Task"
294
+ validate_generic_type!(name, arguments)
295
+ return Types::Registry.task(arguments[0])
296
+ end
308
297
 
309
- if parts.first.start_with?("@")
310
- raise_sema_error("unknown lifetime #{parts.first}", type_ref)
298
+ if (generic_type = resolve_named_generic_type(parts))
299
+ begin
300
+ validate_generic_type_param_constraints!(generic_type, arguments, context: "type #{generic_type}", available_type_param_constraints: type_param_constraints)
301
+ return generic_type.instantiate(arguments)
302
+ rescue ArgumentError => error
303
+ raise_sema_error(error.message)
311
304
  end
305
+ end
312
306
 
313
- type = @ctx.types[parts.first]
314
- unless type
315
- type_names = @ctx.types.keys
316
- suggestion = suggest_name(parts.first, type_names)
317
- unless suggestion
318
- suggestion = import_suggestion_for_type(parts.first)
307
+ if arguments.all? { |a| a.is_a?(Types::LifetimeRef) }
308
+ type = @ctx.types[name]
309
+ if type.is_a?(Types::Struct) && type.lifetime_params&.any?
310
+ lifetime_args = arguments.select { |a| a.is_a?(Types::LifetimeRef) }.map(&:name)
311
+ if lifetime_args.to_set == type.lifetime_params.to_set
312
+ return type
319
313
  end
320
- raise_sema_error("unknown type #{parts.first}", type_ref, suggestion: suggestion ? "did you mean '#{suggestion}'?" : nil)
321
314
  end
322
- raise_sema_error("generic type #{parts.first} requires type arguments", type_ref) if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
315
+ end
316
+
317
+ validate_generic_type!(name, arguments)
318
+ return Types::Registry.span(arguments.first) if name == "span"
319
+
320
+ return Types::Registry.soa(arguments[0], count: arguments[1].value) if name == "SoA"
321
+
322
+ return Types::Registry.simd(arguments[0], lane_count: arguments[1].value) if name == "simd"
323
+
324
+ arguments = [type_ref.lifetime] + arguments if name == "ref" && type_ref.lifetime
325
+ Types::Registry.generic_instance(name, arguments)
326
+ end
327
+
328
+ def resolve_single_part_type_ref(type_ref, name, nested_types:, type_params:)
329
+ return type_params.fetch(name) if type_params.key?(name)
323
330
 
331
+ if nested_types && (type = nested_types[name])
324
332
  return type
325
333
  end
326
334
 
327
- if parts.length >= 2
328
- type = resolve_nested_type_ref(parts)
329
- return type if type
335
+ if name.start_with?("@")
336
+ raise_sema_error("unknown lifetime #{name}", type_ref)
337
+ end
338
+
339
+ type = @ctx.types[name]
340
+ unless type
341
+ type_names = @ctx.types.keys
342
+ suggestion = suggest_name(name, type_names)
343
+ unless suggestion
344
+ suggestion = import_suggestion_for_type(name)
345
+ end
346
+ raise_sema_error("unknown type #{name}", type_ref, suggestion: suggestion ? "did you mean '#{suggestion}'?" : nil)
330
347
  end
348
+ raise_sema_error("generic type #{name} requires type arguments", type_ref) if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
349
+
350
+ type
351
+ end
352
+
353
+ def resolve_multi_part_type_ref(type_ref, parts)
354
+ type = resolve_nested_type_ref(parts)
355
+ return type if type
331
356
 
332
357
  if parts.length == 2 && @ctx.imports.key?(parts.first)
333
358
  imported_module = @ctx.imports.fetch(parts.first)
@@ -386,12 +411,19 @@ module MilkTea
386
411
  def resolve_type_argument_ref(type_ref, type_params:, type_param_constraints:)
387
412
  return resolve_type_ref(type_ref, type_params:, type_param_constraints:) unless literal_type_argument_name_candidate?(type_ref)
388
413
 
389
- resolve_type_ref(type_ref, type_params:, type_param_constraints:)
390
- rescue SemanticError => error
414
+ result = try_resolve_type_ref(type_ref, type_params:, type_param_constraints:)
415
+ return result if result
416
+
391
417
  literal_type_argument = resolve_named_literal_type_argument(type_ref)
392
418
  return literal_type_argument if literal_type_argument
393
419
 
394
- raise error
420
+ resolve_type_ref(type_ref, type_params:, type_param_constraints:)
421
+ end
422
+
423
+ def try_resolve_type_ref(type_ref, type_params:, type_param_constraints:)
424
+ resolve_type_ref(type_ref, type_params:, type_param_constraints:)
425
+ rescue SemanticError
426
+ nil
395
427
  end
396
428
 
397
429
  def literal_type_argument_name_candidate?(type_ref)
@@ -555,30 +555,32 @@ module MilkTea
555
555
  end
556
556
  end
557
557
 
558
+ MATCH_STMT_DISPATCH = [
559
+ [Types::Enum, :each_enum_match_arm, true],
560
+ [Types::Variant, :each_variant_match_arm, true],
561
+ [:integer, :each_integer_match_arm, false],
562
+ [Types::StringView, :each_string_match_arm, false],
563
+ [Types::Tuple, :each_tuple_match_arm, false],
564
+ ].freeze
565
+
558
566
  def check_match_stmt(statement, scopes:, return_type:, allow_return:)
559
567
  validate_consuming_foreign_expression!(statement.expression, scopes:, root_allowed: false)
560
568
  scrutinee_type = infer_expression(statement.expression, scopes:)
569
+
561
570
  if error_type?(scrutinee_type)
562
- check_recovered_match_stmt(statement, scopes:, return_type:, allow_return:)
563
- elsif scrutinee_type.is_a?(Types::Enum)
564
- check_enum_match_stmt(statement, scrutinee_type, scopes:, return_type:, allow_return:)
565
- elsif scrutinee_type.is_a?(Types::Variant)
566
- check_variant_match_stmt(statement, scrutinee_type, scopes:, return_type:, allow_return:)
567
- elsif integer_type?(scrutinee_type)
568
- check_integer_match_stmt(statement, scrutinee_type, scopes:, return_type:, allow_return:)
569
- elsif scrutinee_type.is_a?(Types::StringView)
570
- check_string_match_stmt(statement, scrutinee_type, scopes:, return_type:, allow_return:)
571
- elsif scrutinee_type.is_a?(Types::Tuple)
572
- check_tuple_match_stmt(statement, scrutinee_type, scopes:, return_type:, allow_return:)
573
- else
574
- raise_sema_error("match requires an enum, variant, or integer scrutinee, got #{scrutinee_type}")
571
+ return check_recovered_match_stmt(statement, scopes:, return_type:, allow_return:)
575
572
  end
576
- end
577
573
 
578
- def check_enum_match_stmt(statement, scrutinee_type, scopes:, return_type:, allow_return:)
579
- each_enum_match_arm(statement, scrutinee_type, scopes:) do |arm, arm_scopes|
580
- check_block(arm.body, scopes: arm_scopes, return_type:, allow_return:)
574
+ MATCH_STMT_DISPATCH.each do |type_class, arm_method, per_arm_scopes|
575
+ next unless type_class == :integer ? integer_type?(scrutinee_type) : scrutinee_type.is_a?(type_class)
576
+
577
+ send(arm_method, statement, scrutinee_type, scopes:) do |arm, arm_scopes|
578
+ check_block(arm.body, scopes: per_arm_scopes ? arm_scopes : scopes, return_type:, allow_return:)
579
+ end
580
+ return
581
581
  end
582
+
583
+ raise_sema_error("match requires an enum, variant, or integer scrutinee, got #{scrutinee_type}")
582
584
  end
583
585
 
584
586
  def each_enum_match_arm(statement, scrutinee_type, scopes:)
@@ -746,24 +748,6 @@ module MilkTea
746
748
  end
747
749
  end
748
750
 
749
- def check_integer_match_stmt(statement, scrutinee_type, scopes:, return_type:, allow_return:)
750
- each_integer_match_arm(statement, scrutinee_type, scopes:) do |arm|
751
- check_block(arm.body, scopes:, return_type:, allow_return:)
752
- end
753
- end
754
-
755
- def check_string_match_stmt(statement, scrutinee_type, scopes:, return_type:, allow_return:)
756
- each_string_match_arm(statement, scrutinee_type, scopes:) do |arm|
757
- check_block(arm.body, scopes:, return_type:, allow_return:)
758
- end
759
- end
760
-
761
- def check_tuple_match_stmt(statement, scrutinee_type, scopes:, return_type:, allow_return:)
762
- each_tuple_match_arm(statement, scrutinee_type, scopes:) do |arm|
763
- check_block(arm.body, scopes:, return_type:, allow_return:)
764
- end
765
- end
766
-
767
751
  def wildcard_pattern?(expression)
768
752
  expression.is_a?(AST::Identifier) && expression.name == "_"
769
753
  end
@@ -810,12 +794,6 @@ module MilkTea
810
794
  failure_fields && failure_fields.length == 1 && failure_fields.key?("error")
811
795
  end
812
796
 
813
- def check_variant_match_stmt(statement, scrutinee_type, scopes:, return_type:, allow_return:)
814
- each_variant_match_arm(statement, scrutinee_type, scopes:) do |arm, arm_scopes|
815
- check_block(arm.body, scopes: arm_scopes, return_type:, allow_return:)
816
- end
817
- end
818
-
819
797
  def each_variant_match_arm(statement, scrutinee_type, scopes:)
820
798
  covered_arms = {}
821
799
  wildcard_seen = false