mt-lang 0.3.32 → 0.3.34

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0210a7132e7230d11f390c51bf60c7ff5a19b0d7716737b3ed5ac89b4a773842
4
- data.tar.gz: 54d1170e9f9630b6747062b2ee8d285cb3b8cb83f5399469ba3b7908f81ad654
3
+ metadata.gz: 8d0786ef5ca9025e069a44b7ea3915199110e1f2397d294ed81122a308c79e2e
4
+ data.tar.gz: 42e3fa0077192377fa7da61cea865fd04e8ef49d66343c71a1bd5e2e1caa8b59
5
5
  SHA512:
6
- metadata.gz: 2ca666aaa8bceb581fbe3a54c315127a3dbe3bb1a7a122027d9af44f96c3095d352d3f10f65f3e4d31b4992bca017eca600e7216c16a9a71ec81f1d0fb8091a7
7
- data.tar.gz: 6d143563d49aae6636133feaa6bac2b0bee00e468d972c48db3d665692624341f4d5cbbe880fe9ba91aa0aec7da0c253df1facc5d4c405ddcd44778e67ca7ca9
6
+ metadata.gz: fd4a874279ff48b7d0f1de8baf092e92e01ede8a4c969133855c9dd9c9f061490c11ff29dfc24905466fe1df56d1d53a86a5c156ce1cbe5efeed60d78f5a21e8
7
+ data.tar.gz: 30bb123ddb1939f7694c62dae186152b8f592d78826e7b4aa416c6a010202d07bda5474b72014114d8064b7168ff02b6b7dd252a8b7d007d9b9bcae8b31b4786
data/lib/milk_tea/base.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  require "pathname"
4
4
 
5
5
  module MilkTea
6
- VERSION = "0.3.32"
6
+ VERSION = "0.3.34"
7
7
 
8
8
  def self.root
9
9
  @root ||= Pathname.new(File.expand_path("../..", __dir__))
@@ -437,7 +437,7 @@ module MilkTea
437
437
  resolve_identifier: ->(id) { @variables[id.name] || @checker.evaluate_compile_time_const_value(id, scopes:) },
438
438
  resolve_member_access: ->(ma) { @checker.evaluate_compile_time_const_value(ma, scopes:) },
439
439
  resolve_type_ref: nil,
440
- resolve_call: nil,
440
+ resolve_call: ->(call_expr) { resolve_compile_time_call(call_expr, scopes:) },
441
441
  )
442
442
  end
443
443
  return nil unless arg_value
@@ -56,16 +56,10 @@ module MilkTea
56
56
  def build_statement(stmt, next_id, break_target:, continue_target:)
57
57
  case stmt
58
58
  when AST::LocalDecl
59
- if stmt.else_body
60
- reads, reads_info = read_identifiers_with_sites(stmt.value)
61
- writes = Set.new
62
- writes_info = []
63
- declaration_key = declaration_binding_key(stmt, stmt.name)
64
- if declaration_key && (stmt.value || @local_decl_without_initializer_writes)
65
- writes << declaration_key
66
- writes_info << { name: stmt.name, binding_key: declaration_key, line: stmt.line, column: stmt.column, origin: :declaration }
67
- end
59
+ reads, reads_info = read_identifiers_with_sites(stmt.value)
60
+ writes, writes_info = local_decl_write_targets(stmt, stmt.name)
68
61
 
62
+ if stmt.else_body
69
63
  success_id = add_linear_node(:local_decl, stmt, next_id, writes:, writes_info:)
70
64
  null_entry = build_block(stmt.else_body, next_id, break_target:, continue_target:)
