mt-lang 0.3.9 → 0.3.10

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 (200) hide show
  1. checksums.yaml +4 -4
  2. data/lib/milk_tea/base.rb +1 -2
  3. data/lib/milk_tea/bindings/bindgen/ast_parser.rb +0 -2
  4. data/lib/milk_tea/bindings/bindgen/declaration.rb +0 -2
  5. data/lib/milk_tea/bindings/bindgen/emitter.rb +0 -2
  6. data/lib/milk_tea/bindings/bindgen/overrides.rb +0 -2
  7. data/lib/milk_tea/bindings/bindgen/type_mapper.rb +51 -53
  8. data/lib/milk_tea/bindings/imported_bindings/generator.rb +7 -9
  9. data/lib/milk_tea/bindings/imported_bindings/method_source.rb +0 -2
  10. data/lib/milk_tea/bindings/imported_bindings/naming.rb +6 -8
  11. data/lib/milk_tea/bindings/imported_bindings.rb +0 -2
  12. data/lib/milk_tea/bindings/opengl_registry.rb +3 -7
  13. data/lib/milk_tea/bindings/steamworks.rb +12 -16
  14. data/lib/milk_tea/bindings/upstream_sources.rb +10 -14
  15. data/lib/milk_tea/bindings/vendored_box2d.rb +10 -12
  16. data/lib/milk_tea/bindings/vendored_cjson.rb +6 -8
  17. data/lib/milk_tea/bindings/vendored_flecs.rb +10 -12
  18. data/lib/milk_tea/bindings/vendored_glfw.rb +11 -13
  19. data/lib/milk_tea/bindings/vendored_libuv.rb +11 -13
  20. data/lib/milk_tea/bindings/vendored_pcre2.rb +11 -13
  21. data/lib/milk_tea/bindings/vendored_raylib.rb +6 -10
  22. data/lib/milk_tea/bindings/vendored_sdl3.rb +11 -13
  23. data/lib/milk_tea/bindings/vendored_steamworks.rb +1 -5
  24. data/lib/milk_tea/core/ast.rb +103 -45
  25. data/lib/milk_tea/core/async_runtime_installer.rb +0 -2
  26. data/lib/milk_tea/core/bindings/attribute_binding.rb +1 -3
  27. data/lib/milk_tea/core/c_backend/aggregate_utils.rb +147 -84
  28. data/lib/milk_tea/core/c_backend/control_flow_emission.rb +394 -396
  29. data/lib/milk_tea/core/c_backend/expressions.rb +489 -476
  30. data/lib/milk_tea/core/c_backend/feature_detection.rb +446 -437
  31. data/lib/milk_tea/core/c_backend/format_helpers.rb +0 -2
  32. data/lib/milk_tea/core/c_backend/reachability.rb +339 -341
  33. data/lib/milk_tea/core/c_backend/reinterpret.rb +231 -217
  34. data/lib/milk_tea/core/c_backend/runtime_helpers.rb +531 -526
  35. data/lib/milk_tea/core/c_backend/statements.rb +528 -530
  36. data/lib/milk_tea/core/c_backend/type_collectors.rb +1344 -1346
  37. data/lib/milk_tea/core/c_backend/type_declaration.rb +215 -213
  38. data/lib/milk_tea/core/c_backend/type_system.rb +347 -349
  39. data/lib/milk_tea/core/c_backend.rb +17 -9
  40. data/lib/milk_tea/core/compatibility_helpers.rb +0 -2
  41. data/lib/milk_tea/core/compile_time/const_eval.rb +7 -12
  42. data/lib/milk_tea/core/compile_time.rb +32 -38
  43. data/lib/milk_tea/core/control_flow/builder.rb +3 -5
  44. data/lib/milk_tea/core/control_flow/constant_propagation.rb +14 -17
  45. data/lib/milk_tea/core/control_flow/definite_assignment.rb +0 -1
  46. data/lib/milk_tea/core/ir.rb +10 -10
  47. data/lib/milk_tea/core/lexer/character_classes.rb +5 -7
  48. data/lib/milk_tea/core/lexer/format_strings.rb +7 -9
  49. data/lib/milk_tea/core/lexer/heredocs.rb +22 -22
  50. data/lib/milk_tea/core/lexer/indentation.rb +0 -2
  51. data/lib/milk_tea/core/lexer/numbers.rb +0 -2
  52. data/lib/milk_tea/core/lexer/recovery.rb +0 -2
  53. data/lib/milk_tea/core/lexer/strings.rb +0 -2
  54. data/lib/milk_tea/core/lexer/symbols.rb +0 -2
  55. data/lib/milk_tea/core/lexer/trivia.rb +0 -2
  56. data/lib/milk_tea/core/lexer.rb +0 -2
  57. data/lib/milk_tea/core/lowering/async/analysis.rb +0 -2
  58. data/lib/milk_tea/core/lowering/async/lowering.rb +1264 -1265
  59. data/lib/milk_tea/core/lowering/async/normalization.rb +0 -2
  60. data/lib/milk_tea/core/lowering/async.rb +627 -630
  61. data/lib/milk_tea/core/lowering/block.rb +413 -416
  62. data/lib/milk_tea/core/lowering/calls.rb +1381 -1384
  63. data/lib/milk_tea/core/lowering/declarations.rb +180 -183
  64. data/lib/milk_tea/core/lowering/dyn.rb +48 -50
  65. data/lib/milk_tea/core/lowering/events.rb +983 -985
  66. data/lib/milk_tea/core/lowering/expressions.rb +1513 -1518
  67. data/lib/milk_tea/core/lowering/foreign_cstr.rb +181 -184
  68. data/lib/milk_tea/core/lowering/functions.rb +185 -188
  69. data/lib/milk_tea/core/lowering/loops.rb +1028 -1031
  70. data/lib/milk_tea/core/lowering/proc.rb +363 -366
  71. data/lib/milk_tea/core/lowering/resolve.rb +2133 -2135
  72. data/lib/milk_tea/core/lowering/scans.rb +179 -181
  73. data/lib/milk_tea/core/lowering/str_buffer.rb +102 -105
  74. data/lib/milk_tea/core/lowering/utils.rb +1040 -1044
  75. data/lib/milk_tea/core/lowering.rb +5 -7
  76. data/lib/milk_tea/core/module_binder.rb +0 -2
  77. data/lib/milk_tea/core/module_loader/errors.rb +4 -2
  78. data/lib/milk_tea/core/module_loader.rb +113 -20
  79. data/lib/milk_tea/core/module_path_resolver.rb +0 -2
  80. data/lib/milk_tea/core/module_roots.rb +6 -8
  81. data/lib/milk_tea/core/parser/attributes.rb +0 -2
  82. data/lib/milk_tea/core/parser/blocks.rb +0 -2
  83. data/lib/milk_tea/core/parser/declarations.rb +0 -2
  84. data/lib/milk_tea/core/parser/expressions.rb +8 -9
  85. data/lib/milk_tea/core/parser/recovery.rb +0 -2
  86. data/lib/milk_tea/core/parser/statements.rb +0 -2
  87. data/lib/milk_tea/core/parser/types.rb +8 -10
  88. data/lib/milk_tea/core/parser.rb +0 -2
  89. data/lib/milk_tea/core/pretty_printer/ast_formatter.rb +31 -33
  90. data/lib/milk_tea/core/pretty_printer/base_formatter.rb +0 -2
  91. data/lib/milk_tea/core/pretty_printer/ir_formatter.rb +0 -2
  92. data/lib/milk_tea/core/semantic_analyzer/analysis_context.rb +0 -2
  93. data/lib/milk_tea/core/semantic_analyzer/attributes.rb +14 -16
  94. data/lib/milk_tea/core/semantic_analyzer/calls.rb +0 -2
  95. data/lib/milk_tea/core/semantic_analyzer/expressions.rb +1 -14
  96. data/lib/milk_tea/core/semantic_analyzer/flow_refinement.rb +18 -21
  97. data/lib/milk_tea/core/semantic_analyzer/foreign_functions.rb +0 -3
  98. data/lib/milk_tea/core/semantic_analyzer/function_binding.rb +12 -15
  99. data/lib/milk_tea/core/semantic_analyzer/generics.rb +57 -59
  100. data/lib/milk_tea/core/semantic_analyzer/interface_conformance.rb +0 -2
  101. data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +5 -9
  102. data/lib/milk_tea/core/semantic_analyzer/nullability.rb +0 -3
  103. data/lib/milk_tea/core/semantic_analyzer/statements.rb +35 -40
  104. data/lib/milk_tea/core/semantic_analyzer/top_level.rb +10 -12
  105. data/lib/milk_tea/core/semantic_analyzer/type_compatibility.rb +0 -6
  106. data/lib/milk_tea/core/semantic_analyzer/type_declaration.rb +102 -105
  107. data/lib/milk_tea/core/semantic_analyzer.rb +17 -8
  108. data/lib/milk_tea/core/types/layout.rb +21 -22
  109. data/lib/milk_tea/core/types/predicates.rb +0 -2
  110. data/lib/milk_tea/core/types/registry.rb +16 -18
  111. data/lib/milk_tea/core/types/visitor.rb +0 -4
  112. data/lib/milk_tea/dap/backends/lldb_dap.rb +0 -2
  113. data/lib/milk_tea/dap/protocol.rb +1 -1
  114. data/lib/milk_tea/dap/server/breakpoints.rb +0 -2
  115. data/lib/milk_tea/dap/server/debug_map.rb +0 -2
  116. data/lib/milk_tea/dap/server/handlers.rb +0 -2
  117. data/lib/milk_tea/dap/server/launch.rb +0 -2
  118. data/lib/milk_tea/dap/server/lldb_backend.rb +8 -10
  119. data/lib/milk_tea/dap/server/pause_diagnostics.rb +14 -16
  120. data/lib/milk_tea/dap/server/utilities.rb +0 -2
  121. data/lib/milk_tea/dap/server/wire.rb +0 -2
  122. data/lib/milk_tea/dap/server.rb +0 -2
  123. data/lib/milk_tea/lsp/diagnostics.rb +16 -16
  124. data/lib/milk_tea/lsp/server/call_hierarchy.rb +11 -12
  125. data/lib/milk_tea/lsp/server/code_actions.rb +355 -357
  126. data/lib/milk_tea/lsp/server/code_lens.rb +23 -25
  127. data/lib/milk_tea/lsp/server/completion.rb +873 -875
  128. data/lib/milk_tea/lsp/server/configuration.rb +129 -131
  129. data/lib/milk_tea/lsp/server/debug_info.rb +0 -2
  130. data/lib/milk_tea/lsp/server/definition.rb +564 -565
  131. data/lib/milk_tea/lsp/server/diagnostics_scheduling.rb +191 -193
  132. data/lib/milk_tea/lsp/server/execute_command.rb +0 -2
  133. data/lib/milk_tea/lsp/server/folding_range.rb +0 -4
  134. data/lib/milk_tea/lsp/server/formatting.rb +478 -480
  135. data/lib/milk_tea/lsp/server/hover.rb +1282 -1284
  136. data/lib/milk_tea/lsp/server/inlay_hints.rb +179 -181
  137. data/lib/milk_tea/lsp/server/lifecycle.rb +192 -194
  138. data/lib/milk_tea/lsp/server/linked_editing_range.rb +0 -2
  139. data/lib/milk_tea/lsp/server/on_type_formatting.rb +0 -2
  140. data/lib/milk_tea/lsp/server/progress.rb +0 -2
  141. data/lib/milk_tea/lsp/server/references.rb +316 -318
  142. data/lib/milk_tea/lsp/server/rename.rb +445 -447
  143. data/lib/milk_tea/lsp/server/selection_range.rb +0 -4
  144. data/lib/milk_tea/lsp/server/semantic_tokens.rb +1318 -1320
  145. data/lib/milk_tea/lsp/server/signature_help.rb +146 -148
  146. data/lib/milk_tea/lsp/server/text_documents.rb +99 -101
  147. data/lib/milk_tea/lsp/server/type_hierarchy.rb +2 -4
  148. data/lib/milk_tea/lsp/server/utilities.rb +397 -399
  149. data/lib/milk_tea/lsp/server.rb +0 -3
  150. data/lib/milk_tea/lsp/workspace/analysis.rb +40 -42
  151. data/lib/milk_tea/lsp/workspace/dependency_graph.rb +4 -10
  152. data/lib/milk_tea/lsp/workspace/utilities.rb +19 -19
  153. data/lib/milk_tea/packages/atomic_write.rb +4 -5
  154. data/lib/milk_tea/packages/dependency_solver.rb +15 -15
  155. data/lib/milk_tea/packages/lock.rb +4 -4
  156. data/lib/milk_tea/packages/manager_cli.rb +1 -1
  157. data/lib/milk_tea/packages/manifest.rb +3 -3
  158. data/lib/milk_tea/packages/registry_store.rb +4 -6
  159. data/lib/milk_tea/packages/services.rb +16 -16
  160. data/lib/milk_tea/packages/source_cache.rb +4 -6
  161. data/lib/milk_tea/packages/source_resolver.rb +44 -44
  162. data/lib/milk_tea/packages/version.rb +8 -8
  163. data/lib/milk_tea/tooling/build.rb +3 -7
  164. data/lib/milk_tea/tooling/build_cache.rb +0 -2
  165. data/lib/milk_tea/tooling/debug_info_formatter.rb +31 -33
  166. data/lib/milk_tea/tooling/debug_map.rb +8 -10
  167. data/lib/milk_tea/tooling/docs_app.rb +0 -2
  168. data/lib/milk_tea/tooling/linter/doc_tags.rb +25 -27
  169. data/lib/milk_tea/tooling/linter/fix_engine.rb +87 -24
  170. data/lib/milk_tea/tooling/linter/flow_rules.rb +44 -46
  171. data/lib/milk_tea/tooling/linter/imports_platform.rb +14 -16
  172. data/lib/milk_tea/tooling/linter/release_rules.rb +3 -5
  173. data/lib/milk_tea/tooling/linter/reserved_names.rb +23 -25
  174. data/lib/milk_tea/tooling/linter/rules.rb +87 -89
  175. data/lib/milk_tea/tooling/linter/source_helpers.rb +40 -42
  176. data/lib/milk_tea/tooling/linter/trailing_comma.rb +17 -19
  177. data/lib/milk_tea/tooling/linter/visitors.rb +112 -54
  178. data/lib/milk_tea/tooling/linter.rb +0 -2
  179. data/lib/milk_tea/tooling/project_scaffold.rb +0 -2
  180. data/lib/milk_tea/tooling/run.rb +0 -2
  181. data/lib/milk_tea/tooling/toolchain_cli.rb +0 -2
  182. data/std/cli.mt +13 -32
  183. data/std/color.mt +28 -28
  184. data/std/encoding.mt +4 -4
  185. data/std/graph.mt +1 -2
  186. data/std/hash.mt +14 -14
  187. data/std/http/server.mt +3 -3
  188. data/std/input.mt +1 -1
  189. data/std/json.mt +1 -1
  190. data/std/linear_algebra.mt +6 -6
  191. data/std/net/mux.mt +1 -1
  192. data/std/noise.mt +23 -23
  193. data/std/parse.mt +2 -2
  194. data/std/process.mt +3 -4
  195. data/std/sparse_set.mt +1 -1
  196. data/std/steering.mt +5 -5
  197. data/std/str.mt +1 -1
  198. data/std/tween.mt +4 -4
  199. data/std/utility.mt +3 -3
  200. metadata +2 -2
