mt-lang 0.3.39 → 0.3.41

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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/lib/milk_tea/base.rb +1 -1
  3. data/lib/milk_tea/core/ast.rb +2 -2
  4. data/lib/milk_tea/core/bindings/attribute_binding.rb +1 -6
  5. data/lib/milk_tea/core/bindings/module_binding.rb +1 -1
  6. data/lib/milk_tea/core/intrinsics.rb +23 -1
  7. data/lib/milk_tea/core/lowering/functions.rb +3 -0
  8. data/lib/milk_tea/core/lowering/resolve.rb +4 -65
  9. data/lib/milk_tea/core/lowering/utils.rb +0 -17
  10. data/lib/milk_tea/core/lowering.rb +1 -2
  11. data/lib/milk_tea/core/module_binder.rb +4 -15
  12. data/lib/milk_tea/core/module_loader.rb +41 -8
  13. data/lib/milk_tea/core/parser/declarations.rb +24 -17
  14. data/lib/milk_tea/core/semantic_analyzer/analysis_context.rb +2 -111
  15. data/lib/milk_tea/core/semantic_analyzer/expressions.rb +1 -2
  16. data/lib/milk_tea/core/semantic_analyzer/function_binding.rb +26 -17
  17. data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +26 -42
  18. data/lib/milk_tea/core/semantic_analyzer/type_compatibility.rb +0 -59
  19. data/lib/milk_tea/core/semantic_analyzer/type_declaration.rb +0 -2
  20. data/lib/milk_tea/core/types/predicates.rb +57 -0
  21. data/lib/milk_tea/core/types/registry.rb +14 -2
  22. data/lib/milk_tea/core/types.rb +0 -4
  23. data/lib/milk_tea/lsp/server/code_actions.rb +13 -7
  24. data/lib/milk_tea/lsp/server/diagnostics_scheduling.rb +56 -12
  25. data/lib/milk_tea/lsp/server/text_documents.rb +18 -2
  26. data/lib/milk_tea/lsp/workspace/caches.rb +28 -1
  27. data/lib/milk_tea/lsp/workspace/dependency_graph.rb +31 -0
  28. data/lib/milk_tea/lsp/workspace/store.rb +7 -1
  29. data/lib/milk_tea/lsp/workspace.rb +6 -0
  30. data/lib/milk_tea/tooling/formatter.rb +2 -3
  31. data/lib/milk_tea/tooling/linter/fix_engine.rb +46 -0
  32. data/lib/milk_tea/tooling/linter/rules.rb +32 -0
  33. data/lib/milk_tea/tooling/linter.rb +4 -0
  34. data/lib/milk_tea/tooling.rb +0 -1
  35. metadata +2 -3
  36. data/lib/milk_tea/tooling/cst_formatter.rb +0 -13
@@ -129,53 +129,23 @@ module MilkTea
129
129
  def validate_async_statement!(statement)
130
130
  case statement
131
131
  when AST::ErrorBlockStmt
132
- if statement.header_expression
133
- context = case statement.header_type
134
- when :if then "if conditions"
135
- when :while then "while conditions"
136
- end
137
- validate_async_expression_support!(statement.header_expression, context:) if context
138
- end
139
- if statement.header_type == :for
140
- Array(statement.header_iterables).each do |iterable|
141
- validate_async_expression_support!(iterable, context: "for iterables")
142
- end
143
- end
144
132
  statement.body.each { |s| validate_async_statement!(s) }
145
133
  when AST::ErrorStmt
146
134
  nil
147
135
  when AST::LocalDecl
148
- validate_async_expression_support!(statement.value, context: "local initializer") if statement.value
149
136
  statement.else_body&.each { |s| validate_async_statement!(s) }
150
- when AST::Assignment
151
- validate_async_expression_support!(statement.target, context: "assignment target")
152
- validate_async_expression_support!(statement.value, context: "assignment")
153
- when AST::ExpressionStmt
154
- validate_async_expression_support!(statement.expression, context: "expression statement")
155
- when AST::ReturnStmt
156
- return unless statement.value
157
-
158
- validate_async_expression_support!(statement.value, context: "return statement")
137
+ when AST::Assignment, AST::ExpressionStmt, AST::ReturnStmt
138
+ nil
159
139
  when AST::IfStmt
160
140
  statement.branches.each do |branch|
161
- validate_async_expression_support!(branch.condition, context: "if conditions")
162
-
163
141
  branch.body.each { |s| validate_async_statement!(s) }
164
142
  end
165
143
  statement.else_body&.each { |s| validate_async_statement!(s) }