71
65
  condition_id = @graph.add_node(
@@ -80,14 +74,6 @@ module MilkTea
80
74
  return condition_id
81
75
  end
82
76
 
83
- reads, reads_info = read_identifiers_with_sites(stmt.value)
84
- writes = Set.new
85
- writes_info = []
86
- declaration_key = declaration_binding_key(stmt, stmt.name)
87
- if declaration_key && (stmt.value || @local_decl_without_initializer_writes)
88
- writes << declaration_key
89
- writes_info << { name: stmt.name, binding_key: declaration_key, line: stmt.line, column: stmt.column, origin: :declaration }
90
- end
91
77
  add_linear_node(:local_decl, stmt, next_id, reads:, reads_info:, writes:, writes_info:)
92
78
  when AST::Assignment
93
79
  reads, reads_info = read_identifiers_with_sites(stmt.value)
@@ -213,13 +199,10 @@ module MilkTea
213
199
  build_block(stmt.body, next_id, break_target:, continue_target:)
214
200
  when AST::DeferStmt
215
201
  body_entry = build_block(stmt.body, next_id, break_target:, continue_target:)
216
- expression_reads, expression_reads_info = statement_list_reads_with_sites(stmt.body)
217
202
  defer_id = @graph.add_node(
218
203
  kind: :defer,
219
204
  statement: stmt,
220
205
  line: stmt.line,
221
- reads: expression_reads,
222
- reads_info: expression_reads_info,
223
206
  )
224
207
  @graph.add_edge(defer_id, body_entry)
225
208
  defer_id
@@ -315,66 +298,6 @@ module MilkTea
315
298
  [reads, reads_info]
316
299
  end
317
300
 
318
- def statement_list_reads_with_sites(statements)
319
- reads = Set.new
320
- reads_info = []
321
- statement_list_read_identifiers(statements, reads, reads_info)
322
- [reads, reads_info]
323
- end
324
-
325
- def statement_list_read_identifiers(statements, reads, reads_info)
326
- Array(statements).each do |statement|
327
- statement_read_identifiers(statement, reads, reads_info)
328
- end
329
- end
330
-
331
- def statement_read_identifiers(statement, reads, reads_info)
332
- case statement
333
- when AST::ExpressionStmt
334
- read_identifiers(statement.expression, reads, reads_info)
335
- when AST::DeferStmt
336
- statement_list_read_identifiers(statement.body, reads, reads_info)
337
- when AST::LocalDecl
338
- read_identifiers(statement.value, reads, reads_info)
339
- statement_list_read_identifiers(statement.else_body, reads, reads_info)
340
- when AST::Assignment
341
- read_identifiers(statement.target, reads, reads_info)
342
- read_identifiers(statement.value, reads, reads_info)
343
- when AST::ReturnStmt
344
- read_identifiers(statement.value, reads, reads_info)
345
- when AST::IfStmt
346
- statement.branches.each do |branch|
347
- read_identifiers(branch.condition, reads, reads_info)
348
- statement_list_read_identifiers(branch.body, reads, reads_info)
349
- end
350
- statement_list_read_identifiers(statement.else_body, reads, reads_info)
351
- when AST::WhileStmt
352
- read_identifiers(statement.condition, reads, reads_info)
353
- statement_list_read_identifiers(statement.body, reads, reads_info)
354
- when AST::ForStmt
355
- statement.iterables.each { |iterable| read_identifiers(iterable, reads, reads_info) }
356
- statement_list_read_identifiers(statement.body, reads, reads_info)
357
- when AST::UnsafeStmt
358
- statement_list_read_identifiers(statement.body, reads, reads_info)
359
- when AST::MatchStmt
360
- read_identifiers(statement.expression, reads, reads_info)
361
- statement.arms.each do |arm|
362
- read_identifiers(arm.pattern, reads, reads_info)
363
- statement_list_read_identifiers(arm.body, reads, reads_info)
364
- end
365
- when AST::StaticAssert
366
- read_identifiers(statement.condition, reads, reads_info)
367
- read_identifiers(statement.message, reads, reads_info)
368
- when AST::WhenStmt
369
- read_identifiers(statement.discriminant, reads, reads_info)
370
- statement.branches.each do |branch|
371
- read_identifiers(branch.pattern, reads, reads_info)
372
- statement_list_read_identifiers(branch.body, reads, reads_info)
373
- end
374
- statement_list_read_identifiers(statement.else_body, reads, reads_info)
375
- end
376
- end
377
-
378
301
  def read_identifiers(expression, names = Set.new, reads_info = [])
379
302
  case expression
380
303
  when nil
@@ -582,6 +505,18 @@ module MilkTea
582
505
  name
583
506
  end
584
507
 
508
+ def local_decl_write_targets(stmt, name)
509
+ writes = Set.new
510
+ writes_info = []
511
+ declaration_key = declaration_binding_key(stmt, name)
512
+ if declaration_key && (stmt.value || @local_decl_without_initializer_writes)
513
+ writes << declaration_key
514
+ writes_info << { name:, binding_key: declaration_key, line: stmt.line, column: stmt.column, origin: :declaration }
515
+ end
516
+ write_targets_from_expression(stmt.value, line: stmt.line, writes:, writes_info:)
517
+ [writes, writes_info]
518
+ end
519
+
585
520
  def add_null_test_refinements(cond_id, true_succ, false_succ, condition)
586
521
  pairs = null_check_pairs(condition, positive: true)
587
522
  return if pairs.empty?
@@ -26,9 +26,9 @@ module MilkTea
26
26
 
27
27
  next if type == Types::BUILTIN_TYPE_META_TYPE
28
28
 
29
- if const_value && (decl.value.is_a?(AST::Call) || decl.value.is_a?(AST::Specialization))
29
+ if !const_value.nil? && (decl.value.is_a?(AST::Call) || decl.value.is_a?(AST::Specialization))
30
30
  value = lower_const_value_literal(type, const_value)
31
- elsif const_value && (decl.block_body || decl.value.is_a?(AST::ExpressionList))
31
+ elsif !const_value.nil? && (decl.block_body || decl.value.is_a?(AST::ExpressionList))
32
32
  if const_value.is_a?(Array) && const_value.empty? && decl.value.is_a?(AST::ExpressionList) && !decl.value.elements.empty?
33
33
  value = lower_static_storage_initializer(decl.value, env: empty_env, expected_type: type)
34
34
  else
@@ -38,12 +38,46 @@ module MilkTea
38
38
  raise LoweringError.new("constant #{decl.name} has no compile-time value", line: decl.line, column: decl.column)
39
39
  else
40
40
  value = lower_static_storage_initializer(decl.value, env: empty_env, expected_type: type)
41
+ if (decl.value.is_a?(AST::Call) || decl.value.is_a?(AST::Specialization)) && static_initializer_ir_has_call?(value)
42
+ raise LoweringError.new("constant #{decl.name} initializer is not a compile-time value", line: decl.line, column: decl.column, path: @ctx.current_analysis_path)
43
+ end
41
44
  end
42
45
 
43
46
  IR::Constant.new(name: decl.name, linkage_name: value_c_name(decl.name), type:, value:, line: decl.line, path: @ctx.current_analysis_path)
44
47
  end
45
48
  end
46
49
 
50
+ def static_initializer_ir_has_call?(node)
51
+ case node
52
+ when IR::Call
53
+ true
54
+ when IR::AggregateLiteral
55
+ node.fields.any? { |field| static_initializer_ir_has_call?(field.value) }
56
+ when IR::ArrayLiteral
57
+ node.elements.any? { |element| static_initializer_ir_has_call?(element) }
58
+ when IR::VariantLiteral
59
+ node.fields.any? { |field| static_initializer_ir_has_call?(field.value) }
60
+ when IR::Binary
61
+ static_initializer_ir_has_call?(node.left) || static_initializer_ir_has_call?(node.right)
62
+ when IR::Unary
63
+ static_initializer_ir_has_call?(node.operand)
64
+ when IR::Conditional
65
+ static_initializer_ir_has_call?(node.condition) || static_initializer_ir_has_call?(node.then_expression) || static_initializer_ir_has_call?(node.else_expression)
66
+ when IR::Cast
67
+ static_initializer_ir_has_call?(node.expression)
68
+ when IR::AddressOf
69
+ static_initializer_ir_has_call?(node.expression)
70
+ when IR::Member
71
+ static_initializer_ir_has_call?(node.receiver)
72
+ when IR::Index, IR::CheckedIndex, IR::CheckedSpanIndex, IR::NullableIndex, IR::NullableSpanIndex
73
+ static_initializer_ir_has_call?(node.receiver) || static_initializer_ir_has_call?(node.index)
74
+ when IR::ReinterpretExpr
75
+ static_initializer_ir_has_call?(node.expression)
76
+ else
77
+ false
78
+ end
79
+ end
80
+
47
81
  def lower_const_value_literal(type, const_value)
48
82
  case const_value
49
83
  when Integer
@@ -1323,10 +1323,10 @@ module MilkTea
1323
1323
  IR::FloatLiteral.new(value: expression.value, type:)
1324
1324
  when AST::SizeofExpr
1325
1325
  target_type = resolve_type_ref_with_fallback(expression.type, env:)
1326
- target_type ? IR::SizeofExpr.new(target_type:, type:) : raise(LoweringError, "size_of argument is not a concrete type")
1326
+ target_type ? IR::SizeofExpr.new(target_type:, type:) : raise(LoweringError.new("size_of argument is not a concrete type", line: expression.line, column: expression.column, path: @ctx.current_analysis_path))
1327
1327
  when AST::AlignofExpr
1328
1328
  target_type = resolve_type_ref_with_fallback(expression.type, env:)
1329
- target_type ? IR::AlignofExpr.new(target_type:, type:) : raise(LoweringError, "align_of argument is not a concrete type")
1329
+ target_type ? IR::AlignofExpr.new(target_type:, type:) : raise(LoweringError.new("align_of argument is not a concrete type", line: expression.line, column: expression.column, path: @ctx.current_analysis_path))
1330
1330
  when AST::OffsetofExpr
1331
1331
  target_type = resolve_type_ref(expression.type)
1332
1332
  if !@bypass_sema_type_cache && (precomputed = @ctx.const_values[@ctx.ast.node_ids[expression.object_id]])
@@ -1348,6 +1348,8 @@ module MilkTea
1348
1348
  binding = lookup_value(expression.name, env)
1349
1349
  if binding
1350
1350
  lower_bound_identifier(binding, expected_type:)
1351
+ elsif (value_param = value_param_literal(expression.name, type))
1352
+ value_param
1351
1353
  elsif @ctx.functions.key?(expression.name)
1352
1354
  function_binding = @ctx.functions.fetch(expression.name)
1353
1355
  raise LoweringError.new("generic function #{expression.name} cannot be used as a value", line: 0, column: 0, path: @ctx.current_analysis_path) if function_binding.type_params.any?
@@ -1699,13 +1701,24 @@ module MilkTea
1699
1701
  return unless expression
1700
1702
 
1701
1703
  ct_value = compile_time_const_value(expression, env:)
1702
- if ct_value.is_a?(Types::Struct) || ct_value.is_a?(Types::Primitive) ||
1703
- ct_value.is_a?(Types::Union) || ct_value.is_a?(Types::Nullable) ||
1704
- ct_value.is_a?(Types::StructInstance)
1704
+ if sized_layout_ct_value?(ct_value)
1705
1705
  ct_value
1706
1706
  end
1707
1707
  end
1708
1708
 
1709
+ def sized_layout_ct_value?(type)
1710
+ case type
1711
+ when Types::Primitive, Types::Struct, Types::StructInstance, Types::Union, Types::Enum, Types::Flags, Types::Variant, Types::Span, Types::StringView, Types::Task, Types::Event, Types::Subscription
1712
+ true
1713
+ when Types::Nullable
1714
+ true
1715
+ when Types::GenericInstance
1716
+ pointer_type?(type) || array_type?(type) || str_buffer_type?(type)
1717
+ else
1718
+ false
1719
+ end
1720
+ end
1721
+
1709
1722
  def build_expression_from_qualified_name(qualified_name)
1710
1723
  parts = qualified_name.parts
1711
1724
  return unless parts.length >= 1
@@ -117,7 +117,9 @@ module MilkTea
117
117
  env = empty_env
118
118
  parameter_setup = []
119
119
  previous_type_substitutions = @ctx.current_type_substitutions
120
+ previous_value_type_params = @ctx.current_value_type_params
120
121
  @ctx.current_type_substitutions = binding.type_substitutions
122
+ @ctx.current_value_type_params = resolve_value_type_params(decl.type_params)
121
123
 
122
124
  return lower_async_function_decl(binding, receiver_type:) if binding.async
123
125
 
@@ -176,6 +178,15 @@ module MilkTea
176
178
  )