@@ -4,741 +4,740 @@ module MilkTea
4
4
  module LSP
5
5
  class Server
6
6
  module ServerDefinition
7
- private
7
+ def is_builtin_name?(name, tokens, token_index)
8
+ return false unless token_index
9
+ builtin_hover_info(name, tokens, token_index)
10
+ end
8
11
 
9
- def is_builtin_name?(name, tokens, token_index)
10
- return false unless token_index
11
- builtin_hover_info(name, tokens, token_index)
12
- end
12
+ def handle_definition(params)
13
+ handle_definition_request('textDocument/definition', params, error_label: 'definition')
14
+ end
13
15
 
14
- def handle_definition(params)
15
- handle_definition_request('textDocument/definition', params, error_label: 'definition')
16
- end
16
+ def handle_declaration(params)
17
+ handle_definition_request('textDocument/declaration', params, error_label: 'declaration')
18
+ end
17
19
 
18
- def handle_declaration(params)
19
- handle_definition_request('textDocument/declaration', params, error_label: 'declaration')
20
- end
20
+ def handle_type_definition(params)
21
+ stages = new_perf_stages
22
+ total_start = stages ? monotonic_time : nil
23
+ uri = params.dig('textDocument', 'uri')
24
+ result_state = 'miss'
25
+
26
+ location = resolve_type_definition_location(params, stages: stages)
27
+ result_state = location ? 'hit' : 'miss'
28
+ location
29
+ rescue StandardError => e
30
+ result_state = 'error'
31
+ warn "Error in typeDefinition handler: #{e.message}"
32
+ nil
33
+ ensure
34
+ log_request_stage_breakdown('textDocument/typeDefinition', total_start, uri: uri, stages: stages, summary: "result=#{result_state}")
35
+ end
21
36
 
22
- def handle_type_definition(params)
23
- stages = new_perf_stages
24
- total_start = stages ? monotonic_time : nil
25
- uri = params.dig('textDocument', 'uri')
26
- result_state = 'miss'
27
-
28
- location = resolve_type_definition_location(params, stages: stages)
29
- result_state = location ? 'hit' : 'miss'
30
- location
31
- rescue StandardError => e
32
- result_state = 'error'
33
- warn "Error in typeDefinition handler: #{e.message}"
34
- nil
35
- ensure
36
- log_request_stage_breakdown('textDocument/typeDefinition', total_start, uri: uri, stages: stages, summary: "result=#{result_state}")
37
- end
37
+ def handle_implementation(params)
38
+ stages = new_perf_stages
39
+ total_start = stages ? monotonic_time : nil
40
+ uri = params.dig('textDocument', 'uri')
41
+ result_state = 'miss'
42
+
43
+ locations = resolve_implementation_locations(params, stages: stages)
44
+ result_state = locations.empty? ? 'miss' : 'hit'
45
+ locations
46
+ rescue StandardError => e
47
+ result_state = 'error'
48
+ warn "Error in implementation handler: #{e.message}"
49
+ []
50
+ ensure
51
+ log_request_stage_breakdown('textDocument/implementation', total_start, uri: uri, stages: stages, summary: "result=#{result_state}")
52
+ end
38
53
 