166
144
  when AST::WhileStmt
167
- validate_async_expression_support!(statement.condition, context: "while conditions")
168
-
169
145
  statement.body.each { |s| validate_async_statement!(s) }
170
146
  when AST::ForStmt
171
- statement.iterables.each do |iterable|
172
- validate_async_expression_support!(iterable, context: "for iterables")
173
- end
174
-
175
147
  statement.body.each { |s| validate_async_statement!(s) }
176
148
  when AST::MatchStmt
177
- validate_async_expression_support!(statement.expression, context: "match discriminants")
178
-
179
149
  statement.arms.each { |arm| arm.body.each { |s| validate_async_statement!(s) } }
180
150
  when AST::UnsafeStmt
181
151
  statement.body.each { |s| validate_async_statement!(s) }
@@ -191,85 +161,6 @@ module MilkTea
191
161
  end
192
162
  end
193
163
 
194
- def validate_async_expression_support!(expression, context:)
195
- unsupported_context = unsupported_await_position(expression)
196
- return unless unsupported_context
197
-
198
- raise_sema_error("await in async functions is not supported inside #{unsupported_context} yet")
199
- end
200
-
201
- def unsupported_await_position(expression)
202
- nil
203
- end
204
-
205
- def statement_contains_await?(statement)
206
- case statement
207
- when AST::ErrorBlockStmt
208
- (statement.header_expression && expression_contains_await?(statement.header_expression)) ||
209
- Array(statement.header_iterables).any? { |iterable| expression_contains_await?(iterable) } ||
210
- statements_contain_await?(statement.body)
211
- when AST::LocalDecl
212
- (statement.value && expression_contains_await?(statement.value)) ||
213
- (statement.else_body && statements_contain_await?(statement.else_body))
214
- when AST::Assignment
215
- expression_contains_await?(statement.target) || expression_contains_await?(statement.value)
216
- when AST::IfStmt
217
- statement.branches.any? { |branch| expression_contains_await?(branch.condition) || statements_contain_await?(branch.body) } ||
218
- (statement.else_body && statements_contain_await?(statement.else_body))
219
- when AST::MatchStmt
220
- expression_contains_await?(statement.expression) || statement.arms.any? { |arm| expression_contains_await?(arm.pattern) || statements_contain_await?(arm.body) }
221
- when AST::UnsafeStmt
222
- statements_contain_await?(statement.body)
223
- when AST::StaticAssert
224
- expression_contains_await?(statement.condition) || expression_contains_await?(statement.message)
225
- when AST::ForStmt
226
- statement.iterables.any? { |iterable| expression_contains_await?(iterable) } || statements_contain_await?(statement.body)
227
- when AST::WhileStmt
228
- expression_contains_await?(statement.condition) || statements_contain_await?(statement.body)
229
- when AST::ReturnStmt
230
- statement.value && expression_contains_await?(statement.value)
231
- when AST::DeferStmt
232
- statements_contain_await?(statement.body)
233
- when AST::ExpressionStmt
234
- expression_contains_await?(statement.expression)
235
- else
236
- false
237
- end
238
- end
239
-
240
- def statements_contain_await?(statements)
241
- statements.any? { |statement| statement_contains_await?(statement) }
242
- end
243
-
244
- def expression_contains_await?(expression)
245
- case expression
246
- when AST::AwaitExpr
247
- true
248
- when AST::Call, AST::Specialization
249
- expression_contains_await?(expression.callee) || expression.arguments.any? { |argument| expression_contains_await?(argument.value) }
250
- when AST::UnaryOp
251
- expression_contains_await?(expression.operand)
252
- when AST::BinaryOp
253
- expression_contains_await?(expression.left) || expression_contains_await?(expression.right)
254
- when AST::IfExpr
255
- expression_contains_await?(expression.condition) || expression_contains_await?(expression.then_expression) || expression_contains_await?(expression.else_expression)
256
- when AST::MatchExpr
257
- expression_contains_await?(expression.expression) || expression.arms.any? { |arm| expression_contains_await?(arm.pattern) || expression_contains_await?(arm.value) }
258
- when AST::UnsafeExpr
259
- expression_contains_await?(expression.expression)
260
- when AST::PrefixCast
261
- expression_contains_await?(expression.expression)
262
- when AST::MemberAccess
263
- expression_contains_await?(expression.receiver)
264
- when AST::IndexAccess
265
- expression_contains_await?(expression.receiver) || expression_contains_await?(expression.index)
266
- when AST::FormatString
267
- expression.parts.any? { |part| part.is_a?(AST::FormatExprPart) && expression_contains_await?(part.expression) }
268
- else
269
- false
270
- end
271
- end
272
-
273
164
  def suggest_name(wrong, candidates, max_distance: 2)