177
179
  ensure
178
180
  @ctx.current_type_substitutions = previous_type_substitutions
181
+ @ctx.current_value_type_params = previous_value_type_params
182
+ end
183
+
184
+ def resolve_value_type_params(type_params)
185
+ type_params.each_with_object({}) do |type_param, map|
186
+ next unless type_param.is_a?(AST::ValueTypeParam)
187
+
188
+ map[type_param.name] = resolve_type_ref(type_param.type, type_params: current_type_params)
189
+ end
179
190
  end
180
191
 
181
192
  def lower_async_function_decl(binding, receiver_type: nil)
@@ -9,6 +9,7 @@ module MilkTea
9
9
  attr_accessor :methods, :attributes, :attribute_applications, :implemented_interfaces
10
10
  attr_accessor :struct_types, :union_types, :opaque_types
11
11
  attr_accessor :current_type_substitutions
12
+ attr_accessor :current_value_type_params
12
13
  attr_accessor :resolved_expr_types
13
14
  attr_accessor :resolved_call_kinds
14
15
  attr_accessor :const_values
@@ -27,6 +28,7 @@ module MilkTea
27
28
  @attribute_applications = {}
28
29
  @implemented_interfaces = {}
29
30
  @current_type_substitutions = nil
31
+ @current_value_type_params = nil
30
32
  @resolved_expr_types = {}