39
- def handle_implementation(params)
40
- stages = new_perf_stages
41
- total_start = stages ? monotonic_time : nil
42
- uri = params.dig('textDocument', 'uri')
43
- result_state = 'miss'
44
-
45
- locations = resolve_implementation_locations(params, stages: stages)
46
- result_state = locations.empty? ? 'miss' : 'hit'
47
- locations
48
- rescue StandardError => e
49
- result_state = 'error'
50
- warn "Error in implementation handler: #{e.message}"
51
- []
52
- ensure
53
- log_request_stage_breakdown('textDocument/implementation', total_start, uri: uri, stages: stages, summary: "result=#{result_state}")
54
- end
54
+ def handle_definition_request(method_name, params, error_label:)
55
+ stages = new_perf_stages
56
+ total_start = stages ? monotonic_time : nil
57
+ uri = params.dig('textDocument', 'uri')
58
+ result_state = 'miss'
59
+
60
+ location = resolve_definition_location(params, stages: stages)
61
+ result_state = location ? 'hit' : 'miss'
62
+ location
63
+ rescue StandardError => e
64
+ result_state = 'error'
65
+ warn "Error in #{error_label} handler: #{e.message}"
66
+ nil
67
+ ensure
68
+ log_request_stage_breakdown(method_name, total_start, uri: uri, stages: stages, summary: "result=#{result_state}")
69
+ end
55
70
 
56
- def handle_definition_request(method_name, params, error_label:)
57
- stages = new_perf_stages
58
- total_start = stages ? monotonic_time : nil
59
- uri = params.dig('textDocument', 'uri')
60
- result_state = 'miss'
61
-
62
- location = resolve_definition_location(params, stages: stages)
63
- result_state = location ? 'hit' : 'miss'
64
- location
65
- rescue StandardError => e
66
- result_state = 'error'
67
- warn "Error in #{error_label} handler: #{e.message}"
68
- nil
69
- ensure
70
- log_request_stage_breakdown(method_name, total_start, uri: uri, stages: stages, summary: "result=#{result_state}")
71
- end
71
+ def resolve_definition_location(params, stages: nil)
72
+ uri = params['textDocument']['uri']
73
+ lsp_line = params['position']['line']
74
+ lsp_char = params['position']['character']
75
+
76
+ context = measure_perf_stage(stages, 'context') { token_context_at(uri, lsp_line, lsp_char) }
77
+ token = context&.fetch(:token, nil)
78
+ return nil unless token&.type == :identifier
79
+
80
+ tokens = context[:tokens]
81
+ token_index = context[:token_index]
82
+ return nil if token_index && module_declaration_info_at(tokens, token_index)
83
+
84
+ if token_index && named_argument_label_token?(tokens, token_index)
85
+ location = named_argument_definition_location(uri, token.lexeme, tokens, token_index, stages:)
86
+ return location if location
87
+ end
72
88
 
73
- def resolve_definition_location(params, stages: nil)
74
- uri = params['textDocument']['uri']
75
- lsp_line = params['position']['line']
76
- lsp_char = params['position']['character']
77
-
78
- context = measure_perf_stage(stages, 'context') { token_context_at(uri, lsp_line, lsp_char) }
79
- token = context&.fetch(:token, nil)
80
- return nil unless token&.type == :identifier
81
-
82
- tokens = context[:tokens]
83
- token_index = context[:token_index]
84
- return nil if token_index && module_declaration_info_at(tokens, token_index)
85
-
86
- if token_index && named_argument_label_token?(tokens, token_index)
87
- location = named_argument_definition_location(uri, token.lexeme, tokens, token_index, stages:)
88
- return location if location
89
- end
90
-
91
- import_info = token_index ? measure_perf_stage(stages, 'import_path') { import_path_info_at(tokens, token_index) } : nil
92
- if import_info
93
- return module_definition_location(uri, import_info[:module_name])
94
- end
95
-
96
- facts = measure_perf_stage(stages, 'facts') { @workspace.get_facts(uri) }
97
- if facts
98
- facts_location = measure_perf_stage(stages, 'facts_lookup') do
99
- location = nil
100
- dot_receiver = @workspace.find_dot_receiver(uri, lsp_line, lsp_char)
101
- dot_receiver_path = @workspace.find_dot_receiver_path(uri, lsp_line, lsp_char)
102
- imported_module_name = dot_receiver ? (facts.imports[dot_receiver]&.name || imported_module_name_from_ast(uri, dot_receiver)) : nil
103
-
104
- if token_index && (field_location = resolve_field_member_definition_location(uri, facts, tokens, token_index))
105
- location = field_location
106
- elsif token_index && (enum_member_location = resolve_enum_member_definition_location(uri, facts, tokens, token_index))
107
- location = enum_member_location
108
- elsif token_index && imported_module_name && module_member_access_info(tokens, token_index)
109
- location = module_member_definition_location(uri, imported_module_name, token.lexeme)
110
- location ||= module_definition_location(uri, imported_module_name)
111
- elsif (type_method = resolve_static_type_receiver_method(facts, dot_receiver, dot_receiver_path, token.lexeme))
112
- location = module_member_binding_location(uri, type_method[:module_name], token.lexeme, type_method[:binding]) ||
113
- module_member_definition_location(uri, type_method[:module_name], token.lexeme) ||
114
- module_definition_location(uri, type_method[:module_name])
115
- elsif (binding = method_binding_at_token(facts, token))
116
- location = module_member_binding_location(uri, facts.module_name, token.lexeme, binding)
117
- location ||= module_member_definition_location(uri, facts.module_name, token.lexeme)
118
- elsif (binding = facts.functions[token.lexeme])
119
- location = module_member_binding_location(uri, facts.module_name, token.lexeme, binding)
120
- location ||= module_member_definition_location(uri, facts.module_name, token.lexeme)
121
- elsif facts.interfaces[token.lexeme]
122
- location = module_member_definition_location(uri, facts.module_name, token.lexeme)
123
- elsif facts.types.key?(token.lexeme)
124
- location = module_member_definition_location(uri, facts.module_name, token.lexeme)
125
- elsif (binding = facts.values[token.lexeme])
126
- location = module_member_binding_location(uri, facts.module_name, token.lexeme, binding)
127
- location ||= module_member_definition_location(uri, facts.module_name, token.lexeme)
128
- else
129
- if imported_module_name
130
- location = module_member_definition_location(uri, imported_module_name, token.lexeme) || module_definition_location(uri, imported_module_name)
131
- elsif facts.imports.key?(token.lexeme)
132
- module_name = facts.imports.fetch(token.lexeme).name
133
- location = module_member_definition_location(uri, module_name, token.lexeme)
134
- location ||= module_definition_location(uri, module_name)
135
- elsif (module_name = imported_module_name_from_ast(uri, token.lexeme))
136
- location = module_definition_location(uri, module_name)
89
+ import_info = token_index ? measure_perf_stage(stages, 'import_path') { import_path_info_at(tokens, token_index) } : nil
90
+ if import_info
91
+ return module_definition_location(uri, import_info[:module_name])
92
+ end
93
+
94
+ facts = measure_perf_stage(stages, 'facts') { @workspace.get_facts(uri) }
95
+ if facts
96
+ facts_location = measure_perf_stage(stages, 'facts_lookup') do
97
+ location = nil
98
+ dot_receiver = @workspace.find_dot_receiver(uri, lsp_line, lsp_char)
99
+ dot_receiver_path = @workspace.find_dot_receiver_path(uri, lsp_line, lsp_char)
100
+ imported_module_name = dot_receiver ? (facts.imports[dot_receiver]&.name || imported_module_name_from_ast(uri, dot_receiver)) : nil
101
+
102
+ if token_index && (field_location = resolve_field_member_definition_location(uri, facts, tokens, token_index))
103
+ location = field_location
104
+ elsif token_index && (enum_member_location = resolve_enum_member_definition_location(uri, facts, tokens, token_index))
105
+ location = enum_member_location
106
+ elsif token_index && imported_module_name && module_member_access_info(tokens, token_index)
107
+ location = module_member_definition_location(uri, imported_module_name, token.lexeme)
108
+ location ||= module_definition_location(uri, imported_module_name)
109
+ elsif (type_method = resolve_static_type_receiver_method(facts, dot_receiver, dot_receiver_path, token.lexeme))
110
+ location = module_member_binding_location(uri, type_method[:module_name], token.lexeme, type_method[:binding]) ||
111
+ module_member_definition_location(uri, type_method[:module_name], token.lexeme) ||
112
+ module_definition_location(uri, type_method[:module_name])
113
+ elsif (binding = method_binding_at_token(facts, token))
114
+ location = module_member_binding_location(uri, facts.module_name, token.lexeme, binding)
115
+ location ||= module_member_definition_location(uri, facts.module_name, token.lexeme)
116
+ elsif (binding = facts.functions[token.lexeme])
117
+ location = module_member_binding_location(uri, facts.module_name, token.lexeme, binding)
118
+ location ||= module_member_definition_location(uri, facts.module_name, token.lexeme)
119
+ elsif facts.interfaces[token.lexeme]
120
+ location = module_member_definition_location(uri, facts.module_name, token.lexeme)
121
+ elsif facts.types.key?(token.lexeme)
122
+ location = module_member_definition_location(uri, facts.module_name, token.lexeme)
123
+ elsif (binding = facts.values[token.lexeme])
124
+ location = module_member_binding_location(uri, facts.module_name, token.lexeme, binding)
125
+ location ||= module_member_definition_location(uri, facts.module_name, token.lexeme)
126
+ else
127
+ if imported_module_name
128
+ location = module_member_definition_location(uri, imported_module_name, token.lexeme) || module_definition_location(uri, imported_module_name)
129
+ elsif facts.imports.key?(token.lexeme)
130
+ module_name = facts.imports.fetch(token.lexeme).name
131
+ location = module_member_definition_location(uri, module_name, token.lexeme)
132
+ location ||= module_definition_location(uri, module_name)
133
+ elsif (module_name = imported_module_name_from_ast(uri, token.lexeme))
134
+ location = module_definition_location(uri, module_name)
135
+ end
137
136
  end