274
165
  return nil if wrong.nil? || wrong.to_s.empty? || candidates.nil? || candidates.empty?
275
166
 
@@ -1309,7 +1309,7 @@ module MilkTea
1309
1309
  return [:has_attribute, nil, nil] if callee.name == "has_attribute"
1310
1310
  return [:get, nil, nil] if callee.name == "get"
1311
1311
 
1312
- type = @ctx.types[callee.name]
1312
+ type = lookup_named_type(callee.name)
1313
1313
  return [:struct, type, nil] if type.is_a?(Types::Struct) || type.is_a?(Types::StringView) || task_type?(type) || type.is_a?(Types::Vector) || type.is_a?(Types::Matrix) || type.is_a?(Types::Quaternion)
1314
1314
  if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
1315
1315
  raise_sema_error("generic type #{callee.name} requires type arguments")
@@ -1396,7 +1396,6 @@ module MilkTea
1396
1396
  return [:array_as_span, field_receiver_type, callee.receiver]
1397
1397
  end
1398
1398
 
1399
- return [:callable_value, field_receiver_type.field(callee.member), nil] if aggregate_type?(field_receiver_type) && callable_type?(field_receiver_type.field(callee.member))
1400
1399
  return [:callable_value, field_receiver_type.field(callee.member), nil] if aggregate_type?(field_receiver_type) && callable_type?(field_receiver_type.field(callee.member))
1401
1400
 
1402
1401
  if (imported_module = imported_module_with_private_method(method_receiver_type, callee.member))
@@ -22,25 +22,31 @@ module MilkTea
22
22
  when AST::ExtendingBlock
23
23
  dispatch_receiver_type, receiver_type, receiver_type_param_names, receiver_type_param_constraints = resolve_methods_receiver_target(decl.type_name)
24
24
 
25
- decl.methods.each do |method|
26
- begin
27
- binding = with_error_node(method) do
28
- declare_function_binding(
29
- method,
30
- receiver_type:,
31
- declared_receiver_type: receiver_type,
32
- receiver_type_param_names:,
33
- receiver_type_param_constraints:,
34
- )
35
- end
36
- instance_method = receiver_type && method.kind != :static
37
- method_key = instance_method ? binding.name : "static:#{binding.name}"
38
- raise_sema_error("duplicate method #{decl.type_name}.#{binding.name}") if @ctx.methods[dispatch_receiver_type].key?(method_key)
25
+ previous_nested_types = @current_nested_types
26
+ @current_nested_types = method_receiver_nested_scope(receiver_type)
27
+ begin
28
+ decl.methods.each do |method|
29
+ begin
30
+ binding = with_error_node(method) do
31
+ declare_function_binding(
32
+ method,
33
+ receiver_type:,
34
+ declared_receiver_type: receiver_type,
35
+ receiver_type_param_names:,
36
+ receiver_type_param_constraints:,
37
+ )
38
+ end
39
+ instance_method = receiver_type && method.kind != :static
40
+ method_key = instance_method ? binding.name : "static:#{binding.name}"
41
+ raise_sema_error("duplicate method #{decl.type_name}.#{binding.name}") if @ctx.methods[dispatch_receiver_type].key?(method_key)
39
42
 
40
- @ctx.methods[dispatch_receiver_type][method_key] = binding
41
- rescue SemanticError => e
42
- collect_structural_error(e)
43
+ @ctx.methods[dispatch_receiver_type][method_key] = binding
44
+ rescue SemanticError => e
45
+ collect_structural_error(e)
46
+ end
43
47
  end
48
+ ensure
49
+ @current_nested_types = previous_nested_types
44
50
  end
45
51
  end
46
52
  end
@@ -604,6 +610,7 @@ module MilkTea
604
610
  previous_type_substitutions = @current_type_substitutions
605
611
  previous_specialization_owner = @current_specialization_owner
606
612
  previous_value_type_params = @current_value_type_params
613
+ previous_nested_types = @current_nested_types
607
614
  started_check = false
608
615
  return if binding.external
609
616
  return if @checked_function_bindings[binding.object_id]
@@ -614,6 +621,7 @@ module MilkTea
614
621
  @current_type_substitutions = binding.type_substitutions
615
622
  @current_specialization_owner = binding.specialization_owner
616
623
  @current_value_type_params = resolve_value_type_params(binding.ast.type_params)