31
33
  @resolved_call_kinds = {}
32
34
  @const_values = {}
@@ -699,7 +699,7 @@ module MilkTea
699
699
  end
700
700
 
701
701
  def infer_expression_type(expression, env:, expected_type: nil)
702
- if !@bypass_sema_type_cache && expected_type.nil? && (id = @ctx.ast.node_ids[expression.object_id]) && (resolved = @ctx.resolved_expr_types[id])
702
+ if !@bypass_sema_type_cache && expected_type.nil? && !expression.is_a?(AST::Identifier) && (id = @ctx.ast.node_ids[expression.object_id]) && (resolved = @ctx.resolved_expr_types[id])
703
703
  return resolved
704
704
  end
705
705
 
@@ -740,6 +740,9 @@ module MilkTea
740
740
  when AST::Identifier
741
741
  binding = lookup_value(expression.name, env)
742
742
  return binding[:type] if binding
743
+ if (value_param_type = value_param_declared_type(expression.name))
744
+ return value_param_type
745
+ end
743
746
  return function_type_for_name(expression.name) if @ctx.functions.key?(expression.name)
744
747
 
745
748
  raise LoweringError.new("unknown identifier #{expression.name}", line: expression.line, column: expression.column)
@@ -2437,6 +2440,25 @@ module MilkTea
2437
2440
  @ctx.current_type_substitutions || {}