137
+
138
+ location
138
139
  end
139
140
 
140
- location
141
+ return facts_location if facts_location
141
142
  end
142
143
 
143
- return facts_location if facts_location
144
- end
145
-
146
- return nil if token_index && is_builtin_name?(token.lexeme, tokens, token_index)
144
+ return nil if token_index && is_builtin_name?(token.lexeme, tokens, token_index)
147
145
 
148
- if facts && token_index && !facts_location
149
- local_location = measure_perf_stage(stages, 'local_binding') do
150
- name = token.lexeme
151
- line = lsp_line + 1
152
- char = lsp_char + 1
153
- local_binding = resolve_local_hover_binding(facts, name, line, char)
154
- next nil unless local_binding
146
+ if facts && token_index && !facts_location
147
+ local_location = measure_perf_stage(stages, 'local_binding') do
148
+ name = token.lexeme
149
+ line = lsp_line + 1
150
+ char = lsp_char + 1
151
+ local_binding = resolve_local_hover_binding(facts, name, line, char)
152
+ next nil unless local_binding
155
153
 
156
- ast_node = local_binding.respond_to?(:ast) ? local_binding.ast : nil
157
- if ast_node&.line && ast_node.respond_to?(:column) && ast_node.column
158
- {
159
- uri: uri,
160
- range: {
161
- start: { line: ast_node.line - 1, character: ast_node.column - 1 },
162
- end: { line: ast_node.line - 1, character: ast_node.column - 1 + name.length }
163
- }
164
- }
165
- else
166
- declaration_node = find_local_declaration_ast_node(uri, name, line)
167
- if declaration_node
154
+ ast_node = local_binding.respond_to?(:ast) ? local_binding.ast : nil
155
+ if ast_node&.line && ast_node.column
168
156
  {
169
157
  uri: uri,
170
158
  range: {
171
- start: { line: declaration_node.line - 1, character: declaration_node.column - 1 },
172
- end: { line: declaration_node.line - 1, character: declaration_node.column - 1 + name.length }
159
+ start: { line: ast_node.line - 1, character: ast_node.column - 1 },
160
+ end: { line: ast_node.line - 1, character: ast_node.column - 1 + name.length }
173
161
  }
174
162
  }
163
+ else
164
+ declaration_node = find_local_declaration_ast_node(uri, name, line)
165
+ if declaration_node
166
+ {
167
+ uri: uri,
168
+ range: {
169
+ start: { line: declaration_node.line - 1, character: declaration_node.column - 1 },
170
+ end: { line: declaration_node.line - 1, character: declaration_node.column - 1 + name.length }
171
+ }
172
+ }
173
+ end
175
174
  end
176
175
  end
176
+ return local_location if local_location
177
177
  end
178
- return local_location if local_location
179
- end
180
178
 
181
- found = measure_perf_stage(stages, 'global_lookup') do
182
- @workspace.find_definition_token_global(
183
- token.lexeme,
184
- preferred_uri: uri,
185
- before_line: lsp_line + 1,
186
- before_char: lsp_char + 1,
187
- )
188
- end
189
- return nil unless found
179
+ found = measure_perf_stage(stages, 'global_lookup') do
180
+ @workspace.find_definition_token_global(
181
+ token.lexeme,
182
+ preferred_uri: uri,
183
+ before_line: lsp_line + 1,
184
+ before_char: lsp_char + 1,
185
+ )
186
+ end
187
+ return nil unless found
190
188
 
191
- {
192
- uri: found[:uri],
193
- range: token_to_range(found[:token])
194
- }
195
- end
189
+ {
190
+ uri: found[:uri],
191
+ range: token_to_range(found[:token])
192
+ }
193
+ end
196
194
 
197
- def find_local_declaration_ast_node(uri, name, before_line)
198
- ast = @workspace.get_ast(uri)
199
- return nil unless ast
195
+ def find_local_declaration_ast_node(uri, name, before_line)
196
+ ast = @workspace.get_ast(uri)
197
+ return nil unless ast
200
198
 
201
- result = nil
202
- find_local_decl_node(ast, name, before_line) { |node| result = node; true }
203
- result
204
- end
199
+ result = nil
200
+ find_local_decl_node(ast, name, before_line) { |node| result = node; true }
201
+ result
202
+ end
205
203
 
206
- def find_local_decl_node(node, name, before_line, &block)
207
- return false if node.nil?
204
+ def find_local_decl_node(node, name, before_line, &block)
205
+ return false if node.nil?
208
206
 
209
- if (node.is_a?(AST::LocalDecl) || node.is_a?(AST::ForBinding)) && node.name == name && node.line && node.line < before_line
210
- return true if yield node
211
- end
207
+ if (node.is_a?(AST::LocalDecl) || node.is_a?(AST::ForBinding)) && node.name == name && node.line && node.line < before_line
208
+ return true if yield node
209
+ end
212
210
 
213
- if node.is_a?(Array)
214
- node.each { |item| return true if find_local_decl_node(item, name, before_line, &block) }
215
- return false
216
- end
211
+ if node.is_a?(Array)
212
+ node.each { |item| return true if find_local_decl_node(item, name, before_line, &block) }
213
+ return false
214
+ end
217
215
 
218
- return false unless node.class.name&.start_with?("MilkTea::AST::")
216
+ return false unless node.class.name&.start_with?("MilkTea::AST::")
219
217
 
220
- if node.respond_to?(:members)
221
- node.members.each do |member|
222
- next unless member.is_a?(Symbol)
223
- return true if find_local_decl_node(node.public_send(member), name, before_line, &block)
218
+ if node.respond_to?(:members)
219
+ node.members.each do |member|
220
+ next unless member.is_a?(Symbol)
221
+ return true if find_local_decl_node(node.public_send(member), name, before_line, &block)
222
+ end
224
223
  end
225
- end
226
224
 
227
- false
228
- end
225
+ false
226
+ end
229
227
 
230
- def resolve_field_member_definition_location(current_uri, facts, tokens, token_index)
231
- chain = member_access_chain_at(tokens, token_index)
232
- return nil unless chain
228
+ def resolve_field_member_definition_location(current_uri, facts, tokens, token_index)
229
+ chain = member_access_chain_at(tokens, token_index)
230
+ return nil unless chain
233
231
 
234
- hovered_segment = chain[:segments].find { |segment| segment[:token_index] == token_index }
235
- return nil unless hovered_segment && hovered_segment[:position].positive?
232
+ hovered_segment = chain[:segments].find { |segment| segment[:token_index] == token_index }
233
+ return nil unless hovered_segment && hovered_segment[:position].positive?
236
234
 
237
- current_type = resolve_dot_receiver_value_type(
238
- facts,
239
- chain[:segments].first[:name],
240
- chain[:line],
241
- chain[:char],
242
- )
243
- unless current_type
244
- first_name = chain[:segments].first[:name]
245
- current_type = facts.types[first_name]
246
- end
247
- return nil unless current_type
235
+ current_type = resolve_dot_receiver_value_type(
236
+ facts,
237
+ chain[:segments].first[:name],
238
+ chain[:line],
239
+ chain[:char],
240
+ )
241
+ unless current_type
242
+ first_name = chain[:segments].first[:name]
243
+ current_type = facts.types[first_name]
244
+ end
245
+ return nil unless current_type
248
246
 
249
- chain[:segments][1..hovered_segment[:position]].each do |segment|
250
- field_receiver_type = project_field_receiver_type_for_completion(current_type, facts)
251
- if field_receiver_type.respond_to?(:field) && (field_type = field_receiver_type.field(segment[:name]))
252
- return field_definition_location(current_uri, field_receiver_type, segment[:name]) if segment[:token_index] == token_index
247
+ chain[:segments][1..hovered_segment[:position]].each do |segment|
248
+ field_receiver_type = project_field_receiver_type_for_completion(current_type, facts)
249
+ if field_receiver_type.respond_to?(:field) && (field_type = field_receiver_type.field(segment[:name]))
250
+ return field_definition_location(current_uri, field_receiver_type, segment[:name]) if segment[:token_index] == token_index
253
251
 
254
- current_type = field_type
255
- next
256
- end
252
+ current_type = field_type
253
+ next
254
+ end
257
255
 