624
+ @current_nested_types = method_receiver_nested_scope(binding.declared_receiver_type)
617
625
  with_error_node(binding.ast) do
618
626
  with_scope(binding.body_params) do |scopes|
619
627
  start_local_completion_frame(binding, scopes)
@@ -669,6 +677,7 @@ module MilkTea
669
677
  @current_type_substitutions = previous_type_substitutions
670
678
  @current_specialization_owner = previous_specialization_owner
671
679
  @current_value_type_params = previous_value_type_params
680
+ @current_nested_types = previous_nested_types
672
681
  @checking_function_bindings.delete(binding.object_id)
673
682
  end
674
683
 
@@ -236,7 +236,7 @@ module MilkTea
236
236
  end
237
237
  end
238
238
 
239
- def resolve_type_ref(type_ref, type_params: current_type_params, type_param_constraints: current_type_param_constraints, nested_types: nil)
239
+ def resolve_type_ref(type_ref, type_params: current_type_params, type_param_constraints: current_type_param_constraints, nested_types: current_nested_types)
240
240
  base = resolve_non_nullable_type(type_ref, type_params:, type_param_constraints:, nested_types:)
241
241
  return base if type_ref.is_a?(AST::FunctionType) || type_ref.is_a?(AST::ProcType) || type_ref.is_a?(AST::TupleType)
242
242
 
@@ -247,11 +247,11 @@ module MilkTea
247
247
 
248
248
  def resolve_non_nullable_type(type_ref, type_params: {}, type_param_constraints: {}, nested_types: nil)
249
249
  if type_ref.is_a?(AST::FunctionType)
250
- return resolve_function_type_ref(type_ref, type_params:, type_param_constraints:)
250
+ return resolve_function_type_ref(type_ref, type_params:, type_param_constraints:, nested_types:)
251
251
  end
252
252
 
253
253
  if type_ref.is_a?(AST::ProcType)
254
- return resolve_proc_type_ref(type_ref, type_params:, type_param_constraints:)
254
+ return resolve_proc_type_ref(type_ref, type_params:, type_param_constraints:, nested_types:)
255
255
  end
256
256
 
257
257
  if type_ref.is_a?(AST::DynType)
@@ -259,13 +259,13 @@ module MilkTea
259
259
  end
260
260
 
261
261
  if type_ref.is_a?(AST::TupleType)
262
- return resolve_tuple_type_ref(type_ref, type_params:, type_param_constraints:)
262
+ return resolve_tuple_type_ref(type_ref, type_params:, type_param_constraints:, nested_types:)
263
263
  end
264
264
 
265
265
  parts = type_ref.name.parts
266
266
 
267
267
  if type_ref.arguments.any?
268
- return resolve_generic_instance_type_ref(type_ref, parts, type_params:, type_param_constraints:)
268
+ return resolve_generic_instance_type_ref(type_ref, parts, type_params:, type_param_constraints:, nested_types:)
269
269
  end
270
270
 
271
271
  if parts.length == 1 && type_ref.lifetime
@@ -279,18 +279,18 @@ module MilkTea
279
279
  resolve_multi_part_type_ref(type_ref, parts)
280
280
  end
281
281
 
282
- def resolve_function_type_ref(type_ref, type_params:, type_param_constraints:)
282
+ def resolve_function_type_ref(type_ref, type_params:, type_param_constraints:, nested_types:)
283
283
  params = type_ref.params.map do |param|
284
- Types::Registry.parameter(param.name, resolve_type_ref(param.type, type_params:, type_param_constraints:))
284
+ Types::Registry.parameter(param.name, resolve_type_ref(param.type, type_params:, type_param_constraints:, nested_types:))
285
285
  end
286
- Types::Registry.function(nil, params:, return_type: resolve_type_ref(type_ref.return_type, type_params:, type_param_constraints:))
286
+ Types::Registry.function(nil, params:, return_type: resolve_type_ref(type_ref.return_type, type_params:, type_param_constraints:, nested_types:))
287
287
  end
288
288
 
289
- def resolve_proc_type_ref(type_ref, type_params:, type_param_constraints:)
289
+ def resolve_proc_type_ref(type_ref, type_params:, type_param_constraints:, nested_types:)
290
290
  params = type_ref.params.map do |param|
291
- Types::Registry.parameter(param.name, resolve_type_ref(param.type, type_params:, type_param_constraints:))
291
+ Types::Registry.parameter(param.name, resolve_type_ref(param.type, type_params:, type_param_constraints:, nested_types:))
292
292
  end