2438
2441
  end
2439
2442
 
2443
+ def value_param_substitution(name)
2444
+ substitution = current_type_params[name]
2445
+ substitution.is_a?(Types::LiteralTypeArg) ? substitution : nil
2446
+ end
2447
+
2448
+ def value_param_declared_type(name)
2449
+ return nil unless value_param_substitution(name)
2450
+
2451
+ @ctx.current_value_type_params&.[](name)
2452
+ end
2453
+
2454
+ def value_param_literal(name, expected_type = nil)
2455
+ substitution = value_param_substitution(name)
2456
+ return nil unless substitution && substitution.value.is_a?(Integer)
2457
+
2458
+ type = @ctx.current_value_type_params&.[](name) || expected_type || @ctx.types.fetch("int")
2459
+ IR::IntegerLiteral.new(value: substitution.value, type:)
2460
+ end
2461
+
2440
2462
  def resolve_type_ref(type_ref, type_params: current_type_params)
2441
2463
  if type_ref.is_a?(AST::FunctionType)
2442
2464
  params = type_ref.params.map do |param|
@@ -321,7 +321,25 @@ module MilkTea
321
321
  return literal
322
322
  end
323
323
 
324
- lower_expression(rewrite_static_storage_initializer(expression), env:, expected_type: expected_type)
324
+ rewritten = rewrite_static_storage_initializer(expression)
325
+ if (imported_analysis = static_storage_imported_analysis(expression))
326
+ with_analysis_context(imported_analysis) do
327
+ lower_expression(rewritten, env:, expected_type: expected_type)
328
+ end
329
+ else
330
+ lower_expression(rewritten, env:, expected_type: expected_type)
331
+ end
332
+ end
333
+
334
+ def static_storage_imported_analysis(expression)
335
+ return nil unless expression.is_a?(AST::MemberAccess)
336
+ return nil unless expression.receiver.is_a?(AST::Identifier)
337
+ return nil unless @ctx.imports.key?(expression.receiver.name)
338
+
339
+ imported_module = @ctx.imports.fetch(expression.receiver.name)
340
+ return nil unless imported_module.values[expression.member]&.kind == :const
341
+
342
+ analysis_for_module(imported_module.name)
325
343
  end
326
344
 
327
345
  def lower_compile_time_literal(value, type)
@@ -337,6 +355,14 @@ module MilkTea
337
355
  if type == @ctx.types.fetch("str") || type == @ctx.types.fetch("cstr")
338
356
  return IR::StringLiteral.new(value:, type:, cstring: type == @ctx.types.fetch("cstr"))
339
357
  end
358
+ when Array
359
+ return nil unless array_type?(type)
360
+
361
+ element_type = type.arguments.first
362
+ elements = value.map { |element| lower_compile_time_literal(element, element_type) }
363
+ return nil if elements.any?(&:nil?)
364
+
365
+ IR::ArrayLiteral.new(type:, elements:)
340
366
  when Hash
341
367
  return nil unless type.is_a?(Types::Struct)
342
368
  fields = value.map do |name, field_value|
