mt-lang 0.2.7 → 0.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/milk_tea/base.rb +1 -1
- data/lib/milk_tea/core/lowering/functions.rb +1 -1
- data/lib/milk_tea/core/lowering/resolve.rb +6 -0
- data/lib/milk_tea/core/semantic_analyzer/expressions.rb +2 -2
- data/lib/milk_tea/core/semantic_analyzer/function_binding.rb +39 -2
- data/lib/milk_tea/core/semantic_analyzer/statements.rb +11 -4
- data/lib/milk_tea/core/semantic_analyzer.rb +1 -1
- data/lib/milk_tea/lsp/diagnostics.rb +20 -3
- data/lib/milk_tea/lsp/server/code_actions.rb +12 -1
- data/lib/milk_tea/lsp/server/completion.rb +18 -6
- data/lib/milk_tea/lsp/server/definition.rb +1 -1
- data/lib/milk_tea/lsp/server/diagnostics_scheduling.rb +10 -0
- data/lib/milk_tea/lsp/server/hover.rb +4 -4
- data/lib/milk_tea/lsp/server/semantic_tokens.rb +1 -1
- data/lib/milk_tea/lsp/workspace/analysis.rb +3 -3
- data/lib/milk_tea/lsp/workspace/collection.rb +6 -0
- data/lib/milk_tea/tooling/cli.rb +9 -4
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fcc2383591d95c6043caebcb271aba6b70650528dafbb1a3cd8b906e74a5a6b6
|
|
4
|
+
data.tar.gz: 2e264acc4e563b29caf921062ca9156f92869d101b1f16f6516f9b412061a1c9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 17ef473e87741d685323aa279e434ce56a24b7c30cc4b48f61cbb7d4b7c49d47300c7cbad1e4211740fc35ecc29bf36ee941fa0b4bb18ac0fc19d04aee69d7ab
|
|
7
|
+
data.tar.gz: 9952dc4f2a306b443cbd57c4840965c8c7e870f8f9f976643b063635c64e371c0f8e903ea3446b124cd0b7e9ddf6754807c924e90426c1bfe789124bc08d6d44
|
data/lib/milk_tea/base.rb
CHANGED
|
@@ -80,7 +80,7 @@ module MilkTea
|
|
|
80
80
|
def resolve_extending_receiver_type(analysis, type_name)
|
|
81
81
|
if type_name.is_a?(AST::TypeRef)
|
|
82
82
|
generic_type = resolve_named_generic_type_for_analysis(analysis, type_name.name.parts)
|
|
83
|
-
if generic_type.is_a?(Types::GenericStructDefinition)
|
|
83
|
+
if generic_type.is_a?(Types::GenericStructDefinition) || generic_type.is_a?(Types::GenericVariantDefinition)
|
|
84
84
|
validate_methods_receiver_type_arguments!(type_name, generic_type)
|
|
85
85
|
return generic_type
|
|
86
86
|
end
|
|
@@ -430,6 +430,8 @@ module MilkTea
|
|
|
430
430
|
[:get, nil, nil, nil]
|
|
431
431
|
elsif (type = @ctx.types[callee.name]).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)
|
|
432
432
|
[ :struct_literal, nil, nil, type ]
|
|
433
|
+
elsif (type = @ctx.types[callee.name]).is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
|
|
434
|
+
raise LoweringError, "generic type #{callee.name} requires type arguments"
|
|
433
435
|
else
|
|
434
436
|
emit_fn = @artifacts.emitted_declarations.find { |d| d.is_a?(IR::Function) && d.name == callee.name }
|
|
435
437
|
if emit_fn
|
|
@@ -452,6 +454,10 @@ module MilkTea
|
|
|
452
454
|
return [:function, external_function_c_name(binding), nil, binding.type, binding]
|
|
453
455
|
end
|
|
454
456
|
imported_type = imported_module.types[callee.member]
|
|
457
|
+
if imported_type.is_a?(Types::GenericStructDefinition) || imported_type.is_a?(Types::GenericVariantDefinition)
|
|
458
|
+
raise LoweringError, "generic type #{callee.receiver.name}.#{callee.member} requires type arguments"
|
|
459
|
+
end
|
|
460
|
+
|
|
455
461
|
if imported_type.is_a?(Types::Struct) || imported_type.is_a?(Types::StringView) || task_type?(imported_type) || imported_type.is_a?(Types::Vector) || imported_type.is_a?(Types::Matrix) || imported_type.is_a?(Types::Quaternion)
|
|
456
462
|
return [:struct_literal, nil, nil, imported_module.types.fetch(callee.member)]
|
|
457
463
|
end
|
|
@@ -1005,7 +1005,7 @@ module MilkTea
|
|
|
1005
1005
|
)
|
|
1006
1006
|
|
|
1007
1007
|
check_function_call(callable, expression.arguments, scopes:)
|
|
1008
|
-
|
|
1008
|
+
validate_specialized_function_body(callable) unless callable.type_arguments.empty?
|
|
1009
1009
|
callable.type.return_type
|
|
1010
1010
|
when :method
|
|
1011
1011
|
callable = specialize_function_binding(
|
|
@@ -1018,7 +1018,7 @@ module MilkTea
|
|
|
1018
1018
|
raise_sema_error("cannot call editable method #{callable.name} on an immutable receiver") if callable.type.receiver_editable && !assignable_receiver?(receiver, scopes)
|
|
1019
1019
|
|
|
1020
1020
|
check_function_call(callable, expression.arguments, scopes:)
|
|
1021
|
-
|
|
1021
|
+
validate_specialized_function_body(callable) unless callable.type_arguments.empty?
|
|
1022
1022
|
callable.type.return_type
|
|
1023
1023
|
when :callable_value
|
|
1024
1024
|
check_callable_value_call(callable, expression.arguments, scopes:, callee_expression: expression.callee)
|
|
@@ -256,6 +256,22 @@ module MilkTea
|
|
|
256
256
|
end
|
|
257
257
|
end
|
|
258
258
|
|
|
259
|
+
# Validates the body of a specialized (instantiated) function or method
|
|
260
|
+
# binding. The owner checker may be in collecting-errors mode, which
|
|
261
|
+
# would silently swallow body errors into @structural_errors. We
|
|
262
|
+
# temporarily disable collect mode on the owner so the caller receives
|
|
263
|
+
# the SemanticError directly.
|
|
264
|
+
def validate_specialized_function_body(binding)
|
|
265
|
+
owner = binding.owner
|
|
266
|
+
prev_collecting = owner.instance_variable_get(:@collecting_errors)
|
|
267
|
+
owner.instance_variable_set(:@collecting_errors, false)
|
|
268
|
+
owner.send(:check_function, binding)
|
|
269
|
+
rescue SemanticError => e
|
|
270
|
+
raise unless e.message.include?("cannot assign through immutable")
|
|
271
|
+
ensure
|
|
272
|
+
owner.instance_variable_set(:@collecting_errors, prev_collecting) if owner
|
|
273
|
+
end
|
|
274
|
+
|
|
259
275
|
# Per-function error collection used by check_collecting_errors.
|
|
260
276
|
# Continues past individual function failures, accumulating SemanticErrors.
|
|
261
277
|
def check_functions_collecting(errors)
|
|
@@ -286,13 +302,29 @@ module MilkTea
|
|
|
286
302
|
end
|
|
287
303
|
end
|
|
288
304
|
|
|
305
|
+
# Scans generic method bodies for assignments to this through a
|
|
306
|
+
# non-editable receiver. Full body checking is deferred to call-site
|
|
307
|
+
# specialization, but immutable-this violations are type-independent.
|
|
308
|
+
def check_generic_method_immutable_this(binding, scopes)
|
|
309
|
+
this_binding = scopes.first&.values&.find { |v| v.name == "this" }
|
|
310
|
+
return unless this_binding
|
|
311
|
+
return if this_binding.mutable
|
|
312
|
+
|
|
313
|
+
binding.ast.body&.each do |statement|
|
|
314
|
+
next unless statement.is_a?(AST::Assignment) && statement.operator == "="
|
|
315
|
+
next unless statement.target.is_a?(AST::MemberAccess) && statement.target.receiver.is_a?(AST::Identifier) && statement.target.receiver.name == "this"
|
|
316
|
+
|
|
317
|
+
raise_sema_error("cannot assign through immutable this", statement.target)
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
|
|
289
321
|
def check_function(binding)
|
|
290
322
|
@local_completion_frames = @local_completion_frames.dup if @local_completion_frames.frozen?
|
|
291
323
|
|
|
292
324
|
previous_type_substitutions = @current_type_substitutions
|
|
293
325
|
previous_specialization_owner = @current_specialization_owner
|
|
294
326
|
started_check = false
|
|
295
|
-
return if binding.external
|
|
327
|
+
return if binding.external
|
|
296
328
|
return if @checked_function_bindings[binding.object_id]
|
|
297
329
|
return if @checking_function_bindings[binding.object_id]
|
|
298
330
|
|
|
@@ -303,6 +335,11 @@ module MilkTea
|
|
|
303
335
|
with_error_node(binding.ast) do
|
|
304
336
|
with_scope(binding.body_params) do |scopes|
|
|
305
337
|
start_local_completion_frame(binding, scopes)
|
|
338
|
+
if binding.type_params.any?
|
|
339
|
+
check_generic_method_immutable_this(binding, scopes)
|
|
340
|
+
return
|
|
341
|
+
end
|
|
342
|
+
|
|
306
343
|
if binding.ast.is_a?(AST::ForeignFunctionDecl)
|
|
307
344
|
record_callable_value_expression_site(binding.ast.mapping) unless binding.ast.mapping.is_a?(AST::Call)
|
|
308
345
|
expression = foreign_mapping_expression(binding.ast)
|
|
@@ -337,10 +374,10 @@ module MilkTea
|
|
|
337
374
|
end
|
|
338
375
|
end
|
|
339
376
|
end
|
|
340
|
-
@checked_function_bindings[binding.object_id] = true
|
|
341
377
|
ensure
|
|
342
378
|
return unless started_check
|
|
343
379
|
|
|
380
|
+
@checked_function_bindings[binding.object_id] = true
|
|
344
381
|
finish_local_completion_frame(binding)
|
|
345
382
|
@preassigned_local_binding_ids = {}
|
|
346
383
|
@nullability_flow_result = nil
|
|
@@ -304,10 +304,17 @@ module MilkTea
|
|
|
304
304
|
end
|
|
305
305
|
display_name = type_name.is_a?(Array) ? type_name.join(".") : type_name
|
|
306
306
|
raise_sema_error("unknown type #{display_name} for struct destructure") unless struct_type
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
307
|
+
if struct_type.is_a?(Types::GenericStructDefinition)
|
|
308
|
+
if value_type.is_a?(Types::StructInstance) && value_type.definition == struct_type
|
|
309
|
+
fields = value_type.fields
|
|
310
|
+
else
|
|
311
|
+
raise_sema_error("generic type #{display_name} requires type arguments")
|
|
312
|
+
end
|
|
313
|
+
else
|
|
314
|
+
raise_sema_error("#{display_name} is not a struct") unless struct_type.is_a?(Types::Struct) || struct_type.is_a?(Types::Tuple)
|
|
315
|
+
ensure_assignable!(value_type, struct_type, "cannot destructure #{value_type} as #{display_name}")
|
|
316
|
+
fields = struct_type.fields
|
|
317
|
+
end
|
|
311
318
|
raise_sema_error("destructure pattern has #{statement.destructure_bindings.length} bindings but #{display_name} has #{fields.length} fields") unless statement.destructure_bindings.length == fields.length
|
|
312
319
|
|
|
313
320
|
current_scope = current_actual_scope(scopes)
|
|
@@ -87,8 +87,17 @@ module MilkTea
|
|
|
87
87
|
sema_start = total_start ? monotonic_time : nil
|
|
88
88
|
sema_snapshot ||= SemanticAnalyzer.tooling_snapshot(ast, imported_modules: imported_modules.fetch(:modules), path: path, allow_missing_imports: true)
|
|
89
89
|
sema_facts = sema_snapshot.facts
|
|
90
|
+
cross_by_uri = {}
|
|
91
|
+
target_path = path.is_a?(String) ? File.expand_path(path) : nil
|
|
90
92
|
sema_snapshot.diagnostics.reject { |diagnostic| redundant_unknown_import_diagnostic?(diagnostic, unresolved_import_paths) }
|
|
91
|
-
.each
|
|
93
|
+
.each do |diagnostic|
|
|
94
|
+
if target_path && diagnostic.path && File.expand_path(diagnostic.path) != target_path
|
|
95
|
+
target_uri = path_to_uri(diagnostic.path)
|
|
96
|
+
(cross_by_uri[target_uri] ||= []) << format_tooling_diagnostic(diagnostic, stage: 'sema')
|
|
97
|
+
else
|
|
98
|
+
diagnostics << format_tooling_diagnostic(diagnostic, stage: 'sema')
|
|
99
|
+
end
|
|
100
|
+
end
|
|
92
101
|
sema_ms = elapsed_ms(sema_start) if sema_start
|
|
93
102
|
rescue StandardError => e
|
|
94
103
|
log_diagnostics_warning("Error collecting diagnostics: #{e.message}")
|
|
@@ -142,7 +151,7 @@ module MilkTea
|
|
|
142
151
|
log_diagnostics_warning("Error collecting lint diagnostics: #{e.message}")
|
|
143
152
|
end
|
|
144
153
|
|
|
145
|
-
{ diagnostics: diagnostics, facts: sema_facts, sema_snapshot: sema_snapshot }
|
|
154
|
+
{ diagnostics: diagnostics, cross_file_diagnostics: cross_by_uri, facts: sema_facts, sema_snapshot: sema_snapshot }
|
|
146
155
|
ensure
|
|
147
156
|
if total_start
|
|
148
157
|
lint_breakdown = lint_profile&.summary(limit: 12)
|
|
@@ -196,7 +205,15 @@ module MilkTea
|
|
|
196
205
|
def self.redundant_unknown_import_diagnostic?(diagnostic, unresolved_import_paths)
|
|
197
206
|
return false unless diagnostic&.message.to_s.start_with?("unknown import ")
|
|
198
207
|
|
|
199
|
-
|
|
208
|
+
import_path = diagnostic.message.to_s.match(/unknown import (.+)$/)&.captures&.first
|
|
209
|
+
return false unless import_path
|
|
210
|
+
|
|
211
|
+
unresolved_import_paths.include?(import_path)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def self.path_to_uri(path)
|
|
215
|
+
escaped_path = path.split('/').map { |seg| CGI.escape(seg).gsub('+', '%20') }.join('/')
|
|
216
|
+
"file://#{escaped_path}"
|
|
200
217
|
end
|
|
201
218
|
|
|
202
219
|
def self.uri_to_path(uri)
|
|
@@ -366,7 +366,8 @@ module MilkTea
|
|
|
366
366
|
return { kind: 'full', items: [] } unless uri
|
|
367
367
|
|
|
368
368
|
content = @workspace.get_content(uri)
|
|
369
|
-
|
|
369
|
+
result = @workspace.collect_diagnostics(uri)
|
|
370
|
+
diagnostics = result
|
|
370
371
|
fingerprint = diagnostics_fingerprint(content, diagnostics)
|
|
371
372
|
previous_result_id = params['previousResultId']
|
|
372
373
|
cached = @diagnostic_report_cache[uri]
|
|
@@ -384,6 +385,16 @@ module MilkTea
|
|
|
384
385
|
fingerprint: fingerprint
|
|
385
386
|
}
|
|
386
387
|
|
|
388
|
+
cross = @workspace.cross_file_diagnostics
|
|
389
|
+
if cross&.any?
|
|
390
|
+
cross.each do |target_uri, items|
|
|
391
|
+
@protocol.write_notification('textDocument/publishDiagnostics', {
|
|
392
|
+
uri: target_uri,
|
|
393
|
+
diagnostics: items
|
|
394
|
+
})
|
|
395
|
+
end
|
|
396
|
+
end
|
|
397
|
+
|
|
387
398
|
{
|
|
388
399
|
kind: 'full',
|
|
389
400
|
resultId: result_id,
|
|
@@ -473,7 +473,7 @@ module MilkTea
|
|
|
473
473
|
|
|
474
474
|
current_type = first_type
|
|
475
475
|
chain_segments[1..].each do |seg|
|
|
476
|
-
field_owner = project_field_receiver_type_for_completion(current_type)
|
|
476
|
+
field_owner = project_field_receiver_type_for_completion(current_type, facts)
|
|
477
477
|
if field_owner.respond_to?(:field) && (field_type = field_owner.field(seg))
|
|
478
478
|
current_type = field_type
|
|
479
479
|
else
|
|
@@ -674,7 +674,7 @@ module MilkTea
|
|
|
674
674
|
def completion_items_for_value_receiver(facts, receiver_type, prefix)
|
|
675
675
|
items = []
|
|
676
676
|
|
|
677
|
-
field_receiver_type = project_field_receiver_type_for_completion(receiver_type)
|
|
677
|
+
field_receiver_type = project_field_receiver_type_for_completion(receiver_type, facts)
|
|
678
678
|
if field_receiver_type.respond_to?(:fields)
|
|
679
679
|
field_receiver_type.fields.each do |fname, ftype|
|
|
680
680
|
next unless prefix.empty? || fname.start_with?(prefix)
|
|
@@ -763,8 +763,20 @@ module MilkTea
|
|
|
763
763
|
dispatch_receiver_type == receiver_type ? receiver_type : dispatch_receiver_type
|
|
764
764
|
end
|
|
765
765
|
|
|
766
|
-
def project_field_receiver_type_for_completion(type)
|
|
767
|
-
project_receiver_type_for_completion(type)
|
|
766
|
+
def project_field_receiver_type_for_completion(type, facts = nil)
|
|
767
|
+
type = project_receiver_type_for_completion(type)
|
|
768
|
+
return type.definition if type.is_a?(Types::StructInstance)
|
|
769
|
+
return field_type_from_struct_definition(type, facts) if facts
|
|
770
|
+
|
|
771
|
+
type
|
|
772
|
+
end
|
|
773
|
+
|
|
774
|
+
def field_type_from_struct_definition(type, facts)
|
|
775
|
+
return type unless type.is_a?(Types::GenericInstance)
|
|
776
|
+
return type if ref_type_name?(type) || pointer_type_name?(type)
|
|
777
|
+
|
|
778
|
+
struct_def = facts.types[type.name]
|
|
779
|
+
struct_def if struct_def&.respond_to?(:fields)
|
|
768
780
|
end
|
|
769
781
|
|
|
770
782
|
def project_method_receiver_type_for_completion(type)
|
|
@@ -778,8 +790,8 @@ module MilkTea
|
|
|
778
790
|
type
|
|
779
791
|
end
|
|
780
792
|
|
|
781
|
-
def field_owner_type(receiver_type)
|
|
782
|
-
aggregate_type = project_field_receiver_type_for_completion(receiver_type)
|
|
793
|
+
def field_owner_type(receiver_type, facts = nil)
|
|
794
|
+
aggregate_type = project_field_receiver_type_for_completion(receiver_type, facts)
|
|
783
795
|
return aggregate_type.definition if aggregate_type.is_a?(Types::StructInstance)
|
|
784
796
|
|
|
785
797
|
aggregate_type
|
|
@@ -247,7 +247,7 @@ module MilkTea
|
|
|
247
247
|
return nil unless current_type
|
|
248
248
|
|
|
249
249
|
chain[:segments][1..hovered_segment[:position]].each do |segment|
|
|
250
|
-
field_receiver_type = project_field_receiver_type_for_completion(current_type)
|
|
250
|
+
field_receiver_type = project_field_receiver_type_for_completion(current_type, facts)
|
|
251
251
|
if field_receiver_type.respond_to?(:field) && (field_type = field_receiver_type.field(segment[:name]))
|
|
252
252
|
return field_definition_location(current_uri, field_receiver_type, segment[:name]) if segment[:token_index] == token_index
|
|
253
253
|
|
|
@@ -133,6 +133,16 @@ module MilkTea
|
|
|
133
133
|
diagnostics: diagnostics
|
|
134
134
|
})
|
|
135
135
|
notify_diagnostic_errors(uri, diagnostics)
|
|
136
|
+
|
|
137
|
+
cross = @workspace.cross_file_diagnostics
|
|
138
|
+
if cross&.any?
|
|
139
|
+
cross.each do |target_uri, items|
|
|
140
|
+
@protocol.write_notification('textDocument/publishDiagnostics', {
|
|
141
|
+
uri: target_uri,
|
|
142
|
+
diagnostics: items
|
|
143
|
+
})
|
|
144
|
+
end
|
|
145
|
+
end
|
|
136
146
|
end
|
|
137
147
|
elsif perf_logging?
|
|
138
148
|
@diagnostics_perf[:dropped_stale] += 1
|
|
@@ -649,7 +649,7 @@ module MilkTea
|
|
|
649
649
|
return nil unless current_type
|
|
650
650
|
|
|
651
651
|
chain[:segments][1..hovered_segment[:position]].each do |segment|
|
|
652
|
-
field_receiver_type = project_field_receiver_type_for_completion(current_type)
|
|
652
|
+
field_receiver_type = project_field_receiver_type_for_completion(current_type, facts)
|
|
653
653
|
if field_receiver_type.respond_to?(:field) && (field_type = field_receiver_type.field(segment[:name]))
|
|
654
654
|
source_location = field_definition_location(current_uri, field_receiver_type, segment[:name])
|
|
655
655
|
|
|
@@ -787,7 +787,7 @@ module MilkTea
|
|
|
787
787
|
return nil unless receiver_info
|
|
788
788
|
|
|
789
789
|
field_name = tokens[token_index].lexeme
|
|
790
|
-
receiver_type = project_field_receiver_type_for_completion(receiver_info[:type])
|
|
790
|
+
receiver_type = project_field_receiver_type_for_completion(receiver_info[:type], facts)
|
|
791
791
|
return nil unless receiver_type.respond_to?(:field)
|
|
792
792
|
|
|
793
793
|
field_type = receiver_type.field(field_name)
|
|
@@ -809,7 +809,7 @@ module MilkTea
|
|
|
809
809
|
|
|
810
810
|
field_name = tokens[token_index].lexeme
|
|
811
811
|
if receiver_info
|
|
812
|
-
receiver_type = project_field_receiver_type_for_completion(receiver_info[:type])
|
|
812
|
+
receiver_type = project_field_receiver_type_for_completion(receiver_info[:type], facts)
|
|
813
813
|
if receiver_type.respond_to?(:field)
|
|
814
814
|
field_type = receiver_type.field(field_name)
|
|
815
815
|
if field_type
|
|
@@ -1421,7 +1421,7 @@ module MilkTea
|
|
|
1421
1421
|
def_index = tokens.index(definition_token)
|
|
1422
1422
|
if def_index
|
|
1423
1423
|
prev = previous_non_trivia_token_index(tokens, def_index)
|
|
1424
|
-
if prev
|
|
1424
|
+
if prev
|
|
1425
1425
|
case tokens[prev].lexeme
|
|
1426
1426
|
when "let" then kind = :let
|
|
1427
1427
|
when "var" then kind = :var
|
|
@@ -961,7 +961,7 @@ module MilkTea
|
|
|
961
961
|
resolve_receiver_value_type(facts, receiver_tok).then do |receiver_type|
|
|
962
962
|
next false unless receiver_type
|
|
963
963
|
|
|
964
|
-
field_receiver_type = project_field_receiver_type_for_completion(receiver_type)
|
|
964
|
+
field_receiver_type = project_field_receiver_type_for_completion(receiver_type, facts)
|
|
965
965
|
next false unless field_receiver_type.respond_to?(:field)
|
|
966
966
|
|
|
967
967
|
callable_semantic_type?(field_receiver_type.field(name))
|
|
@@ -158,9 +158,9 @@ module MilkTea
|
|
|
158
158
|
ast = get_ast(uri)
|
|
159
159
|
return @last_good_tooling_snapshot_cache[uri] if ast.nil?
|
|
160
160
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
161
|
+
result = MilkTea::SemanticAnalyzer.check_collecting_errors(ast, path:)
|
|
162
|
+
facts = result[:analysis]
|
|
163
|
+
MilkTea::SemanticAnalyzer::ToolingSnapshot.new(facts:, diagnostics: (Array(result[:errors]).map { |e| e.to_diagnostic(path:) } || []).freeze)
|
|
164
164
|
end
|
|
165
165
|
if snapshot&.facts
|
|
166
166
|
@last_good_tooling_snapshot_cache[uri] = snapshot
|
|
@@ -56,10 +56,12 @@ module MilkTea
|
|
|
56
56
|
)
|
|
57
57
|
collect_ms = elapsed_ms(collect_start) if collect_start
|
|
58
58
|
diagnostics = result[:diagnostics]
|
|
59
|
+
cross_by_uri = result[:cross_file_diagnostics] || {}
|
|
59
60
|
facts = result[:facts]
|
|
60
61
|
snapshot = result[:sema_snapshot]
|
|
61
62
|
@facts_cache_mutex.synchronize do
|
|
62
63
|
if @facts_generation[uri] == generation
|
|
64
|
+
@cross_file_diagnostics = cross_by_uri
|
|
63
65
|
@tooling_snapshot_cache[uri] = snapshot if snapshot
|
|
64
66
|
@last_good_tooling_snapshot_cache[uri] = snapshot if snapshot&.facts
|
|
65
67
|
@facts_cache[uri] = facts if facts
|
|
@@ -93,6 +95,10 @@ module MilkTea
|
|
|
93
95
|
end
|
|
94
96
|
end
|
|
95
97
|
end
|
|
98
|
+
|
|
99
|
+
def cross_file_diagnostics
|
|
100
|
+
@facts_cache_mutex.synchronize { @cross_file_diagnostics }
|
|
101
|
+
end
|
|
96
102
|
end
|
|
97
103
|
end
|
|
98
104
|
end
|
data/lib/milk_tea/tooling/cli.rb
CHANGED
|
@@ -684,12 +684,17 @@ module MilkTea
|
|
|
684
684
|
diagnostics = sort_by_location(diagnostics)
|
|
685
685
|
|
|
686
686
|
if diagnostics.any? || closure_errors.any?
|
|
687
|
-
|
|
687
|
+
main_source = read_source_file(path)
|
|
688
|
+
main_abs = File.expand_path(path)
|
|
688
689
|
diagnostics.each do |d|
|
|
690
|
+
same_file = !d.respond_to?(:path) || d.path.nil? || File.expand_path(d.path) == main_abs
|
|
691
|
+
source = same_file ? main_source : nil
|
|
689
692
|
@err.puts(ErrorFormatter.format(d, source:, color: error_color?(@err)))
|
|
690
693
|
end
|
|
691
694
|
closure_errors.each do |d|
|
|
692
|
-
|
|
695
|
+
same_file = !d.respond_to?(:path) || d.path.nil? || File.expand_path(d.path) == main_abs
|
|
696
|
+
source = same_file ? main_source : nil
|
|
697
|
+
@err.puts(ErrorFormatter.format(d, source:, color: error_color?(@err)))
|
|
693
698
|
end
|
|
694
699
|
all_diagnostics.concat(diagnostics)
|
|
695
700
|
all_diagnostics.concat(closure_errors)
|
|
@@ -711,9 +716,9 @@ module MilkTea
|
|
|
711
716
|
parts << "#{info_count} #{info_count == 1 ? 'note' : 'notes'}" if info_count > 0
|
|
712
717
|
body = parts.join("; ")
|
|
713
718
|
if error_count > 0
|
|
714
|
-
@err.puts("
|
|
719
|
+
@err.puts("#{body} found")
|
|
715
720
|
elsif warning_count > 0
|
|
716
|
-
@err.puts("
|
|
721
|
+
@err.puts("#{body}")
|
|
717
722
|
end
|
|
718
723
|
final_error_count = error_count + (resolution[:warnings_as_errors] ? warning_count : 0)
|
|
719
724
|
final_error_count > 0 ? 1 : 0
|
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.2.
|
|
4
|
+
version: 0.2.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Long (Teefan) Tran
|
|
@@ -583,7 +583,7 @@ metadata:
|
|
|
583
583
|
homepage_uri: https://teefan.github.io/mt-lang/
|
|
584
584
|
source_code_uri: https://github.com/teefan/mt-lang
|
|
585
585
|
post_install_message: |
|
|
586
|
-
Milk Tea 0.2.
|
|
586
|
+
Milk Tea 0.2.8 installed!
|
|
587
587
|
|
|
588
588
|
System requirements:
|
|
589
589
|
- A C compiler (gcc or clang) must be available on PATH
|