293
- Types::Registry.proc(params:, return_type: resolve_type_ref(type_ref.return_type, type_params:, type_param_constraints:))
293
+ Types::Registry.proc(params:, return_type: resolve_type_ref(type_ref.return_type, type_params:, type_param_constraints:, nested_types:))
294
294
  end
295
295
 
296
296
  def resolve_dyn_type_ref(type_ref)
@@ -302,25 +302,25 @@ module MilkTea
302
302
  type
303
303
  end
304
304
 
305
- def resolve_tuple_type_ref(type_ref, type_params:, type_param_constraints:)
305
+ def resolve_tuple_type_ref(type_ref, type_params:, type_param_constraints:, nested_types:)
306
306
  names = []
307
307
  element_types = []
308
308
  type_ref.element_types.each do |et|
309
309
  if et.is_a?(AST::Argument)
310
310
  names << et.name
311
- element_types << resolve_type_ref(et.value, type_params:, type_param_constraints:)
311
+ element_types << resolve_type_ref(et.value, type_params:, type_param_constraints:, nested_types:)
312
312
  else
313
313
  names << nil
314
- element_types << resolve_type_ref(et, type_params:, type_param_constraints:)
314
+ element_types << resolve_type_ref(et, type_params:, type_param_constraints:, nested_types:)
315
315
  end
316
316
  end
317
317
  has_named = names.any?
318
318
  Types::Registry.tuple(element_types, field_names: has_named ? names : nil)
319
319
  end
320
320
 
321
- def resolve_generic_instance_type_ref(type_ref, parts, type_params:, type_param_constraints:)
321
+ def resolve_generic_instance_type_ref(type_ref, parts, type_params:, type_param_constraints:, nested_types:)
322
322
  name = parts.join(".")
323
- arguments = type_ref.arguments.map { |argument| resolve_type_argument(argument.value, type_params:, type_param_constraints:) }
323
+ arguments = type_ref.arguments.map { |argument| resolve_type_argument(argument.value, type_params:, type_param_constraints:, nested_types:) }
324
324
 
325
325
  if name != "ref" && arguments.any? { |argument| contains_ref_type?(argument) && !stored_ref_supported_type?(argument) }
326
326
  raise_sema_error("ref types cannot be nested inside #{name}", type_ref)
@@ -434,12 +434,12 @@ module MilkTea
434
434
  value.is_a?(Types::Base) ? value : nil
435
435
  end
436
436
 
437
- def resolve_type_argument(argument, type_params: current_type_params, type_param_constraints: current_type_param_constraints)
437
+ def resolve_type_argument(argument, type_params: current_type_params, type_param_constraints: current_type_param_constraints, nested_types: current_nested_types)
438
438
  case argument
439
439
  when AST::TypeRef
440
- resolve_type_argument_ref(argument, type_params:, type_param_constraints:)
440
+ resolve_type_argument_ref(argument, type_params:, type_param_constraints:, nested_types:)
441
441
  when AST::FunctionType, AST::ProcType, AST::TupleType
442
- resolve_type_ref(argument, type_params:, type_param_constraints:)
442
+ resolve_type_ref(argument, type_params:, type_param_constraints:, nested_types:)
443
443
  when AST::IntegerLiteral, AST::FloatLiteral
444
444
  Types::LiteralTypeArg.new(argument.value)
445
445
  else
@@ -447,20 +447,20 @@ module MilkTea
447
447
  end
448
448
  end
449
449
 
450
- def resolve_type_argument_ref(type_ref, type_params:, type_param_constraints:)
451
- return resolve_type_ref(type_ref, type_params:, type_param_constraints:) unless literal_type_argument_name_candidate?(type_ref)
450
+ def resolve_type_argument_ref(type_ref, type_params:, type_param_constraints:, nested_types:)
451
+ return resolve_type_ref(type_ref, type_params:, type_param_constraints:, nested_types:) unless literal_type_argument_name_candidate?(type_ref)
452
452
 
453
- result = try_resolve_type_ref(type_ref, type_params:, type_param_constraints:)
453
+ result = try_resolve_type_ref(type_ref, type_params:, type_param_constraints:, nested_types:)
454
454
  return result if result
455
455
 
456
456
  literal_type_argument = resolve_named_literal_type_argument(type_ref)
457
457
  return literal_type_argument if literal_type_argument
458
458
 
459
- resolve_type_ref(type_ref, type_params:, type_param_constraints:)
459
+ resolve_type_ref(type_ref, type_params:, type_param_constraints:, nested_types:)
460
460
  end
461
461
 