@@ -31,6 +31,7 @@ module MilkTea
31
31
  receiver_type = infer_lvalue_receiver(
32
32
  expression.receiver,
33
33
  scopes:,
34
+ allow_ref_identifier: true,
34
35
  allow_pointer_identifier: true,
35
36
  require_mutable_pointer: true,
36
37
  allow_span_param_identifier: true,
@@ -333,6 +334,10 @@ module MilkTea
333
334
  return binding.type
334
335
  end
335
336
 
337
+ if (value_param_type = current_value_type_params[expression.name])
338
+ return value_param_type
339
+ end
340
+
336
341
  if @ctx.top_level_functions.key?(expression.name)
337
342
  raise_sema_error("generic function #{expression.name} must be called") if @ctx.top_level_functions.fetch(expression.name).type_params.any?
338
343
 
@@ -615,6 +615,7 @@ module MilkTea
615
615
 
616
616
  previous_type_substitutions = @current_type_substitutions
617
617
  previous_specialization_owner = @current_specialization_owner
618
+ previous_value_type_params = @current_value_type_params
618
619
  started_check = false
619
620
  return if binding.external
620
621
  return if @checked_function_bindings[binding.object_id]
@@ -624,6 +625,7 @@ module MilkTea
624
625
  started_check = true
625
626
  @current_type_substitutions = binding.type_substitutions
626
627
  @current_specialization_owner = binding.specialization_owner
628
+ @current_value_type_params = resolve_value_type_params(binding.ast.type_params)
627
629
  with_error_node(binding.ast) do
628
630
  with_scope(binding.body_params) do |scopes|
629
631
  start_local_completion_frame(binding, scopes)
@@ -678,8 +680,21 @@ module MilkTea
678
680
  @nullability_flow_result = nil
679
681
  @current_type_substitutions = previous_type_substitutions
680
682
  @current_specialization_owner = previous_specialization_owner
683
+ @current_value_type_params = previous_value_type_params
681
684
  @checking_function_bindings.delete(binding.object_id)
682
685
  end
686
+
687
+ def resolve_value_type_params(type_params)
688
+ type_params.each_with_object({}) do |type_param, map|
689
+ next unless type_param.is_a?(AST::ValueTypeParam)
690
+
691
+ map[type_param.name] = resolve_type_ref(
692
+ type_param.type,
693
+ type_params: current_type_params,
694
+ type_param_constraints: current_type_param_constraints,
695
+ )
696
+ end
697
+ end
683
698
  end
684
699
  end
685
700
  end
@@ -7,6 +7,10 @@ module MilkTea
7
7
  @current_type_substitutions || {}
8
8
  end
9
9
 
10
+ def current_value_type_params
11
+ @current_value_type_params || {}
12
+ end
13
+
10
14
  def current_type_param_constraints
11
15
  @current_type_param_constraints || {}
12
16
  end
@@ -463,9 +467,13 @@ module MilkTea
463
467
  resolve_imported_module_const_value(type_ref.name.parts.first, type_ref.name.parts.last)
464
468
  end
465
469
 
466
- return unless value.is_a?(Integer) || value.is_a?(Float)
470
+ return if value.nil?
471
+ return Types::LiteralTypeArg.new(value) if value.is_a?(Integer) || value.is_a?(Float)
472
+ return value if value.is_a?(Types::Base)
467
473
 
468
- Types::LiteralTypeArg.new(value)
474
+ nil
475
+ rescue SemanticError
476
+ nil
469
477
  end
470
478
 
471
479
  def resolve_current_module_const_value(name)
@@ -657,12 +665,8 @@ module MilkTea
657
665
  return false unless expression
658
666
 
659
667
  ct_value = evaluate_compile_time_const_value(expression, scopes:)
660
- if ct_value.is_a?(Types::Struct) || ct_value.is_a?(Types::Primitive) ||
661
- ct_value.is_a?(Types::Union) || ct_value.is_a?(Types::Nullable) ||
662
- ct_value.is_a?(Types::StructInstance)
663
- if sized_layout_type?(ct_value)
664
- return true
665
- end
668
+ if sized_layout_type?(ct_value)
669
+ return true
666
670
  end
667
671
 
668
672
  false
@@ -184,6 +184,23 @@ module MilkTea
184
184
  !binding.external && binding.type_params.empty?
185
185
  end
186
186
 
187
+ def predeclare_top_level_consts
188
+ @ctx.ast.declarations.each do |decl|
189
+ next unless decl.is_a?(AST::ConstDecl)
190
+
191
+ @ctx.const_declarations[decl.name] ||= decl
192
+ next if @ctx.top_level_values.key?(decl.name)
193
+
194
+ @ctx.top_level_values[decl.name] = value_binding(
195
+ name: decl.name,
196
+ type: @error_type,
197
+ mutable: false,
198
+ kind: :const,
199
+ )
200
+ @predeclared_const_names << decl.name
201
+ end
202
+ end
203
+
187
204
  def finalize_top_level_const_values
188
205
  @ctx.const_declarations.each_key { |name| evaluate_top_level_const_value(name) }
189
206
  end
@@ -247,7 +264,7 @@ module MilkTea
247
264
  kind: binding.kind,
248
265
  const_value: value,
249
266
  )
250
- @evaluated_const_values[name] = true
267
+ @evaluated_const_values[name] = true unless value.nil?
251
268
  end
252
269
 
253
270
  def evaluate_compile_time_block(statements, scopes: nil)
@@ -261,6 +278,10 @@ module MilkTea
261
278
  end
262
279
 
263
280
  def evaluate_compile_time_const_value(expression, scopes: nil)