258
- if current_type.respond_to?(:nested_types) && (nested = current_type.nested_types[segment[:name]])
259
- if segment[:token_index] == token_index
260
- decl = nested.respond_to?(:ast_declaration) ? nested.ast_declaration : nil
261
- if decl&.line && decl.respond_to?(:column) && decl.column
262
- return {
263
- uri: current_uri,
264
- range: {
265
- start: { line: decl.line - 1, character: decl.column - 1 },
266
- end: { line: decl.line - 1, character: decl.column - 1 + segment[:name].length },
267
- },
268
- }
256
+ if current_type.respond_to?(:nested_types) && (nested = current_type.nested_types[segment[:name]])
257
+ if segment[:token_index] == token_index
258
+ decl = nested.respond_to?(:ast_declaration) ? nested.ast_declaration : nil
259
+ if decl&.line && decl.column
260
+ return {
261
+ uri: current_uri,
262
+ range: {
263
+ start: { line: decl.line - 1, character: decl.column - 1 },
264
+ end: { line: decl.line - 1, character: decl.column - 1 + segment[:name].length },
265
+ },
266
+ }
267
+ end
268
+ return nil
269
269
  end
270
- return nil
270
+ current_type = nested
271
+ next
271
272
  end
272
- current_type = nested
273
- next
274
- end
275
273
 
276
- if segment[:token_index] == token_index
277
- method_receiver_type = project_method_receiver_type_for_completion(current_type)
278
- method_info = member_method_info_for_receiver_type(facts, method_receiver_type, segment[:name])
279
- return nil unless method_info
274
+ if segment[:token_index] == token_index
275
+ method_receiver_type = project_method_receiver_type_for_completion(current_type)
276
+ method_info = member_method_info_for_receiver_type(facts, method_receiver_type, segment[:name])
277
+ return nil unless method_info
280
278
 
281
- return module_member_binding_location(current_uri, method_info[:module_name], segment[:name], method_info[:binding]) ||
282
- module_member_definition_location(current_uri, method_info[:module_name], segment[:name])
283
- end
279
+ return module_member_binding_location(current_uri, method_info[:module_name], segment[:name], method_info[:binding]) ||
280
+ module_member_definition_location(current_uri, method_info[:module_name], segment[:name])
281
+ end
284
282
 
285
- break
283
+ break
284
+ end
285
+
286
+ nil
286
287
  end
287
288
 
288
- nil
289
- end
289
+ def resolve_type_definition_location(params, stages: nil)
290
+ uri = params['textDocument']['uri']
291
+ lsp_line = params['position']['line']
292
+ lsp_char = params['position']['character']
290
293
 
291
- def resolve_type_definition_location(params, stages: nil)
292
- uri = params['textDocument']['uri']
293
- lsp_line = params['position']['line']
294
- lsp_char = params['position']['character']
294
+ context = measure_perf_stage(stages, 'context') { token_context_at(uri, lsp_line, lsp_char) }
295
+ token = context&.fetch(:token, nil)
296
+ return nil unless token&.type == :identifier
295
297
 
296
- context = measure_perf_stage(stages, 'context') { token_context_at(uri, lsp_line, lsp_char) }
297
- token = context&.fetch(:token, nil)
298
- return nil unless token&.type == :identifier
298
+ name = token.lexeme
299
+ tokens = context[:tokens]
300
+ token_index = context[:token_index]
299
301
 
300
- name = token.lexeme
301
- tokens = context[:tokens]
302
- token_index = context[:token_index]
302
+ import_info = token_index ? measure_perf_stage(stages, 'import_path') { import_path_info_at(tokens, token_index) } : nil
303
+ if import_info
304
+ return module_definition_location(uri, import_info[:module_name])
305
+ end
303
306
 
304
- import_info = token_index ? measure_perf_stage(stages, 'import_path') { import_path_info_at(tokens, token_index) } : nil
305
- if import_info
306
- return module_definition_location(uri, import_info[:module_name])
307
- end
307
+ facts = measure_perf_stage(stages, 'facts') { @workspace.get_facts(uri) }
308
+ return nil unless facts
308
309
 
309
- facts = measure_perf_stage(stages, 'facts') { @workspace.get_facts(uri) }
310
- return nil unless facts
310
+ dot_receiver = @workspace.find_dot_receiver(uri, lsp_line, lsp_char)
311
+ imported_module_name = dot_receiver ? (facts.imports[dot_receiver]&.name || imported_module_name_from_ast(uri, dot_receiver)) : nil
311
312
 
312
- dot_receiver = @workspace.find_dot_receiver(uri, lsp_line, lsp_char)
313
- imported_module_name = dot_receiver ? (facts.imports[dot_receiver]&.name || imported_module_name_from_ast(uri, dot_receiver)) : nil
313
+ if facts.types.key?(name) || facts.interfaces.key?(name)
314
+ return module_member_definition_location(uri, facts.module_name, name)
315
+ end
314
316
 
315
- if facts.types.key?(name) || facts.interfaces.key?(name)
316
- return module_member_definition_location(uri, facts.module_name, name)
317
- end
317
+ if token_index && imported_module_name && module_member_access_info(tokens, token_index)
318
+ return module_member_definition_location(uri, imported_module_name, name) ||
319
+ module_definition_location(uri, imported_module_name)
320
+ end
318
321
 
319
- if token_index && imported_module_name && module_member_access_info(tokens, token_index)
320
- return module_member_definition_location(uri, imported_module_name, name) ||
321
- module_definition_location(uri, imported_module_name)
322
- end
322
+ if imported_module_name && (facts.types.key?(imported_module_name) || facts.interfaces.key?(imported_module_name))
323
+ return module_member_definition_location(uri, imported_module_name, name) ||
324
+ module_definition_location(uri, imported_module_name)
325
+ end
323
326
 
324
- if imported_module_name && (facts.types.key?(imported_module_name) || facts.interfaces.key?(imported_module_name))
325
- return module_member_definition_location(uri, imported_module_name, name) ||
326
- module_definition_location(uri, imported_module_name)
327
+ handle_definition_request('textDocument/typeDefinition', params, error_label: 'typeDefinition')
327
328
  end
328
329
 
329
- handle_definition_request('textDocument/typeDefinition', params, error_label: 'typeDefinition')
330
- end
330
+ def resolve_implementation_locations(params, stages: nil)
331
+ uri = params['textDocument']['uri']
332
+ lsp_line = params['position']['line']
333
+ lsp_char = params['position']['character']
331
334
 
332
- def resolve_implementation_locations(params, stages: nil)
333
- uri = params['textDocument']['uri']
334
- lsp_line = params['position']['line']
335
- lsp_char = params['position']['character']
335
+ token = measure_perf_stage(stages, 'token') { @workspace.find_token_at(uri, lsp_line, lsp_char) }
336
+ return [] unless token&.type == :identifier
336
337
 
337
- token = measure_perf_stage(stages, 'token') { @workspace.find_token_at(uri, lsp_line, lsp_char) }
338
- return [] unless token&.type == :identifier
338
+ facts = measure_perf_stage(stages, 'facts') { @workspace.get_facts(uri) }
339
+ return [] unless facts
339
340
 
340
- facts = measure_perf_stage(stages, 'facts') { @workspace.get_facts(uri) }
341
- return [] unless facts
341
+ target = measure_perf_stage(stages, 'target_lookup') { resolve_interface_method_target_at_token(facts, token) }
342
+ if target
343
+ return measure_perf_stage(stages, 'implementation_lookup') do
344
+ interface_method_implementation_locations(target[:interface], target[:method])
345
+ end
346
+ end
342
347
 
343
- target = measure_perf_stage(stages, 'target_lookup') { resolve_interface_method_target_at_token(facts, token) }
344
- if target
345
- return measure_perf_stage(stages, 'implementation_lookup') do
346
- interface_method_implementation_locations(target[:interface], target[:method])
348
+ interface_binding = measure_perf_stage(stages, 'binding_lookup') do
349
+ resolve_interface_binding_at_position(uri, facts, token, lsp_line, lsp_char)
347
350
  end
348
- end
351
+ return [] unless interface_binding
349
352
 
350
- interface_binding = measure_perf_stage(stages, 'binding_lookup') do
351
- resolve_interface_binding_at_position(uri, facts, token, lsp_line, lsp_char)
353
+ measure_perf_stage(stages, 'implementation_lookup') { interface_implementation_locations(interface_binding) }
352
354
  end
353
- return [] unless interface_binding
354
355
 
355
- measure_perf_stage(stages, 'implementation_lookup') { interface_implementation_locations(interface_binding) }
356
- end
357
-
358
- def module_definition_location(current_uri, module_name)
359
- path = module_path_for_name(current_uri, module_name)
360
- return nil unless path
356
+ def module_definition_location(current_uri, module_name)
357
+ path = module_path_for_name(current_uri, module_name)
358
+ return nil unless path
361
359
 