462
- def try_resolve_type_ref(type_ref, type_params:, type_param_constraints:)
463
- resolve_type_ref(type_ref, type_params:, type_param_constraints:)
462
+ def try_resolve_type_ref(type_ref, type_params:, type_param_constraints:, nested_types:)
463
+ resolve_type_ref(type_ref, type_params:, type_param_constraints:, nested_types:)
464
464
  rescue SemanticError
465
465
  nil
466
466
  end
@@ -867,10 +867,6 @@ module MilkTea
867
867
  Types.pointer_to(type)
868
868
  end
869
869
 
870
- def contains_type_var?(type)
871
- super
872
- end
873
-
874
870
  def resolve_nested_type_ref(parts)
875
871
  current = @ctx.types[parts.first]
876
872
  return nil unless current.is_a?(Types::Struct) || current.is_a?(Types::GenericStructDefinition)
@@ -975,18 +971,6 @@ module MilkTea
975
971
  nil
976
972
  end
977
973
 
978
- def collection_loop_type(type)
979
- super
980
- end
981
-
982
- def collection_loop_binding_type(iterable_type, element_type)
983
- super
984
- end
985
-
986
- def collection_loop_ref_element_type?(type)
987
- super
988
- end
989
-
990
974
  def iterator_loop_type(type)
991
975
  type = referenced_type(type) if ref_type?(type)
992
976
  iter_method = lookup_method(type, "iter")
@@ -1091,7 +1075,7 @@ module MilkTea
1091
1075
  when AST::Identifier
1092
1076
  return current_type_params[expression.name] if current_type_params.key?(expression.name)
1093
1077
 
1094
- @ctx.types[expression.name]
1078
+ lookup_named_type(expression.name)
1095
1079
  when AST::MemberAccess
1096
1080
  return nil unless expression.receiver.is_a?(AST::Identifier)
1097
1081
 
@@ -164,65 +164,6 @@ module MilkTea
164
164
  backing_type.integer_width == expected_type.integer_width
165
165
  end
166
166
 
167
- def common_numeric_type(left_type, right_type)
168
- left_type = left_type.backing_type if left_type.is_a?(Types::EnumBase)
169
- right_type = right_type.backing_type if right_type.is_a?(Types::EnumBase)
170
- return unless left_type.is_a?(Types::Primitive) && right_type.is_a?(Types::Primitive)
171
- return unless left_type.numeric? && right_type.numeric?
172
- return left_type if left_type == right_type
173
-
174
- return common_integer_type(left_type, right_type) if left_type.integer? && right_type.integer?
175
- return wider_float_type(left_type, right_type) if left_type.float? && right_type.float?
176
-
177
- float_type, integer_type = left_type.float? ? [left_type, right_type] : [right_type, left_type]
178
- return unless integer_type.integer? && integer_type.fixed_width_integer?
179
-
180
- float_type
181
- end
182
-
183
- def common_integer_type(left_type, right_type)
184
- left_type = left_type.backing_type if left_type.is_a?(Types::EnumBase)
185
- right_type = right_type.backing_type if right_type.is_a?(Types::EnumBase)
186
- return unless left_type.is_a?(Types::Primitive) && right_type.is_a?(Types::Primitive)
187
- return unless left_type.integer? && right_type.integer?
188
- return left_type if left_type == right_type
189
- return unless left_type.fixed_width_integer? && right_type.fixed_width_integer?
190
-
191
- # Same signedness: the wider type wins (both operands are losslessly
192
- # assignable to it).
193
- if left_type.signed_integer? == right_type.signed_integer?
194
- return left_type.integer_width >= right_type.integer_width ? left_type : right_type
195
- end
196
-
197
- # Mixed signed/unsigned: promote to the narrowest signed type that holds
198
- # both operands' full ranges, mirroring the lossless assignment rule. A
199
- # strictly-wider signed type covers an unsigned operand; equal-width or
200
- # wider unsigned operands widen to the next signed width. Mixing with a
201
- # 64-bit unsigned type has no safe signed common type, so callers fall
202
- # back to requiring an explicit cast.
203
- signed_type, unsigned_type = if left_type.signed_integer?
204
- [left_type, right_type]
205
- else
206
- [right_type, left_type]
207
- end
208
-
209
- return signed_type if signed_type.integer_width > unsigned_type.integer_width
210
-
211
- signed_type_above_width(unsigned_type.integer_width)
212
- end
213
-
214
- def signed_type_above_width(width)
215
- case width
216
- when 8 then @ctx.types.fetch("short")
217
- when 16 then @ctx.types.fetch("int")
218
- when 32 then @ctx.types.fetch("long")
219
- end
220
- end
221
-
222
- def wider_float_type(left_type, right_type)
223
- left_type.float_width >= right_type.float_width ? left_type : right_type
224
- end
225
-
226
167
  def pointer_arithmetic_result(operator, left_type, right_type)