281
+ if (type_value = evaluate_type_constructor_index_access(expression, scopes:))
282
+ return type_value
283
+ end
284
+
264
285
  CompileTime.evaluate(
265
286
  expression,
266
287
  resolve_identifier: lambda do |identifier_expression|
@@ -324,6 +345,26 @@ module MilkTea
324
345
  raise_sema_error(e.message)
325
346
  end
326
347
 
348
+ def evaluate_type_constructor_index_access(expression, scopes:)
349
+ return nil unless expression.is_a?(AST::IndexAccess)
350
+ return nil unless expression.receiver.is_a?(AST::Identifier)
351
+ return nil unless expression.index.is_a?(AST::Identifier)
352
+ return nil unless %w[ptr const_ptr array span own ref].include?(expression.receiver.name)
353
+
354
+ type_ref = AST::TypeRef.new(
355
+ name: AST::QualifiedName.new(parts: [expression.index.name]),
356
+ arguments: [],
357
+ nullable: false,
358
+ )
359
+ specialization = AST::Specialization.new(
360
+ callee: expression.receiver,
361
+ arguments: [AST::TypeArgument.new(value: type_ref)],
362
+ )
363
+ evaluate_type_returning_call(specialization, scopes:)
364
+ rescue SemanticError
365
+ nil
366
+ end
367
+
327
368
  def evaluate_compile_time_call(expression, scopes: nil)
328
369
  case expression.callee
329
370
  when AST::MemberAccess
@@ -431,9 +472,31 @@ module MilkTea
431
472
  end
432
473
  return fields
433
474
  end
475
+ if resolved_type && array_type?(resolved_type)
476
+ values = []
477
+ expression.arguments.each do |argument|
478
+ val = CompileTime.evaluate(argument.value, resolve_identifier: lambda { |id|
479
+ if scopes
480
+ binding = lookup_value(id.name, scopes)
481
+ return binding.const_value unless binding&.const_value.nil?
482
+ end
483
+ resolve_current_module_const_value(id.name)
484
+ }, resolve_member_access: lambda { |ma|
485
+ if (receiver_type = resolve_type_expression(ma.receiver))
486
+ next resolve_enum_member_const_value(receiver_type, ma.member)
487
+ end
488
+ nil
489
+ }, resolve_call: lambda { |inner_call|
490
+ evaluate_compile_time_call(inner_call, scopes:)
491
+ })
492
+ return nil unless val
493
+ values << val
494
+ end
495
+ return values
496
+ end
434
497
  func = @ctx.top_level_functions[callee_name]
435
498
  if func&.ast&.respond_to?(:const) && func.ast.const
436
- evaluate_const_function_body(func, expression.arguments, scopes:)
499
+ evaluate_const_function_body(func, expression.arguments, scopes:, type_args: expression.callee.arguments)
437
500
  else
438
501
  evaluate_type_returning_call(expression, scopes:)
439
502
  end
@@ -453,7 +516,7 @@ module MilkTea
453
516
  CompileTime::Reflection.core_evaluate_type_returning(
454
517
  callee_name, type_args,
455
518
  evaluate_value: ->(v) { evaluate_compile_time_const_value(v, scopes:) },
456
- resolve_type_ref: ->(tr) { resolve_type_ref(tr) },
519
+ resolve_type_ref: ->(tr) { resolve_named_literal_type_argument(tr) || resolve_type_ref(tr) },
457
520
  pointer_to: ->(t) { pointer_to(t) },
458
521
  const_pointer_to: ->(t) { const_pointer_to(t) },
459
522
  top_level_functions: ->(name) { @ctx.top_level_functions[name] },
@@ -484,7 +547,11 @@ module MilkTea
484
547
  when AST::IntegerLiteral
485
548
  initial_vars[param.name] = arg_value.value
486
549
  when AST::TypeRef
487
- initial_vars[param.name] = resolve_type_ref(arg_value)
550
+ if (literal = resolve_named_literal_type_argument(arg_value))
551
+ initial_vars[param.name] = literal.value
552
+ else
553
+ initial_vars[param.name] = resolve_type_ref(arg_value)
554
+ end
488
555
  else
489
556
  return nil
490
557
  end
@@ -498,10 +565,11 @@ module MilkTea
498
565
  raise_sema_error(e.message)
499
566
  end
500
567
 
501
- def evaluate_const_function_body(func, arguments, scopes:)
568
+ def evaluate_const_function_body(func, arguments, scopes:, type_args: nil)
502
569
  return nil unless func.ast.params.length == arguments.length
503
570
 
504
571
  initial_vars = {}
572
+ bind_const_function_value_type_params(func, type_args, initial_vars)
505
573
  func.ast.params.each_with_index do |param, idx|
506
574
  arg_expr = arguments[idx].value
507
575
  arg_value = if scopes
@@ -528,6 +596,25 @@ module MilkTea
528
596
  raise_sema_error(e.message)
529
597
  end
530
598
 
599
+ def bind_const_function_value_type_params(func, type_args, initial_vars)
600
+ value_params = func.ast.type_params.select { |p| p.is_a?(AST::ValueTypeParam) }
601
+ return if value_params.empty? || type_args.nil?
602
+
603
+ value_params.zip(type_args).each do |param, arg|
604
+ arg_value = arg.value
605
+ case arg_value
606
+ when AST::IntegerLiteral
607
+ initial_vars[param.name] = arg_value.value
608
+ when AST::TypeRef
609
+ if (literal = resolve_named_literal_type_argument(arg_value))
610
+ initial_vars[param.name] = literal.value
611
+ else
612
+ initial_vars[param.name] = resolve_type_ref(arg_value)
613
+ end
614
+ end
615
+ end
616
+ end
617
+
531
618
  def evaluate_has_attribute_call(arguments, scopes:)
532
619
  target = evaluate_reflection_target_argument(arguments.first.value, scopes:)
533
620
  binding = resolve_attribute_name_argument(arguments[1].value)
@@ -726,6 +726,8 @@ module MilkTea
726
726
 
727
727
  def ensure_available_value_name!(name, kind_label: "value", line: nil, column: nil, length: nil)
728
728
  ensure_non_reserved_value_type_name!(name, kind_label:, line:, column:, length:)
729
+ return if @predeclared_const_names.delete?(name)
730
+
729
731
  raise_sema_error("duplicate value #{name}") if @ctx.top_level_values.key?(name) || @ctx.top_level_functions.key?(name)
730
732
  end
731
733
 
@@ -762,6 +764,7 @@ module MilkTea
762
764
  type: type,
763
765
  mutable: false,
764
766
  kind: :const,
767
+ const_value: @ctx.top_level_values[decl.name]&.const_value,
765
768
  )
766
769
  rescue SemanticError => e
767
770
  collect_structural_error(e)
@@ -770,6 +773,7 @@ module MilkTea
770
773
  type: @error_type,
771
774
  mutable: false,
772
775
  kind: :const,
776
+ const_value: @ctx.top_level_values[decl.name]&.const_value,
773
777
  ) unless @ctx.top_level_values.key?(decl.name)