362
- {
363
- uri: path_to_uri(File.expand_path(path)),
364
- range: {
365
- start: { line: 0, character: 0 },
366
- end: { line: 0, character: 0 }
360
+ {
361
+ uri: path_to_uri(File.expand_path(path)),
362
+ range: {
363
+ start: { line: 0, character: 0 },
364
+ end: { line: 0, character: 0 }
365
+ }
367
366
  }
368
- }
369
- end
367
+ end
370
368
 
371
- def module_member_definition_location(current_uri, module_name, member_name)
372
- path = module_path_for_name(current_uri, module_name)
373
- return nil unless path
369
+ def module_member_definition_location(current_uri, module_name, member_name)
370
+ path = module_path_for_name(current_uri, module_name)
371
+ return nil unless path
374
372
 
375
- token = find_definition_token_in_file(path, member_name)
376
- return nil unless token
373
+ token = find_definition_token_in_file(path, member_name)
374
+ return nil unless token
377
375
 
378
- {
379
- uri: path_to_uri(File.expand_path(path)),
380
- range: token_to_range(token)
381
- }
382
- end
376
+ {
377
+ uri: path_to_uri(File.expand_path(path)),
378
+ range: token_to_range(token)
379
+ }
380
+ end
383
381
 
384
- def field_definition_location(current_uri, receiver_type, field_name)
385
- owner_type = field_owner_type(receiver_type)
386
- return nil unless owner_type&.respond_to?(:name)
382
+ def field_definition_location(current_uri, receiver_type, field_name)
383
+ owner_type = field_owner_type(receiver_type)
384
+ return nil unless owner_type&.respond_to?(:name)
387
385
 
388
- path = module_path_for_name(current_uri, owner_type.module_name)
389
- return nil unless path
386
+ path = module_path_for_name(current_uri, owner_type.module_name)
387
+ return nil unless path
390
388
 
391
- token = find_field_token_in_type(path, owner_type.name, field_name, current_uri: current_uri)
392
- return nil unless token
389
+ token = find_field_token_in_type(path, owner_type.name, field_name, current_uri: current_uri)
390
+ return nil unless token
393
391
 
394
- {
395
- uri: path_to_uri(File.expand_path(path)),
396
- range: token_to_range(token)
397
- }
398
- end
392
+ {
393
+ uri: path_to_uri(File.expand_path(path)),
394
+ range: token_to_range(token)
395
+ }
396
+ end
399
397
 
400
- def enum_member_definition_location(current_uri, module_name, type_name, member_name)
401
- path = module_path_for_name(current_uri, module_name)
402
- return nil unless path
398
+ def enum_member_definition_location(current_uri, module_name, type_name, member_name)
399
+ path = module_path_for_name(current_uri, module_name)
400
+ return nil unless path
403
401
 
404
- token = find_enum_member_token_in_file(path, type_name, member_name)
405
- return nil unless token
402
+ token = find_enum_member_token_in_file(path, type_name, member_name)
403
+ return nil unless token
406
404
 
407
- {
408
- uri: path_to_uri(File.expand_path(path)),
409
- range: token_to_range(token)
410
- }
411
- end
405
+ {
406
+ uri: path_to_uri(File.expand_path(path)),
407
+ range: token_to_range(token)
408
+ }
409
+ end
412
410
 
413
- def module_member_binding_location(current_uri, module_name, member_name, binding)
414
- path = module_path_for_name(current_uri, module_name)
415
- return nil unless path
411
+ def module_member_binding_location(current_uri, module_name, member_name, binding)
412
+ path = module_path_for_name(current_uri, module_name)
413
+ return nil unless path
416
414
 
417
- ast = binding.respond_to?(:ast) ? binding.ast : nil
418
- if ast&.line && ast.respond_to?(:column) && ast.column
419
- start_line = ast.line - 1
420
- start_char = ast.column - 1
415
+ ast = binding.respond_to?(:ast) ? binding.ast : nil
416
+ if ast&.line && ast.column
417
+ start_line = ast.line - 1
418
+ start_char = ast.column - 1
421
419
 
422
- return {
423
- uri: path_to_uri(File.expand_path(path)),
424
- range: {
425
- start: { line: start_line, character: start_char },
426
- end: { line: start_line, character: start_char + member_name.length }
420
+ return {
421
+ uri: path_to_uri(File.expand_path(path)),
422
+ range: {
423
+ start: { line: start_line, character: start_char },
424
+ end: { line: start_line, character: start_char + member_name.length }
425
+ }
427
426
  }
428
- }
429
- end
427
+ end
430
428
 
431
- module_member_definition_location(current_uri, module_name, member_name)
432
- end
429
+ module_member_definition_location(current_uri, module_name, member_name)
430
+ end
433
431
 
434
- def module_path_for_name(current_uri, module_name)
435
- current_path = uri_to_path(current_uri)
436
- return nil unless current_path
437
- return current_path if module_name.nil? || module_name.empty?
432
+ def module_path_for_name(current_uri, module_name)
433
+ current_path = uri_to_path(current_uri)
434
+ return nil unless current_path
435
+ return current_path if module_name.nil? || module_name.empty?
438
436
 
439
- current_facts = @workspace.get_facts(current_uri)
440
- return current_path if current_facts&.module_name == module_name
437
+ current_facts = @workspace.get_facts(current_uri)
438
+ return current_path if current_facts&.module_name == module_name
441
439
 
442
- resolution = DependencyResolution.resolve(current_path, mode: @workspace.dependency_resolution_mode)
443
- module_roots = if resolution.ok?
444
- MilkTea::ModuleRoots.roots_for_path(current_path, locked: resolution.locked)
445
- else
446
- MilkTea::ModuleRoots.roots_for_path(current_path)
447
- end
448
- relative_path = File.join(*module_name.split('.')) + '.mt'
449
- resolved_path = module_roots.lazy.map { |root| File.join(root, relative_path) }.find { |candidate| File.file?(candidate) }
450
- return resolved_path if resolved_path
440
+ resolution = DependencyResolution.resolve(current_path, mode: @workspace.dependency_resolution_mode)
441
+ module_roots = if resolution.ok?
442
+ MilkTea::ModuleRoots.roots_for_path(current_path, locked: resolution.locked)
443
+ else
444
+ MilkTea::ModuleRoots.roots_for_path(current_path)
445
+ end
446
+ relative_path = File.join(*module_name.split('.')) + '.mt'
447
+ resolved_path = module_roots.lazy.map { |root| File.join(root, relative_path) }.find { |candidate| File.file?(candidate) }
448
+ return resolved_path if resolved_path
451
449
 
452
- workspace_root = @root_uri ? uri_to_path(@root_uri) : nil
453
- return nil unless workspace_root && File.directory?(workspace_root)
450
+ workspace_root = @root_uri ? uri_to_path(@root_uri) : nil
451
+ return nil unless workspace_root && File.directory?(workspace_root)
454
452
 
455
- workspace_candidate = File.join(workspace_root, relative_path)
456
- return workspace_candidate if File.file?(workspace_candidate)
453
+ workspace_candidate = File.join(workspace_root, relative_path)
454
+ return workspace_candidate if File.file?(workspace_candidate)
457
455
 
458
- nil
459
- rescue PackageLockError
460
- module_roots = MilkTea::ModuleRoots.roots_for_path(current_path)
461
- relative_path = File.join(*module_name.split('.')) + '.mt'
462
- resolved_path = module_roots.lazy.map { |root| File.join(root, relative_path) }.find { |candidate| File.file?(candidate) }
463
- return resolved_path if resolved_path
456
+ nil
457
+ rescue PackageLockError
458
+ module_roots = MilkTea::ModuleRoots.roots_for_path(current_path)
459
+ relative_path = File.join(*module_name.split('.')) + '.mt'
460
+ resolved_path = module_roots.lazy.map { |root| File.join(root, relative_path) }.find { |candidate| File.file?(candidate) }
461
+ return resolved_path if resolved_path
464
462
 
465
- workspace_root = @root_uri ? uri_to_path(@root_uri) : nil
466
- return nil unless workspace_root && File.directory?(workspace_root)
463
+ workspace_root = @root_uri ? uri_to_path(@root_uri) : nil
464
+ return nil unless workspace_root && File.directory?(workspace_root)
467
465
 
468
- workspace_candidate = File.join(workspace_root, relative_path)
469
- return workspace_candidate if File.file?(workspace_candidate)
466
+ workspace_candidate = File.join(workspace_root, relative_path)
467
+ return workspace_candidate if File.file?(workspace_candidate)
470
468
 
471
- nil
472
- end
469
+ nil
470
+ end
473
471
 
474
- def imported_module_name_from_ast(uri, alias_name)
475
- return nil if alias_name.nil? || alias_name.empty?
472
+ def imported_module_name_from_ast(uri, alias_name)
473
+ return nil if alias_name.nil? || alias_name.empty?
476
474
 
477
- ast = @workspace.get_ast(uri)
478
- return nil unless ast
475
+ ast = @workspace.get_ast(uri)
476
+ return nil unless ast
479
477
 
480
- import = ast.imports.find do |entry|
481
- resolved_alias = entry.alias_name || entry.path.parts.last
482
- resolved_alias == alias_name
478
+ import = ast.imports.find do |entry|
479
+ resolved_alias = entry.alias_name || entry.path.parts.last
480
+ resolved_alias == alias_name
481
+ end
482
+ import&.path&.to_s
483
+ rescue StandardError
484
+ nil
483
485
  end
484
- import&.path&.to_s
485
- rescue StandardError
486
- nil
487
- end
488
486
 
489
- def find_definition_token_in_file(path, name)
490
- tokens = definition_file_tokens(path)
487
+ def find_definition_token_in_file(path, name)
488
+ tokens = definition_file_tokens(path)
491
489
 
492
- tokens.each_cons(2) do |kw_tok, id_tok|
493
- next unless MilkTea::LSP::Workspace::DEFINITION_KEYWORDS.include?(kw_tok.type)
494
- next unless id_tok.type == :identifier && id_tok.lexeme == name
490
+ tokens.each_cons(2) do |kw_tok, id_tok|
491
+ next unless MilkTea::LSP::Workspace::DEFINITION_KEYWORDS.include?(kw_tok.type)
492
+ next unless id_tok.type == :identifier && id_tok.lexeme == name
495
493
 
496
- return id_tok
494
+ return id_tok
495
+ end
496
+
497
+ nil
498
+ rescue StandardError
499
+ nil
497
500
  end
498
501
 
499
- nil
500
- rescue StandardError
501
- nil
502
- end
502
+ def find_field_token_in_type(path, type_name, field_name, current_uri: nil)
503
+ tokens = definition_lookup_tokens(path, current_uri: current_uri)
503
504
 
504
- def find_field_token_in_type(path, type_name, field_name, current_uri: nil)
505
- tokens = definition_lookup_tokens(path, current_uri: current_uri)
505
+ tokens.each_with_index do |token, index|
506
+ next unless [:struct, :union].include?(token.type)
506
507
 
507
- tokens.each_with_index do |token, index|
508
- next unless [:struct, :union].include?(token.type)
508
+ name_index = next_non_trivia_token_index(tokens, index + 1)
509
+ next unless name_index && tokens[name_index].type == :identifier && tokens[name_index].lexeme == type_name
509
510
 
510
- name_index = next_non_trivia_token_index(tokens, index + 1)
511
- next unless name_index && tokens[name_index].type == :identifier && tokens[name_index].lexeme == type_name
511
+ field_token = find_field_token_in_body(tokens, index, field_name)
512
+ return field_token if field_token
513
+ end
512
514
 
513
- field_token = find_field_token_in_body(tokens, index, field_name)
514
- return field_token if field_token
515
+ nil
516
+ rescue StandardError
517
+ nil
515
518
  end
516
519
 
517
- nil
518
- rescue StandardError
519
- nil
520
- end
520
+ def find_field_token_in_body(tokens, header_index, field_name)
521
+ header = tokens[header_index]
522
+ i = header_index + 1
521
523
 
522
- def find_field_token_in_body(tokens, header_index, field_name)
523
- header = tokens[header_index]
524
- i = header_index + 1
524
+ while i < tokens.length
525
+ token = tokens[i]
525
526
 
526
- while i < tokens.length
527
- token = tokens[i]
527
+ if token.line > header.line && ![:newline, :indent, :dedent, :eof].include?(token.type) &&
528
+ first_non_trivia_token_on_line?(tokens, i) && token.column <= header.column
529
+ break
530
+ end
528
531
 
529
- if token.line > header.line && ![:newline, :indent, :dedent, :eof].include?(token.type) &&
530
- first_non_trivia_token_on_line?(tokens, i) && token.column <= header.column
531
- break
532
- end
532
+ if token.type == :identifier && token.lexeme == field_name && token.line > header.line &&
533
+ first_non_trivia_token_on_line?(tokens, i) && token.column > header.column
534
+ colon_index = next_non_trivia_token_index(tokens, i + 1)
535
+ return token if colon_index && tokens[colon_index].type == :colon
536
+ end
533
537
 
534
- if token.type == :identifier && token.lexeme == field_name && token.line > header.line &&
535
- first_non_trivia_token_on_line?(tokens, i) && token.column > header.column
536
- colon_index = next_non_trivia_token_index(tokens, i + 1)
537
- return token if colon_index && tokens[colon_index].type == :colon
538
+ i += 1
538
539
  end
539
540
 
540
- i += 1
541
+ nil
541
542
  end
542
543
 
543
- nil
544
- end
544
+ def find_enum_member_token_in_file(path, type_name, member_name)
545
+ tokens = definition_file_tokens(path)
545
546
 
546
- def find_enum_member_token_in_file(path, type_name, member_name)
547
- tokens = definition_file_tokens(path)
547
+ tokens.each_with_index do |token, index|
548
+ next unless [:enum, :flags].include?(token.type)
548
549
 
549
- tokens.each_with_index do |token, index|
550
- next unless [:enum, :flags].include?(token.type)
550
+ name_index = next_non_trivia_token_index(tokens, index + 1)
551
+ next unless name_index && tokens[name_index].type == :identifier && tokens[name_index].lexeme == type_name
551
552
 
552
- name_index = next_non_trivia_token_index(tokens, index + 1)
553
- next unless name_index && tokens[name_index].type == :identifier && tokens[name_index].lexeme == type_name
553
+ member_token = find_enum_member_token_in_body(tokens, index, member_name)
554
+ return member_token if member_token
555
+ end
554
556
 
555
- member_token = find_enum_member_token_in_body(tokens, index, member_name)
556
- return member_token if member_token
557
+ nil
558
+ rescue StandardError
559
+ nil
557
560
  end
558
561
 
559
- nil
560
- rescue StandardError
561
- nil
562
- end
562
+ def find_enum_member_token_in_body(tokens, header_index, member_name)
563
+ header = tokens[header_index]
564
+ i = header_index + 1
563
565
 
564
- def find_enum_member_token_in_body(tokens, header_index, member_name)
565
- header = tokens[header_index]
566
- i = header_index + 1
566
+ while i < tokens.length
567
+ token = tokens[i]
567
568
 
568
- while i < tokens.length
569
- token = tokens[i]
569
+ if token.line > header.line && ![:newline, :indent, :dedent, :eof].include?(token.type) &&
570
+ first_non_trivia_token_on_line?(tokens, i) && token.column <= header.column
571
+ break
572
+ end
570
573
 
571
- if token.line > header.line && ![:newline, :indent, :dedent, :eof].include?(token.type) &&
572
- first_non_trivia_token_on_line?(tokens, i) && token.column <= header.column
573
- break
574
- end
574
+ if token.type == :identifier && token.lexeme == member_name && token.line > header.line &&
575
+ first_non_trivia_token_on_line?(tokens, i) && token.column > header.column
576
+ return token
577
+ end
575
578
 
576
- if token.type == :identifier && token.lexeme == member_name && token.line > header.line &&
577
- first_non_trivia_token_on_line?(tokens, i) && token.column > header.column
578
- return token
579
+ i += 1
579
580
  end
580
581
 
581
- i += 1
582
+ nil
582
583
  end
583
584
 
584
- nil
585
- end
585
+ def enum_member_value_text(current_uri, module_name, type_name, member_name)
586
+ path = module_path_for_name(current_uri, module_name)
587
+ return nil unless path
586
588
 
587
- def enum_member_value_text(current_uri, module_name, type_name, member_name)
588
- path = module_path_for_name(current_uri, module_name)
589
- return nil unless path
589
+ declaration = definition_file_ast(path)&.declarations&.find do |decl|
590
+ (decl.is_a?(AST::EnumDecl) || decl.is_a?(AST::FlagsDecl)) && decl.name == type_name
591
+ end
592
+ return nil unless declaration
590
593
 
591
- declaration = definition_file_ast(path)&.declarations&.find do |decl|
592
- (decl.is_a?(AST::EnumDecl) || decl.is_a?(AST::FlagsDecl)) && decl.name == type_name
594
+ member = declaration.members.find { |candidate| candidate.name == member_name }
595
+ return nil unless member&.value
596
+
597
+ MilkTea::PrettyPrinter::ASTFormatter.new.send(:render_expression, member.value)
598
+ rescue StandardError
599
+ nil
593
600
  end
594
- return nil unless declaration
595
601
 
596
- member = declaration.members.find { |candidate| candidate.name == member_name }
597
- return nil unless member&.value
602
+ def definition_file_mtime_key(path)
603
+ stat = File.stat(path)
604
+ "#{stat.mtime.to_i}:#{stat.mtime.nsec}"
605
+ rescue StandardError
606
+ 'missing'
607
+ end
598
608
 
599
- MilkTea::PrettyPrinter::ASTFormatter.new.send(:render_expression, member.value)
600
- rescue StandardError
601
- nil
602
- end
609
+ def definition_file_tokens(path, mtime_key: nil)
610
+ cache_key = "#{path}:#{mtime_key || definition_file_mtime_key(path)}"
611
+ @definition_file_token_cache[cache_key] ||= begin
612
+ MilkTea::Lexer.lex(File.read(path), path: path_to_uri(path))
613
+ end
614
+ end
603
615
 
604
- def definition_file_mtime_key(path)
605
- stat = File.stat(path)
606
- "#{stat.mtime.to_i}:#{stat.mtime.nsec}"
607
- rescue StandardError
608
- 'missing'
609
- end
616
+ def definition_lookup_tokens(path, current_uri: nil)
617
+ current_path = current_uri ? uri_to_path(current_uri) : nil
618
+ if current_path && File.expand_path(current_path) == File.expand_path(path)
619
+ workspace_tokens = @workspace.get_tokens(current_uri)
620
+ return workspace_tokens if workspace_tokens
621
+ end
610
622
 
611
- def definition_file_tokens(path, mtime_key: nil)
612
- cache_key = "#{path}:#{mtime_key || definition_file_mtime_key(path)}"
613
- @definition_file_token_cache[cache_key] ||= begin
614
- MilkTea::Lexer.lex(File.read(path), path: path_to_uri(path))
623
+ definition_file_tokens(path)
615
624
  end
616
- end
617
625
 
618
- def definition_lookup_tokens(path, current_uri: nil)
619
- current_path = current_uri ? uri_to_path(current_uri) : nil
620
- if current_path && File.expand_path(current_path) == File.expand_path(path)
621
- workspace_tokens = @workspace.get_tokens(current_uri)
622
- return workspace_tokens if workspace_tokens
626
+ def definition_file_ast(path)
627
+ mtime_key = definition_file_mtime_key(path)
628
+ cache_key = "#{path}:#{mtime_key}"
629
+ @definition_file_ast_cache[cache_key] ||= begin
630
+ MilkTea::Parser.parse(nil, path: path_to_uri(path), tokens: definition_file_tokens(path, mtime_key: mtime_key))
631
+ end
623
632
  end
624
633
 
625
- definition_file_tokens(path)
626
- end
627
-
628
- def definition_file_ast(path)
629
- mtime_key = definition_file_mtime_key(path)
630
- cache_key = "#{path}:#{mtime_key}"
631
- @definition_file_ast_cache[cache_key] ||= begin
632
- MilkTea::Parser.parse(nil, path: path_to_uri(path), tokens: definition_file_tokens(path, mtime_key: mtime_key))
633
- end
634
- end
634
+ def resolve_interface_binding_at_position(uri, facts, token, lsp_line, lsp_char)
635
+ binding = facts.interfaces[token.lexeme]
636
+ return binding if binding
635
637
 
636
- def resolve_interface_binding_at_position(uri, facts, token, lsp_line, lsp_char)
637
- binding = facts.interfaces[token.lexeme]
638
- return binding if binding
638
+ dot_receiver = @workspace.find_dot_receiver(uri, lsp_line, lsp_char)
639
+ return nil unless dot_receiver
639
640
 
640
- dot_receiver = @workspace.find_dot_receiver(uri, lsp_line, lsp_char)
641
- return nil unless dot_receiver
641
+ facts.imports[dot_receiver]&.interfaces&.fetch(token.lexeme, nil)
642
+ end
642
643
 
643
- facts.imports[dot_receiver]&.interfaces&.fetch(token.lexeme, nil)
644
- end
644
+ def resolve_interface_method_target_at_token(facts, token)
645
+ facts.interfaces.each_value do |interface_binding|
646
+ method_binding = interface_binding.methods[token.lexeme]
647
+ next unless method_binding
648
+ next unless method_binding.ast.line == token.line
649
+ next unless method_binding.ast.column == token.column
645
650
 
646
- def resolve_interface_method_target_at_token(facts, token)
647
- facts.interfaces.each_value do |interface_binding|
648
- method_binding = interface_binding.methods[token.lexeme]
649
- next unless method_binding
650
- next unless method_binding.ast.line == token.line
651
- next unless method_binding.ast.respond_to?(:column) && method_binding.ast.column == token.column
651
+ return { interface: interface_binding, method: method_binding }
652
+ end
652
653
 
653
- return { interface: interface_binding, method: method_binding }
654
+ nil
654
655
  end
655
656
 
656
- nil
657
- end
657
+ def interface_implementation_locations(interface_binding)
658
+ seen = Set.new
659
+ @workspace.all_documents.filter_map do |doc_uri|
660
+ facts = @workspace.get_facts(doc_uri)
661
+ next unless facts
658
662
 
659
- def interface_implementation_locations(interface_binding)
660
- seen = Set.new
661
- @workspace.all_documents.filter_map do |doc_uri|
662
- facts = @workspace.get_facts(doc_uri)
663
- next unless facts
663
+ facts.implemented_interfaces.each_with_object([]) do |(receiver_type, interfaces), locations|
664
+ next unless interfaces.any? { |candidate| same_interface_binding?(candidate, interface_binding) }
664
665
 
665
- facts.implemented_interfaces.each_with_object([]) do |(receiver_type, interfaces), locations|
666
- next unless interfaces.any? { |candidate| same_interface_binding?(candidate, interface_binding) }
666
+ location = interface_receiver_definition_location(doc_uri, receiver_type)
667
+ next unless location
667
668
 
668
- location = interface_receiver_definition_location(doc_uri, receiver_type)
669
- next unless location
669
+ key = [location[:uri], location.dig(:range, :start, :line), location.dig(:range, :start, :character)]
670
+ next if seen.include?(key)
670
671
 
671
- key = [location[:uri], location.dig(:range, :start, :line), location.dig(:range, :start, :character)]
672
- next if seen.include?(key)
672
+ seen << key
673
+ locations << location
674
+ end
675
+ end.flatten
676
+ end
673
677
 
674
- seen << key
675
- locations << location
676
- end
677
- end.flatten
678
- end
678
+ def interface_method_implementation_locations(interface_binding, interface_method)
679
+ seen = Set.new
680
+ @workspace.all_documents.filter_map do |doc_uri|
681
+ facts = @workspace.get_facts(doc_uri)
682
+ next unless facts
679
683
 
680
- def interface_method_implementation_locations(interface_binding, interface_method)
681
- seen = Set.new
682
- @workspace.all_documents.filter_map do |doc_uri|
683
- facts = @workspace.get_facts(doc_uri)
684
- next unless facts
684
+ facts.implemented_interfaces.each_with_object([]) do |(receiver_type, interfaces), locations|
685
+ next unless interfaces.any? { |candidate| same_interface_binding?(candidate, interface_binding) }
685
686
 
686
- facts.implemented_interfaces.each_with_object([]) do |(receiver_type, interfaces), locations|
687
- next unless interfaces.any? { |candidate| same_interface_binding?(candidate, interface_binding) }
687
+ method = methods_for_receiver_type(facts, receiver_type)[interface_method.name]
688
+ next unless method
688
689
 
689
- method = methods_for_receiver_type(facts, receiver_type)[interface_method.name]
690
- next unless method
690
+ module_name = receiver_module_name(receiver_type)
691
+ location = module_member_binding_location(doc_uri, module_name, interface_method.name, method)
692
+ location ||= module_member_definition_location(doc_uri, module_name, interface_method.name)
693
+ next unless location
691
694
 
692
- module_name = receiver_module_name(receiver_type)
693
- location = module_member_binding_location(doc_uri, module_name, interface_method.name, method)
694
- location ||= module_member_definition_location(doc_uri, module_name, interface_method.name)
695
- next unless location
695
+ key = [location[:uri], location.dig(:range, :start, :line), location.dig(:range, :start, :character)]
696
+ next if seen.include?(key)
696
697
 
697
- key = [location[:uri], location.dig(:range, :start, :line), location.dig(:range, :start, :character)]
698
- next if seen.include?(key)
698
+ seen << key
699
+ locations << location
700
+ end
701
+ end.flatten
702
+ end
699
703
 
700
- seen << key
701
- locations << location
702
- end
703
- end.flatten
704
- end
704
+ def interface_receiver_definition_location(current_uri, receiver_type)
705
+ receiver_type = receiver_type.definition if receiver_type.is_a?(Types::StructInstance) || receiver_type.is_a?(Types::VariantInstance)
705
706
 
706
- def interface_receiver_definition_location(current_uri, receiver_type)
707
- receiver_type = receiver_type.definition if receiver_type.is_a?(Types::StructInstance) || receiver_type.is_a?(Types::VariantInstance)
707
+ if receiver_type.module_name.nil? || receiver_type.module_name.empty?
708
+ token = local_type_definition_token(current_uri, receiver_type.name)
709
+ token ||= @workspace.find_definition_token(current_uri, receiver_type.name)
710
+ return { uri: current_uri, range: token_to_range(token) } if token
711
+ end
708
712
 
709
- if receiver_type.module_name.nil? || receiver_type.module_name.empty?
710
- token = local_type_definition_token(current_uri, receiver_type.name)
711
- token ||= @workspace.find_definition_token(current_uri, receiver_type.name)
712
- return { uri: current_uri, range: token_to_range(token) } if token
713
+ module_member_definition_location(current_uri, receiver_type.module_name, receiver_type.name)
713
714
  end
714
715
 
715
- module_member_definition_location(current_uri, receiver_type.module_name, receiver_type.name)
716
- end
716
+ def receiver_module_name(receiver_type)
717
+ receiver_type = receiver_type.definition if receiver_type.is_a?(Types::StructInstance) || receiver_type.is_a?(Types::VariantInstance)
717
718
 
718
- def receiver_module_name(receiver_type)
719
- receiver_type = receiver_type.definition if receiver_type.is_a?(Types::StructInstance) || receiver_type.is_a?(Types::VariantInstance)
719
+ receiver_type.module_name
720
+ end
720
721
 
721
- receiver_type.module_name
722
- end
722
+ def local_type_definition_token(uri, name)
723
+ tokens = @workspace.get_tokens(uri)
724
+ return nil unless tokens
723
725
 
724
- def local_type_definition_token(uri, name)
725
- tokens = @workspace.get_tokens(uri)
726
- return nil unless tokens
726
+ tokens.each_cons(2) do |kw_tok, id_tok|
727
+ next unless [:struct, :opaque, :enum, :flags, :variant, :union].include?(kw_tok.type)
728
+ next unless id_tok.type == :identifier && id_tok.lexeme == name
727
729
 
728
- tokens.each_cons(2) do |kw_tok, id_tok|
729
- next unless [:struct, :opaque, :enum, :flags, :variant, :union].include?(kw_tok.type)
730
- next unless id_tok.type == :identifier && id_tok.lexeme == name
730
+ return id_tok
731
+ end
731
732
 
732
- return id_tok
733
+ nil
733
734
  end
734
735
 
735
- nil
736
+ def same_interface_binding?(left, right)
737
+ left.name == right.name && left.module_name == right.module_name
738
+ end
736
739
  end
737
740
 
738
- def same_interface_binding?(left, right)
739
- left.name == right.name && left.module_name == right.module_name
740
- end
741
- end
742
741
  def named_argument_definition_location(uri, name, tokens, token_index, stages: nil)
743
742
  return nil unless named_argument_label_token?(tokens, token_index)
744
743