227
168
  if pointer_type?(left_type) && integer_type?(right_type)
228
169
  require_unsafe!("pointer arithmetic requires unsafe") unless own_type?(left_type)
@@ -186,7 +186,6 @@ module MilkTea
186
186
  implemented_interfaces: {}, imports: {},
187
187
  private_types: {}, private_interfaces: {}, private_attributes: {},
188
188
  private_values: {}, private_functions: {}, private_methods: {},
189
- private_implemented_interfaces: {},
190
189
  )
191
190
  end
192
191
 
@@ -342,7 +341,6 @@ module MilkTea
342
341
  params: params.freeze,
343
342
  module_name: @ctx.module_name,
344
343
  builtin: false,
345
- ast: decl,
346
344
  )
347
345
  end
348
346
  end
@@ -650,6 +650,63 @@ module MilkTea
650
650
  def array_element_type(type)
651
651
  type.arguments.first
652
652
  end
653
+
654
+ def common_numeric_type(left_type, right_type)
655
+ left_type = left_type.backing_type if left_type.is_a?(Types::EnumBase)
656
+ right_type = right_type.backing_type if right_type.is_a?(Types::EnumBase)
657
+ return unless left_type.is_a?(Types::Primitive) && right_type.is_a?(Types::Primitive)
658
+ return unless left_type.numeric? && right_type.numeric?
659
+ return left_type if left_type == right_type
660
+
661
+ return common_integer_type(left_type, right_type) if left_type.integer? && right_type.integer?
662
+ return wider_float_type(left_type, right_type) if left_type.float? && right_type.float?
663
+
664
+ float_type, integer_type = left_type.float? ? [left_type, right_type] : [right_type, left_type]
665
+ return unless integer_type.integer? && integer_type.fixed_width_integer?
666
+
667
+ float_type
668
+ end
669
+
670
+ def common_integer_type(left_type, right_type)
671
+ left_type = left_type.backing_type if left_type.is_a?(Types::EnumBase)
672
+ right_type = right_type.backing_type if right_type.is_a?(Types::EnumBase)
673
+ return unless left_type.is_a?(Types::Primitive) && right_type.is_a?(Types::Primitive)
674
+ return unless left_type.integer? && right_type.integer?
675
+ return left_type if left_type == right_type
676
+ return unless left_type.fixed_width_integer? && right_type.fixed_width_integer?
677
+
678
+ # Same signedness: the wider type wins. Mixed signed/unsigned: promote to
679
+ # the narrowest signed type that holds both operands' full ranges. A
680
+ # strictly-wider signed type covers an unsigned operand; equal-width or
681
+ # wider unsigned operands widen to the next signed width. Mixing with a
682
+ # 64-bit unsigned type has no safe signed common type, so callers fall
683
+ # back to requiring an explicit cast.
684
+ if left_type.signed_integer? == right_type.signed_integer?
685
+ return left_type.integer_width >= right_type.integer_width ? left_type : right_type
686
+ end
687
+
688
+ signed_type, unsigned_type = if left_type.signed_integer?
689
+ [left_type, right_type]
690
+ else
691
+ [right_type, left_type]
692
+ end
693
+
694
+ return signed_type if signed_type.integer_width > unsigned_type.integer_width
695
+
696
+ signed_type_above_width(unsigned_type.integer_width)
697
+ end
698
+
699
+ def signed_type_above_width(width)
700
+ case width
701
+ when 8 then Types::Registry.primitive("short")
702
+ when 16 then Types::Registry.primitive("int")
703
+ when 32 then Types::Registry.primitive("long")
704
+ end
705
+ end
706
+
707
+ def wider_float_type(left_type, right_type)
708
+ left_type.float_width >= right_type.float_width ? left_type : right_type
709
+ end
653
710
  end
654
711
  end
655
712
  end
@@ -41,16 +41,28 @@ module MilkTea
41
41
  _intern([:string_view]) { StringView.new }
42
42
  end
43
43
 