774
778
  end
775
779
  when AST::VarDecl
@@ -175,6 +175,7 @@ module MilkTea
175
175
  @mutable_lvalue_argument_identifier_ids = {}
176
176
  @editable_receiver_expression_ids = {}
177
177
  @preassigned_local_binding_ids = {}
178
+ @predeclared_const_names = Set.new
178
179
  @nullability_flow_result = nil
179
180
  @unsafe_statement_lines = []
180
181
  @callable_value_identifier_sites = {}
@@ -196,6 +197,7 @@ module MilkTea
196
197
  run_phase(:resolve_generic_type_param_constraints, requires: [:declare_named_types])
197
198
  run_phase(:resolve_type_aliases, requires: [:declare_named_types])
198
199
  run_phase(:declare_attributes)
200
+ run_phase(:predeclare_top_level_consts)
199
201
  run_phase(:resolve_aggregate_fields, requires: [:resolve_type_aliases, :declare_named_types])
200
202
  run_phase(:resolve_enum_members, requires: [:declare_named_types])
201
203
  run_phase(:resolve_variant_arms, requires: [:declare_named_types])
@@ -260,12 +262,16 @@ module MilkTea
260
262
  when AST::WhenStmt
261
263
  body = when_chosen_body(stmt) || []
262
264
  body.each { |nested| collect_emit_from_statements([nested]) }
263
- when AST::ForStmt, AST::WhileStmt, AST::IfStmt, AST::MatchStmt
265
+ when AST::ForStmt, AST::WhileStmt
264
266
  next unless stmt.inline
265
267
  stmt.body&.each { |s| collect_emit_from_statements([s]) }
266
- if stmt.is_a?(AST::IfStmt)
267
- stmt.else_body&.each { |s| collect_emit_from_statements([s]) }
268
- end
268
+ when AST::IfStmt
269
+ next unless stmt.inline
270
+ stmt.branches.each { |branch| collect_emit_from_statements(branch.body) }
271
+ stmt.else_body&.each { |s| collect_emit_from_statements([s]) }
272
+ when AST::MatchStmt
273
+ next unless stmt.inline
274
+ stmt.arms.each { |arm| collect_emit_from_statements(arm.body) }
269
275
  end
270
276
  end
271
277
  end
@@ -302,6 +308,7 @@ module MilkTea
302
308
  run_collecting_phase(:resolve_generic_type_param_constraints, requires: [:declare_named_types])
303
309
  run_collecting_phase(:resolve_type_aliases, requires: [:declare_named_types])
304
310
  run_collecting_phase(:declare_attributes)
311
+ run_collecting_phase(:predeclare_top_level_consts)
305
312
  run_collecting_phase(:resolve_aggregate_fields, requires: [:resolve_type_aliases, :declare_named_types])
306
313
  run_collecting_phase(:resolve_enum_members, requires: [:declare_named_types])
307
314
  run_collecting_phase(:resolve_variant_arms, requires: [:declare_named_types])
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mt-lang
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.32
4
+ version: 0.3.34
5
5
  platform: ruby
6
6
  authors:
7
7
  - Long (Teefan) Tran
@@ -624,7 +624,7 @@ metadata:
624
624
  homepage_uri: https://teefan.github.io/mt-lang/
625
625
  source_code_uri: https://github.com/teefan/mt-lang
626
626
  post_install_message: |
627
- Milk Tea 0.3.32 installed!
627
+ Milk Tea 0.3.34 installed!
628
628
 
629
629
  System requirements:
630
630
  - A C compiler (gcc or clang) must be available on PATH