44
+ # Param signature for intern keys. Parameter#eql? is name-insensitive
45
+ # (assignability must not depend on parameter names), so arrays of
46
+ # Parameter objects would conflate fn(value: int) with fn(arg0: int) in
47
+ # the intern pool. Embedding names here keeps distinct signatures
48
+ # distinct across independent programs sharing a long-lived pool (the LSP
49
+ # never resets the registry between checks).
50
+ def self.param_signature(params)
51
+ params.map { |p| [p.name, p.type, p.mutable, p.passing_mode, p.boundary_type] }
52
+ end
53
+
44
54
  def self.function(name, params:, return_type:, receiver_type: nil, receiver_editable: false, variadic: false, external: false)
45
55
  params_frozen = params.freeze
46
- _intern([:function, name, params_frozen, return_type, receiver_type, receiver_editable, variadic, external]) {
56
+ param_key = param_signature(params_frozen)
57
+ _intern([:function, name, param_key, return_type, receiver_type, receiver_editable, variadic, external]) {
47
58
  Function.new(name, params: params_frozen, return_type: return_type, receiver_type: receiver_type, receiver_editable: receiver_editable, variadic: variadic, external: external)
48
59
  }
49
60
  end
50
61
 
51
62
  def self.proc(params:, return_type:)
52
63
  params_frozen = params.freeze
53
- _intern([:proc, params_frozen, return_type]) { Proc.new(params: params_frozen, return_type: return_type) }
64
+ param_key = param_signature(params_frozen)
65
+ _intern([:proc, param_key, return_type]) { Proc.new(params: params_frozen, return_type: return_type) }
54
66
  end
55
67
 
56
68
  def self.parameter(name, type, mutable: false, passing_mode: :plain, boundary_type: nil)
@@ -1712,10 +1712,6 @@ module MilkTea
1712
1712
  GenericInstance.new("ptr", [type])
1713
1713
  end
1714
1714
 
1715
- def self.integer_type?(type)
1716
- type.is_a?(Primitive) && %w[int ptr_uint i8 i16 i32 i64 u8 u16 u32 u64].include?(type.name)
1717
- end
1718
-
1719
1715
  def self.array_type?(type)
1720
1716
  type.is_a?(GenericInstance) && type.name == "array" && type.arguments.length == 2
1721
1717
  end
@@ -360,6 +360,8 @@ module MilkTea
360
360
  end
361
361
 
362
362
  def handle_document_diagnostic(params)
363
+ return { kind: 'full', items: [] } if request_cancelled?(@current_request_id)
364
+
363
365
  uri = params.dig('textDocument', 'uri')
364
366
  return { kind: 'full', items: [] } unless uri
365
367
 
@@ -404,6 +406,8 @@ module MilkTea
404
406
  end
405
407
 
406
408
  def handle_workspace_diagnostic(params)
409
+ return { items: [] } if request_cancelled?(@current_request_id)
410
+
407
411
  progress = nil
408
412
  if (work_done_token = params['workDoneToken'])
409
413
  progress = create_progress_handle(@protocol, work_done_token)
@@ -416,7 +420,13 @@ module MilkTea
416
420
  end
417
421
 
418
422
  all_uris = @workspace.open_document_uris
419
- items = all_uris.filter_map do |uri|
423
+ items = []
424
+ all_uris.each do |uri|
425
+ # Coarse cancellation: workspace/diagnostic can iterate many cold
426
+ # documents (~1s each); bail early when the client cancels so we do
427
+ # not sink CPU into results that will be discarded.
428
+ break if request_cancelled?(@current_request_id)
429
+
420
430
  content = @workspace.get_content(uri)
421
431
  next if content.empty?
422
432
 
@@ -426,10 +436,10 @@ module MilkTea
426
436
 
427
437
  cached = @workspace_diagnostic_cache[uri]
428
438
  if cached && cached[:result_id] == prev_map[uri] && cached[:fingerprint] == fingerprint
429
- { uri: uri, kind: 'unchanged', resultId: result_id, items: [], version: nil }
439
+ items << { uri: uri, kind: 'unchanged', resultId: result_id, items: [], version: nil }
430
440
  else
431
441
  @workspace_diagnostic_cache[uri] = { result_id: result_id, fingerprint: fingerprint }
432
- { uri: uri, kind: 'full', resultId: result_id, items: diagnostics, version: nil }
442
+ items << { uri: uri, kind: 'full', resultId: result_id, items: diagnostics, version: nil }
433
443
  end
434
444
  end
435
445
 
@@ -443,10 +453,6 @@ module MilkTea
443
453
  { items: [] }
444
454
  end
445
455
 
446
- def refresh_workspace_diagnostics
447
- @protocol.write_notification('workspace/diagnostic/refresh', nil)
448
- end
449
-
450
456
  def find_match_end_line(lines, match_start_idx)
451
457
  return nil if match_start_idx >= lines.length
452
458