mt-lang 0.2.0
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 +7 -0
- data/.ruby-version +1 -0
- data/AUTHORS +3 -0
- data/Gemfile +19 -0
- data/Gemfile.lock +82 -0
- data/LICENSE +21 -0
- data/README.md +1208 -0
- data/Rakefile +332 -0
- data/bin/mtc +8 -0
- data/bin/profile-mtc-checks +133 -0
- data/bin/tracy-profiler +0 -0
- data/docs/build-guide.md +536 -0
- data/docs/index.html +2778 -0
- data/docs/language-design.md +1519 -0
- data/docs/language-manual.md +1534 -0
- data/lib/milk_tea/base.rb +49 -0
- data/lib/milk_tea/bindings/bindgen/ast_parser.rb +398 -0
- data/lib/milk_tea/bindings/bindgen/declaration.rb +319 -0
- data/lib/milk_tea/bindings/bindgen/emitter.rb +387 -0
- data/lib/milk_tea/bindings/bindgen/overrides.rb +134 -0
- data/lib/milk_tea/bindings/bindgen/type_mapper.rb +622 -0
- data/lib/milk_tea/bindings/bindgen.rb +207 -0
- data/lib/milk_tea/bindings/cli.rb +121 -0
- data/lib/milk_tea/bindings/imported_bindings/defaults.rb +210 -0
- data/lib/milk_tea/bindings/imported_bindings/generator.rb +1114 -0
- data/lib/milk_tea/bindings/imported_bindings/method_source.rb +190 -0
- data/lib/milk_tea/bindings/imported_bindings/naming.rb +286 -0
- data/lib/milk_tea/bindings/imported_bindings.rb +215 -0
- data/lib/milk_tea/bindings/opengl_registry.rb +547 -0
- data/lib/milk_tea/bindings/raw_bindings/defaults.rb +1338 -0
- data/lib/milk_tea/bindings/raw_bindings.rb +269 -0
- data/lib/milk_tea/bindings/steamworks.rb +629 -0
- data/lib/milk_tea/bindings/upstream_sources.rb +352 -0
- data/lib/milk_tea/bindings/vendored_box2d.rb +79 -0
- data/lib/milk_tea/bindings/vendored_c_library.rb +322 -0
- data/lib/milk_tea/bindings/vendored_cjson.rb +52 -0
- data/lib/milk_tea/bindings/vendored_flecs.rb +78 -0
- data/lib/milk_tea/bindings/vendored_glfw.rb +77 -0
- data/lib/milk_tea/bindings/vendored_libuv.rb +75 -0
- data/lib/milk_tea/bindings/vendored_pcre2.rb +84 -0
- data/lib/milk_tea/bindings/vendored_raylib.rb +131 -0
- data/lib/milk_tea/bindings/vendored_sdl3.rb +78 -0
- data/lib/milk_tea/bindings/vendored_steamworks.rb +71 -0
- data/lib/milk_tea/bindings/vendored_tool.rb +71 -0
- data/lib/milk_tea/bindings/vendored_tools.rb +23 -0
- data/lib/milk_tea/bindings/vendored_tracy.rb +37 -0
- data/lib/milk_tea/bindings.rb +23 -0
- data/lib/milk_tea/core/ast.rb +311 -0
- data/lib/milk_tea/core/async_runtime_installer.rb +28 -0
- data/lib/milk_tea/core/binding_types.rb +18 -0
- data/lib/milk_tea/core/bindings/attribute_binding.rb +58 -0
- data/lib/milk_tea/core/bindings/function_binding.rb +5 -0
- data/lib/milk_tea/core/bindings/module_binding.rb +58 -0
- data/lib/milk_tea/core/bindings/value_binding.rb +21 -0
- data/lib/milk_tea/core/c_backend/aggregate_utils.rb +103 -0
- data/lib/milk_tea/core/c_backend/control_flow_emission.rb +412 -0
- data/lib/milk_tea/core/c_backend/expressions.rb +468 -0
- data/lib/milk_tea/core/c_backend/feature_detection.rb +483 -0
- data/lib/milk_tea/core/c_backend/reachability.rb +398 -0
- data/lib/milk_tea/core/c_backend/reinterpret.rb +226 -0
- data/lib/milk_tea/core/c_backend/runtime_helpers.rb +1080 -0
- data/lib/milk_tea/core/c_backend/statements.rb +563 -0
- data/lib/milk_tea/core/c_backend/type_collectors.rb +1545 -0
- data/lib/milk_tea/core/c_backend/type_declaration.rb +223 -0
- data/lib/milk_tea/core/c_backend/type_system.rb +345 -0
- data/lib/milk_tea/core/c_backend.rb +287 -0
- data/lib/milk_tea/core/compatibility_helpers.rb +79 -0
- data/lib/milk_tea/core/compile_time/const_eval.rb +187 -0
- data/lib/milk_tea/core/compile_time.rb +329 -0
- data/lib/milk_tea/core/control_flow/builder.rb +582 -0
- data/lib/milk_tea/core/control_flow/constant_propagation.rb +143 -0
- data/lib/milk_tea/core/control_flow/dataflow.rb +74 -0
- data/lib/milk_tea/core/control_flow/definite_assignment.rb +79 -0
- data/lib/milk_tea/core/control_flow/graph.rb +90 -0
- data/lib/milk_tea/core/control_flow/liveness.rb +24 -0
- data/lib/milk_tea/core/control_flow/nullability_flow.rb +43 -0
- data/lib/milk_tea/core/control_flow/reachability.rb +22 -0
- data/lib/milk_tea/core/control_flow/termination.rb +31 -0
- data/lib/milk_tea/core/control_flow.rb +34 -0
- data/lib/milk_tea/core/cst.rb +48 -0
- data/lib/milk_tea/core/cst_builder.rb +19 -0
- data/lib/milk_tea/core/ir.rb +85 -0
- data/lib/milk_tea/core/keywords.rb +97 -0
- data/lib/milk_tea/core/lexer/character_classes.rb +60 -0
- data/lib/milk_tea/core/lexer/format_strings.rb +225 -0
- data/lib/milk_tea/core/lexer/heredocs.rb +199 -0
- data/lib/milk_tea/core/lexer/indentation.rb +62 -0
- data/lib/milk_tea/core/lexer/numbers.rb +96 -0
- data/lib/milk_tea/core/lexer/recovery.rb +32 -0
- data/lib/milk_tea/core/lexer/strings.rb +167 -0
- data/lib/milk_tea/core/lexer/symbols.rb +71 -0
- data/lib/milk_tea/core/lexer/trivia.rb +53 -0
- data/lib/milk_tea/core/lexer.rb +430 -0
- data/lib/milk_tea/core/lowering/artifacts.rb +26 -0
- data/lib/milk_tea/core/lowering/async/analysis.rb +245 -0
- data/lib/milk_tea/core/lowering/async/lowering.rb +1399 -0
- data/lib/milk_tea/core/lowering/async/normalization.rb +459 -0
- data/lib/milk_tea/core/lowering/async.rb +714 -0
- data/lib/milk_tea/core/lowering/block.rb +1052 -0
- data/lib/milk_tea/core/lowering/calls.rb +1565 -0
- data/lib/milk_tea/core/lowering/declarations.rb +214 -0
- data/lib/milk_tea/core/lowering/dyn.rb +206 -0
- data/lib/milk_tea/core/lowering/events.rb +1054 -0
- data/lib/milk_tea/core/lowering/expressions.rb +1645 -0
- data/lib/milk_tea/core/lowering/foreign_cstr.rb +206 -0
- data/lib/milk_tea/core/lowering/functions.rb +242 -0
- data/lib/milk_tea/core/lowering/loops.rb +1087 -0
- data/lib/milk_tea/core/lowering/lowering_context.rb +80 -0
- data/lib/milk_tea/core/lowering/proc.rb +419 -0
- data/lib/milk_tea/core/lowering/resolve.rb +2516 -0
- data/lib/milk_tea/core/lowering/scans.rb +220 -0
- data/lib/milk_tea/core/lowering/str_buffer.rb +125 -0
- data/lib/milk_tea/core/lowering/utils.rb +1453 -0
- data/lib/milk_tea/core/lowering.rb +378 -0
- data/lib/milk_tea/core/module_binder.rb +181 -0
- data/lib/milk_tea/core/module_loader/errors.rb +21 -0
- data/lib/milk_tea/core/module_loader.rb +479 -0
- data/lib/milk_tea/core/module_path_resolver.rb +153 -0
- data/lib/milk_tea/core/module_roots.rb +88 -0
- data/lib/milk_tea/core/parser/attributes.rb +71 -0
- data/lib/milk_tea/core/parser/blocks.rb +119 -0
- data/lib/milk_tea/core/parser/declarations.rb +749 -0
- data/lib/milk_tea/core/parser/expressions.rb +624 -0
- data/lib/milk_tea/core/parser/recovery.rb +131 -0
- data/lib/milk_tea/core/parser/statements.rb +756 -0
- data/lib/milk_tea/core/parser/types.rb +271 -0
- data/lib/milk_tea/core/parser.rb +400 -0
- data/lib/milk_tea/core/prelude_installer.rb +29 -0
- data/lib/milk_tea/core/pretty_printer/ast_formatter.rb +917 -0
- data/lib/milk_tea/core/pretty_printer/base_formatter.rb +87 -0
- data/lib/milk_tea/core/pretty_printer/ir_formatter.rb +300 -0
- data/lib/milk_tea/core/pretty_printer.rb +17 -0
- data/lib/milk_tea/core/semantic_analyzer/analysis_context.rb +314 -0
- data/lib/milk_tea/core/semantic_analyzer/attributes.rb +184 -0
- data/lib/milk_tea/core/semantic_analyzer/calls.rb +992 -0
- data/lib/milk_tea/core/semantic_analyzer/expressions.rb +1735 -0
- data/lib/milk_tea/core/semantic_analyzer/flow_refinement.rb +355 -0
- data/lib/milk_tea/core/semantic_analyzer/foreign_functions.rb +155 -0
- data/lib/milk_tea/core/semantic_analyzer/function_binding.rb +354 -0
- data/lib/milk_tea/core/semantic_analyzer/generics.rb +383 -0
- data/lib/milk_tea/core/semantic_analyzer/interface_conformance.rb +78 -0
- data/lib/milk_tea/core/semantic_analyzer/module_context.rb +35 -0
- data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +1438 -0
- data/lib/milk_tea/core/semantic_analyzer/nullability.rb +421 -0
- data/lib/milk_tea/core/semantic_analyzer/statements.rb +1308 -0
- data/lib/milk_tea/core/semantic_analyzer/top_level.rb +588 -0
- data/lib/milk_tea/core/semantic_analyzer/type_compatibility.rb +307 -0
- data/lib/milk_tea/core/semantic_analyzer/type_declaration.rb +851 -0
- data/lib/milk_tea/core/semantic_analyzer.rb +327 -0
- data/lib/milk_tea/core/token.rb +26 -0
- data/lib/milk_tea/core/token_stream.rb +30 -0
- data/lib/milk_tea/core/types/layout.rb +243 -0
- data/lib/milk_tea/core/types/predicates.rb +609 -0
- data/lib/milk_tea/core/types/registry.rb +83 -0
- data/lib/milk_tea/core/types/types.rb +1696 -0
- data/lib/milk_tea/core/types/visitor.rb +442 -0
- data/lib/milk_tea/core.rb +25 -0
- data/lib/milk_tea/dap/backends/lldb_dap.rb +158 -0
- data/lib/milk_tea/dap/protocol.rb +58 -0
- data/lib/milk_tea/dap/server/breakpoints.rb +66 -0
- data/lib/milk_tea/dap/server/debug_map.rb +291 -0
- data/lib/milk_tea/dap/server/handlers.rb +374 -0
- data/lib/milk_tea/dap/server/launch.rb +261 -0
- data/lib/milk_tea/dap/server/lldb_backend.rb +380 -0
- data/lib/milk_tea/dap/server/pause_diagnostics.rb +109 -0
- data/lib/milk_tea/dap/server/utilities.rb +160 -0
- data/lib/milk_tea/dap/server/wire.rb +55 -0
- data/lib/milk_tea/dap/server.rb +131 -0
- data/lib/milk_tea/dap/session.rb +152 -0
- data/lib/milk_tea/dap.rb +6 -0
- data/lib/milk_tea/lsp/dependency_resolution.rb +52 -0
- data/lib/milk_tea/lsp/diagnostics.rb +611 -0
- data/lib/milk_tea/lsp/protocol.rb +104 -0
- data/lib/milk_tea/lsp/server/call_hierarchy.rb +274 -0
- data/lib/milk_tea/lsp/server/code_actions.rb +446 -0
- data/lib/milk_tea/lsp/server/code_lens.rb +97 -0
- data/lib/milk_tea/lsp/server/completion.rb +1099 -0
- data/lib/milk_tea/lsp/server/configuration.rb +167 -0
- data/lib/milk_tea/lsp/server/debug_info.rb +45 -0
- data/lib/milk_tea/lsp/server/definition.rb +779 -0
- data/lib/milk_tea/lsp/server/diagnostics_scheduling.rb +239 -0
- data/lib/milk_tea/lsp/server/execute_command.rb +25 -0
- data/lib/milk_tea/lsp/server/folding_range.rb +153 -0
- data/lib/milk_tea/lsp/server/formatting.rb +575 -0
- data/lib/milk_tea/lsp/server/hover.rb +1465 -0
- data/lib/milk_tea/lsp/server/inlay_hints.rb +204 -0
- data/lib/milk_tea/lsp/server/lifecycle.rb +234 -0
- data/lib/milk_tea/lsp/server/linked_editing_range.rb +43 -0
- data/lib/milk_tea/lsp/server/on_type_formatting.rb +73 -0
- data/lib/milk_tea/lsp/server/progress.rb +47 -0
- data/lib/milk_tea/lsp/server/references.rb +433 -0
- data/lib/milk_tea/lsp/server/rename.rb +598 -0
- data/lib/milk_tea/lsp/server/selection_range.rb +130 -0
- data/lib/milk_tea/lsp/server/semantic_tokens.rb +1745 -0
- data/lib/milk_tea/lsp/server/signature_help.rb +200 -0
- data/lib/milk_tea/lsp/server/text_documents.rb +125 -0
- data/lib/milk_tea/lsp/server/type_hierarchy.rb +167 -0
- data/lib/milk_tea/lsp/server/utilities.rb +520 -0
- data/lib/milk_tea/lsp/server.rb +415 -0
- data/lib/milk_tea/lsp/workspace/analysis.rb +209 -0
- data/lib/milk_tea/lsp/workspace/caches.rb +260 -0
- data/lib/milk_tea/lsp/workspace/collection.rb +98 -0
- data/lib/milk_tea/lsp/workspace/definition_index.rb +184 -0
- data/lib/milk_tea/lsp/workspace/dependency_graph.rb +282 -0
- data/lib/milk_tea/lsp/workspace/store.rb +154 -0
- data/lib/milk_tea/lsp/workspace/utilities.rb +490 -0
- data/lib/milk_tea/lsp/workspace.rb +127 -0
- data/lib/milk_tea/lsp.rb +13 -0
- data/lib/milk_tea/packages/atomic_write.rb +63 -0
- data/lib/milk_tea/packages/dependency_solver.rb +194 -0
- data/lib/milk_tea/packages/graph.rb +139 -0
- data/lib/milk_tea/packages/lock.rb +421 -0
- data/lib/milk_tea/packages/manager_cli.rb +485 -0
- data/lib/milk_tea/packages/manifest.rb +356 -0
- data/lib/milk_tea/packages/manifest_editor.rb +134 -0
- data/lib/milk_tea/packages/registry_metadata_provider.rb +34 -0
- data/lib/milk_tea/packages/registry_store.rb +420 -0
- data/lib/milk_tea/packages/services.rb +41 -0
- data/lib/milk_tea/packages/source_cache.rb +71 -0
- data/lib/milk_tea/packages/source_fetcher.rb +124 -0
- data/lib/milk_tea/packages/source_resolver.rb +389 -0
- data/lib/milk_tea/packages/version.rb +164 -0
- data/lib/milk_tea/packages.rb +16 -0
- data/lib/milk_tea/tooling/asset_pack.rb +141 -0
- data/lib/milk_tea/tooling/build.rb +1124 -0
- data/lib/milk_tea/tooling/build_cache.rb +240 -0
- data/lib/milk_tea/tooling/cli.rb +2688 -0
- data/lib/milk_tea/tooling/cst_formatter.rb +13 -0
- data/lib/milk_tea/tooling/debug_info_formatter.rb +456 -0
- data/lib/milk_tea/tooling/debug_map.rb +248 -0
- data/lib/milk_tea/tooling/docs_app.rb +369 -0
- data/lib/milk_tea/tooling/error_formatter.rb +86 -0
- data/lib/milk_tea/tooling/formatter.rb +787 -0
- data/lib/milk_tea/tooling/linter/doc_tags.rb +212 -0
- data/lib/milk_tea/tooling/linter/fix_engine.rb +237 -0
- data/lib/milk_tea/tooling/linter/flow_rules.rb +380 -0
- data/lib/milk_tea/tooling/linter/imports_platform.rb +841 -0
- data/lib/milk_tea/tooling/linter/release_rules.rb +744 -0
- data/lib/milk_tea/tooling/linter/reserved_names.rb +199 -0
- data/lib/milk_tea/tooling/linter/rules.rb +593 -0
- data/lib/milk_tea/tooling/linter/source_helpers.rb +407 -0
- data/lib/milk_tea/tooling/linter/trailing_comma.rb +139 -0
- data/lib/milk_tea/tooling/linter/visitors.rb +1286 -0
- data/lib/milk_tea/tooling/linter.rb +798 -0
- data/lib/milk_tea/tooling/project_scaffold.rb +82 -0
- data/lib/milk_tea/tooling/public/css/docs.css +166 -0
- data/lib/milk_tea/tooling/public/js/docs.js +94 -0
- data/lib/milk_tea/tooling/run.rb +408 -0
- data/lib/milk_tea/tooling/templates/wasm_shell.html +48 -0
- data/lib/milk_tea/tooling/toolchain_cli.rb +157 -0
- data/lib/milk_tea/tooling/views/404.erb +7 -0
- data/lib/milk_tea/tooling/views/index.erb +87 -0
- data/lib/milk_tea/tooling/views/layout.erb +69 -0
- data/lib/milk_tea/tooling/views/module.erb +97 -0
- data/lib/milk_tea/tooling/views/stdlib.erb +21 -0
- data/lib/milk_tea/tooling.rb +20 -0
- data/lib/milk_tea.rb +8 -0
- metadata +426 -0
|
@@ -0,0 +1,1438 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MilkTea
|
|
4
|
+
class SemanticAnalyzer
|
|
5
|
+
class Checker
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def current_type_params
|
|
9
|
+
@current_type_substitutions || {}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def current_type_param_constraints
|
|
13
|
+
@current_type_param_constraints || {}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def lookup_value(name, scopes)
|
|
17
|
+
scopes.reverse_each do |scope|
|
|
18
|
+
return scope[name] if scope.key?(name)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
@ctx.top_level_values[name]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def lookup_method(receiver_type, name)
|
|
25
|
+
method = lookup_method_local_or_imported(receiver_type, name)
|
|
26
|
+
return method if method
|
|
27
|
+
|
|
28
|
+
fallback_owner = specialization_lookup_owner
|
|
29
|
+
return nil unless fallback_owner
|
|
30
|
+
|
|
31
|
+
fallback_owner.send(:lookup_method_local_or_imported, receiver_type, name)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def lookup_static_method(receiver_type, name)
|
|
35
|
+
static_name = "static:#{name}"
|
|
36
|
+
method = lookup_method_local_or_imported(receiver_type, static_name)
|
|
37
|
+
return method if method
|
|
38
|
+
|
|
39
|
+
fallback_owner = specialization_lookup_owner
|
|
40
|
+
return nil unless fallback_owner
|
|
41
|
+
|
|
42
|
+
fallback_owner.send(:lookup_method_local_or_imported, receiver_type, static_name)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def lookup_method_local_or_imported(receiver_type, name)
|
|
46
|
+
dispatch_receiver_type = method_dispatch_receiver_type(receiver_type)
|
|
47
|
+
|
|
48
|
+
method = @ctx.methods.fetch(receiver_type, {})[name]
|
|
49
|
+
method ||= @ctx.methods.fetch(dispatch_receiver_type, {})[name] unless dispatch_receiver_type == receiver_type
|
|
50
|
+
return method if method
|
|
51
|
+
|
|
52
|
+
imported_candidates = []
|
|
53
|
+
|
|
54
|
+
@ctx.imports.each_value do |module_binding|
|
|
55
|
+
imported_method = module_binding.methods.fetch(receiver_type, {})[name]
|
|
56
|
+
if imported_method.nil? && dispatch_receiver_type != receiver_type
|
|
57
|
+
imported_method = module_binding.methods.fetch(dispatch_receiver_type, {})[name]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
imported_candidates << [module_binding, imported_method] if imported_method
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
if imported_candidates.empty?
|
|
64
|
+
owner_module = reachable_module_binding_for_type(receiver_type)
|
|
65
|
+
return nil unless owner_module
|
|
66
|
+
|
|
67
|
+
return module_binding_method(owner_module, receiver_type, dispatch_receiver_type, name)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
if imported_candidates.length > 1
|
|
71
|
+
modules = imported_candidates.map { |module_binding, _binding| module_binding.name }.join(", ")
|
|
72
|
+
display_name = name.delete_prefix("static:")
|
|
73
|
+
raise_sema_error("ambiguous imported method #{receiver_type}.#{display_name}; found in modules #{modules}")
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
imported_candidates.first.last
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def module_binding_method(module_binding, receiver_type, dispatch_receiver_type, name)
|
|
80
|
+
method = module_binding.methods.fetch(receiver_type, {})[name]
|
|
81
|
+
method ||= module_binding.methods.fetch(dispatch_receiver_type, {})[name] unless dispatch_receiver_type == receiver_type
|
|
82
|
+
method
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def reachable_module_binding_for_type(receiver_type)
|
|
86
|
+
module_name = receiver_type_module_name(receiver_type)
|
|
87
|
+
return nil unless module_name
|
|
88
|
+
return nil if module_name == @ctx.module_name
|
|
89
|
+
|
|
90
|
+
find_reachable_imported_module(module_name)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def receiver_type_module_name(receiver_type)
|
|
94
|
+
return receiver_type_module_name(receiver_type.base) if receiver_type.is_a?(Types::Nullable)
|
|
95
|
+
return receiver_type.module_name if receiver_type.respond_to?(:module_name)
|
|
96
|
+
|
|
97
|
+
nil
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def find_reachable_imported_module(module_name)
|
|
101
|
+
visited = {}
|
|
102
|
+
|
|
103
|
+
@ctx.imports.each_value do |module_binding|
|
|
104
|
+
found = find_reachable_imported_module_from(module_binding, module_name, visited)
|
|
105
|
+
return found if found
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
nil
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def find_reachable_imported_module_from(module_binding, module_name, visited)
|
|
112
|
+
return nil unless module_binding
|
|
113
|
+
return module_binding if module_binding.name == module_name
|
|
114
|
+
return nil if visited[module_binding.name]
|
|
115
|
+
|
|
116
|
+
visited[module_binding.name] = true
|
|
117
|
+
module_binding.imports.each_value do |imported_module|
|
|
118
|
+
found = find_reachable_imported_module_from(imported_module, module_name, visited)
|
|
119
|
+
return found if found
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
nil
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def specialization_lookup_owner
|
|
126
|
+
return nil if @current_specialization_owner.nil?
|
|
127
|
+
return nil if @current_specialization_owner.equal?(self)
|
|
128
|
+
|
|
129
|
+
@current_specialization_owner
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def resolve_interface_ref(interface_ref)
|
|
133
|
+
parts = interface_ref.parts
|
|
134
|
+
|
|
135
|
+
interface = if parts.length == 1
|
|
136
|
+
@ctx.interfaces[parts.first]
|
|
137
|
+
elsif parts.length == 2 && @ctx.imports.key?(parts.first)
|
|
138
|
+
imported_module = @ctx.imports.fetch(parts.first)
|
|
139
|
+
raw = imported_module.interfaces[parts.last]
|
|
140
|
+
if imported_module.private_interface?(parts.last)
|
|
141
|
+
raise_sema_error("#{parts.first}.#{parts.last} is private to module #{imported_module.name}")
|
|
142
|
+
end
|
|
143
|
+
raw
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
raise_sema_error("unknown interface #{interface_ref}", interface_ref) unless interface
|
|
147
|
+
|
|
148
|
+
if interface_ref.type_arguments.any?
|
|
149
|
+
raise_sema_error("interface #{interface.name} is not generic") unless interface.is_a?(GenericInterfaceBinding)
|
|
150
|
+
|
|
151
|
+
arguments = interface_ref.type_arguments.map { |arg| resolve_type_ref(arg) }
|
|
152
|
+
interface.instantiate(arguments)
|
|
153
|
+
else
|
|
154
|
+
raise_sema_error("generic interface #{interface.name} requires type arguments") if interface.is_a?(GenericInterfaceBinding)
|
|
155
|
+
|
|
156
|
+
interface
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def interface_implementation_key(type)
|
|
161
|
+
return type.definition if type.is_a?(Types::StructInstance)
|
|
162
|
+
|
|
163
|
+
type
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def type_implements_interface?(type, interface)
|
|
167
|
+
key = interface_implementation_key(type)
|
|
168
|
+
return true if @ctx.implemented_interfaces.fetch(key, []).include?(interface)
|
|
169
|
+
|
|
170
|
+
@ctx.imports.each_value do |module_binding|
|
|
171
|
+
return true if module_binding.implemented_interfaces.fetch(key, []).include?(interface)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
false
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def type_satisfies_interface_constraint?(type, interface, available_type_param_constraints: current_type_param_constraints)
|
|
178
|
+
if type.is_a?(Types::TypeVar)
|
|
179
|
+
constraint = available_type_param_constraints[type.name]
|
|
180
|
+
return constraint && constraint.interfaces.include?(interface)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
type_implements_interface?(type, interface)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def validate_type_param_constraint_binding!(constraints, actual_type, context:, available_type_param_constraints: current_type_param_constraints)
|
|
187
|
+
constraints.interfaces.each do |interface|
|
|
188
|
+
next if type_satisfies_interface_constraint?(actual_type, interface, available_type_param_constraints:)
|
|
189
|
+
|
|
190
|
+
raise_sema_error("type #{actual_type} does not implement interface #{interface.name} for #{context}")
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def validate_generic_type_param_constraints!(generic_type, arguments, context:, available_type_param_constraints: current_type_param_constraints)
|
|
195
|
+
return if generic_type.type_param_constraints.empty?
|
|
196
|
+
|
|
197
|
+
generic_type.type_params.zip(arguments).each do |name, actual_type|
|
|
198
|
+
constraints = generic_type.type_param_constraints[name]
|
|
199
|
+
next unless constraints
|
|
200
|
+
|
|
201
|
+
validate_type_param_constraint_binding!(constraints, actual_type, context:, available_type_param_constraints:)
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def resolve_type_ref(type_ref, type_params: current_type_params, type_param_constraints: current_type_param_constraints, nested_types: nil)
|
|
206
|
+
base = resolve_non_nullable_type(type_ref, type_params:, type_param_constraints:, nested_types:)
|
|
207
|
+
return base if type_ref.is_a?(AST::FunctionType) || type_ref.is_a?(AST::ProcType) || type_ref.is_a?(AST::TupleType)
|
|
208
|
+
|
|
209
|
+
raise_sema_error("ref types are non-null and cannot be nullable", type_ref) if type_ref.nullable && ref_type?(base)
|
|
210
|
+
|
|
211
|
+
type_ref.nullable ? Types::Registry.nullable(base) : base
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def resolve_non_nullable_type(type_ref, type_params: {}, type_param_constraints: {}, nested_types: nil)
|
|
215
|
+
if type_ref.is_a?(AST::FunctionType)
|
|
216
|
+
params = type_ref.params.map do |param|
|
|
217
|
+
Types::Registry.parameter(param.name, resolve_type_ref(param.type, type_params:, type_param_constraints:))
|
|
218
|
+
end
|
|
219
|
+
return Types::Registry.function(nil, params:, return_type: resolve_type_ref(type_ref.return_type, type_params:, type_param_constraints:))
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
if type_ref.is_a?(AST::ProcType)
|
|
223
|
+
params = type_ref.params.map do |param|
|
|
224
|
+
Types::Registry.parameter(param.name, resolve_type_ref(param.type, type_params:, type_param_constraints:))
|
|
225
|
+
end
|
|
226
|
+
return Types::Registry.proc(params:, return_type: resolve_type_ref(type_ref.return_type, type_params:, type_param_constraints:))
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
if type_ref.is_a?(AST::DynType)
|
|
230
|
+
interface = resolve_interface_ref(type_ref.interface)
|
|
231
|
+
raise_sema_error("generic interface #{interface.name} requires type arguments") if interface.is_a?(GenericInterfaceBinding)
|
|
232
|
+
type_arguments = interface.type_arguments || []
|
|
233
|
+
type = Types::Dyn.new(interface, type_arguments)
|
|
234
|
+
type = Types::Registry.nullable(type) if type_ref.nullable
|
|
235
|
+
return type
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
if type_ref.is_a?(AST::TupleType)
|
|
239
|
+
names = []
|
|
240
|
+
element_types = []
|
|
241
|
+
type_ref.element_types.each do |et|
|
|
242
|
+
if et.is_a?(AST::Argument)
|
|
243
|
+
names << et.name
|
|
244
|
+
element_types << resolve_type_ref(et.value, type_params:, type_param_constraints:)
|
|
245
|
+
else
|
|
246
|
+
names << nil
|
|
247
|
+
element_types << resolve_type_ref(et, type_params:, type_param_constraints:)
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
has_named = names.any?
|
|
251
|
+
return Types::Registry.tuple(element_types, field_names: has_named ? names : nil)
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
parts = type_ref.name.parts
|
|
255
|
+
|
|
256
|
+
if type_ref.arguments.any?
|
|
257
|
+
name = parts.join(".")
|
|
258
|
+
arguments = type_ref.arguments.map { |argument| resolve_type_argument(argument.value, type_params:, type_param_constraints:) }
|
|
259
|
+
|
|
260
|
+
if name != "ref" && arguments.any? { |argument| contains_ref_type?(argument) && !stored_ref_supported_type?(argument) }
|
|
261
|
+
raise_sema_error("ref types cannot be nested inside #{name}", type_ref)
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
if name == "Task"
|
|
265
|
+
validate_generic_type!(name, arguments)
|
|
266
|
+
return Types::Registry.task(arguments[0])
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
if (generic_type = resolve_named_generic_type(parts))
|
|
270
|
+
begin
|
|
271
|
+
validate_generic_type_param_constraints!(generic_type, arguments, context: "type #{generic_type}", available_type_param_constraints: type_param_constraints)
|
|
272
|
+
return generic_type.instantiate(arguments)
|
|
273
|
+
rescue ArgumentError => error
|
|
274
|
+
raise_sema_error(error.message)
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
# Handle types with lifetime params only (no type params)
|
|
279
|
+
if arguments.all? { |a| a.is_a?(Types::LifetimeRef) }
|
|
280
|
+
type = @ctx.types[name]
|
|
281
|
+
if type.is_a?(Types::Struct) && type.lifetime_params&.any?
|
|
282
|
+
lifetime_args = arguments.select { |a| a.is_a?(Types::LifetimeRef) }.map(&:name)
|
|
283
|
+
if lifetime_args.to_set == type.lifetime_params.to_set
|
|
284
|
+
return type
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
validate_generic_type!(name, arguments)
|
|
290
|
+
return Types::Registry.span(arguments.first) if name == "span"
|
|
291
|
+
|
|
292
|
+
return Types::Registry.soa(arguments[0], count: arguments[1].value) if name == "SoA"
|
|
293
|
+
|
|
294
|
+
arguments = [type_ref.lifetime] + arguments if name == "ref" && type_ref.lifetime
|
|
295
|
+
return Types::Registry.generic_instance(name, arguments)
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
if parts.length == 1 && type_ref.lifetime
|
|
299
|
+
raise_sema_error("lifetime annotations are only valid on ref types, got #{type_ref.name}", type_ref)
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
if parts.length == 1
|
|
303
|
+
return type_params.fetch(parts.first) if type_params.key?(parts.first)
|
|
304
|
+
|
|
305
|
+
if nested_types && (type = nested_types[parts.first])
|
|
306
|
+
return type
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
if parts.first.start_with?("@")
|
|
310
|
+
raise_sema_error("unknown lifetime #{parts.first}", type_ref)
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
type = @ctx.types[parts.first]
|
|
314
|
+
unless type
|
|
315
|
+
type_names = @ctx.types.keys
|
|
316
|
+
suggestion = suggest_name(parts.first, type_names)
|
|
317
|
+
unless suggestion
|
|
318
|
+
suggestion = import_suggestion_for_type(parts.first)
|
|
319
|
+
end
|
|
320
|
+
raise_sema_error("unknown type #{parts.first}", type_ref, suggestion: suggestion ? "did you mean '#{suggestion}'?" : nil)
|
|
321
|
+
end
|
|
322
|
+
raise_sema_error("generic type #{parts.first} requires type arguments", type_ref) if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
|
|
323
|
+
|
|
324
|
+
return type
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
if parts.length >= 2
|
|
328
|
+
type = resolve_nested_type_ref(parts)
|
|
329
|
+
return type if type
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
if parts.length == 2 && @ctx.imports.key?(parts.first)
|
|
333
|
+
imported_module = @ctx.imports.fetch(parts.first)
|
|
334
|
+
type = imported_module.types[parts.last]
|
|
335
|
+
if imported_module.private_type?(parts.last)
|
|
336
|
+
raise_sema_error("#{parts.first}.#{parts.last} is private to module #{imported_module.name}", type_ref)
|
|
337
|
+
end
|
|
338
|
+
raise_sema_error("unknown type #{type_ref.name}", type_ref) unless type
|
|
339
|
+
raise_sema_error("generic type #{type_ref.name} requires type arguments", type_ref) if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
|
|
340
|
+
|
|
341
|
+
return type
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
if @compile_time_depth&.positive? && (ct_type = resolve_compile_time_type_ref(type_ref))
|
|
345
|
+
return ct_type
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
raise_sema_error("unknown type #{type_ref.name}", type_ref, suggestion: import_suggestion_for_type(type_ref.name))
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
# Resolves a bare dotted reflection type expression such as `field.type`
|
|
352
|
+
# (where `field` is a compile-time `field_handle` bound in scope) to the
|
|
353
|
+
# concrete `Types::Base` it denotes. Returns nil when the type_ref is not a
|
|
354
|
+
# compile-time type expression resolvable in the current scopes. Only the
|
|
355
|
+
# plain `<local>.member` form is supported (no calls/indexing/type args).
|
|
356
|
+
def resolve_compile_time_type_ref(type_ref)
|
|
357
|
+
return nil unless @type_resolution_scopes
|
|
358
|
+
return nil if type_ref.arguments.any? || type_ref.nullable
|
|
359
|
+
|
|
360
|
+
parts = type_ref.name.parts
|
|
361
|
+
return nil unless parts.length >= 2
|
|
362
|
+
|
|
363
|
+
binding = lookup_value(parts.first, @type_resolution_scopes)
|
|
364
|
+
return nil unless binding && !binding.const_value.nil?
|
|
365
|
+
|
|
366
|
+
expression = AST.build_chain_from_parts(parts)
|
|
367
|
+
return nil unless expression
|
|
368
|
+
|
|
369
|
+
value = evaluate_compile_time_const_value(expression, scopes: @type_resolution_scopes)
|
|
370
|
+
value.is_a?(Types::Base) ? value : nil
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
def resolve_type_argument(argument, type_params: current_type_params, type_param_constraints: current_type_param_constraints)
|
|
374
|
+
case argument
|
|
375
|
+
when AST::TypeRef
|
|
376
|
+
resolve_type_argument_ref(argument, type_params:, type_param_constraints:)
|
|
377
|
+
when AST::FunctionType, AST::ProcType
|
|
378
|
+
resolve_type_ref(argument, type_params:, type_param_constraints:)
|
|
379
|
+
when AST::IntegerLiteral, AST::FloatLiteral
|
|
380
|
+
Types::LiteralTypeArg.new(argument.value)
|
|
381
|
+
else
|
|
382
|
+
raise_sema_error("unsupported type argument #{argument.class.name}")
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
def resolve_type_argument_ref(type_ref, type_params:, type_param_constraints:)
|
|
387
|
+
return resolve_type_ref(type_ref, type_params:, type_param_constraints:) unless literal_type_argument_name_candidate?(type_ref)
|
|
388
|
+
|
|
389
|
+
resolve_type_ref(type_ref, type_params:, type_param_constraints:)
|
|
390
|
+
rescue SemanticError => error
|
|
391
|
+
literal_type_argument = resolve_named_literal_type_argument(type_ref)
|
|
392
|
+
return literal_type_argument if literal_type_argument
|
|
393
|
+
|
|
394
|
+
raise error
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
def literal_type_argument_name_candidate?(type_ref)
|
|
398
|
+
type_ref.arguments.empty? && !type_ref.nullable
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
def resolve_named_literal_type_argument(type_ref)
|
|
402
|
+
value = case type_ref.name.parts.length
|
|
403
|
+
when 1
|
|
404
|
+
resolve_current_module_const_value(type_ref.name.parts.first)
|
|
405
|
+
when 2
|
|
406
|
+
resolve_imported_module_const_value(type_ref.name.parts.first, type_ref.name.parts.last)
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
return unless value.is_a?(Integer) || value.is_a?(Float)
|
|
410
|
+
|
|
411
|
+
Types::LiteralTypeArg.new(value)
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
def resolve_current_module_const_value(name)
|
|
415
|
+
binding = @ctx.top_level_values[name]
|
|
416
|
+
return unless binding&.kind == :const
|
|
417
|
+
|
|
418
|
+
evaluate_top_level_const_value(name)
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
def top_level_function(name)
|
|
422
|
+
@ctx.top_level_functions[name]
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
def resolve_imported_module_const_value(import_name, value_name)
|
|
426
|
+
imported_module = @ctx.imports[import_name]
|
|
427
|
+
return unless imported_module
|
|
428
|
+
if imported_module.private_value?(value_name)
|
|
429
|
+
raise_sema_error("#{import_name}.#{value_name} is private to module #{imported_module.name}")
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
binding = imported_module.values[value_name]
|
|
433
|
+
return unless binding&.kind == :const
|
|
434
|
+
|
|
435
|
+
binding.const_value
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
def resolve_enum_member_const_value(receiver_type, member_name, local_enum_type: nil, local_member_values: nil)
|
|
439
|
+
return unless receiver_type.is_a?(Types::EnumBase)
|
|
440
|
+
return unless receiver_type.member(member_name)
|
|
441
|
+
|
|
442
|
+
if local_enum_type && receiver_type == local_enum_type && local_member_values&.key?(member_name)
|
|
443
|
+
return local_member_values[member_name]
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
receiver_type.member_value(member_name)
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
def ensure_assignable!(actual_type, expected_type, message, expression: nil, scopes: nil, external_numeric: false, external_pointer_null: false, contextual_int_to_float: false, line: nil, column: nil)
|
|
450
|
+
line ||= source_line(expression)
|
|
451
|
+
column ||= source_column(expression)
|
|
452
|
+
|
|
453
|
+
unless types_compatible?(actual_type, expected_type, expression:, scopes:, external_numeric:, external_pointer_null:, contextual_int_to_float:)
|
|
454
|
+
suggestion = explicit_cast_suggestion(actual_type, expected_type)
|
|
455
|
+
raise SemanticError.new(message, line:, column:, path: @path, suggestion:)
|
|
456
|
+
end
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
def explicit_cast_suggestion(actual_type, expected_type)
|
|
460
|
+
if expected_type.is_a?(Types::Span) && array_type?(actual_type) &&
|
|
461
|
+
array_element_type(actual_type) == expected_type.element_type
|
|
462
|
+
return "a span is a mutable view; the array must be a mutable addressable value — bind it with `var` (a `let` array does not coerce)"
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
if castable_primitive?(actual_type) && castable_primitive?(expected_type)
|
|
466
|
+
return nil if actual_type == expected_type
|
|
467
|
+
"use an explicit cast: `#{expected_type}<-(value)`"
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
if actual_type.is_a?(Types::Nullable) && expected_type.is_a?(Types::Nullable)
|
|
471
|
+
explicit_cast_suggestion(actual_type.base, expected_type.base)
|
|
472
|
+
else
|
|
473
|
+
nil
|
|
474
|
+
end
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
def castable_primitive?(type)
|
|
478
|
+
return castable_primitive?(type.base) if type.is_a?(Types::Nullable)
|
|
479
|
+
|
|
480
|
+
type.is_a?(Types::Primitive) || type.is_a?(Types::Enum) || type.is_a?(Types::Flags)
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
def ensure_argument_assignable!(actual_type, expected_type, external:, message:, expression: nil, scopes: nil)
|
|
484
|
+
line = source_line(expression)
|
|
485
|
+
column = source_column(expression)
|
|
486
|
+
unless argument_types_compatible?(actual_type, expected_type, external:, expression:, scopes:)
|
|
487
|
+
suggestion = explicit_cast_suggestion(actual_type, expected_type)
|
|
488
|
+
raise SemanticError.new(message, line:, column:, path: @path, suggestion:)
|
|
489
|
+
end
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
def with_error_node(node)
|
|
493
|
+
@error_node_stack << node
|
|
494
|
+
yield
|
|
495
|
+
ensure
|
|
496
|
+
@error_node_stack.pop
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
def current_error_node
|
|
500
|
+
@error_node_stack.reverse_each.find { |node| !node.nil? }
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
def raise_sema_error(message, node = nil, line: nil, column: nil, length: nil, suggestion: nil)
|
|
504
|
+
target = node || current_error_node
|
|
505
|
+
line ||= source_line(target)
|
|
506
|
+
column ||= source_column(target)
|
|
507
|
+
length ||= source_length(target)
|
|
508
|
+
raise SemanticError.new(message, line:, column:, length:, path: @path, suggestion:)
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
def source_line(node)
|
|
512
|
+
return nil unless node
|
|
513
|
+
return node.line if node.respond_to?(:line) && node.line
|
|
514
|
+
|
|
515
|
+
case node
|
|
516
|
+
when AST::MemberAccess then source_line(node.receiver)
|
|
517
|
+
when AST::IndexAccess then source_line(node.receiver) || source_line(node.index)
|
|
518
|
+
when AST::Specialization then source_line(node.callee)
|
|
519
|
+
when AST::Call then source_line(node.callee) || node.arguments.filter_map { |argument| source_line(argument.value) }.first
|
|
520
|
+
when AST::Argument then source_line(node.value)
|
|
521
|
+
when AST::UnaryOp then source_line(node.operand)
|
|
522
|
+
when AST::BinaryOp then source_line(node.left) || source_line(node.right)
|
|
523
|
+
when AST::IfExpr then source_line(node.condition) || source_line(node.then_expression) || source_line(node.else_expression)
|
|
524
|
+
when AST::MatchExpr then source_line(node.expression) || node.arms.filter_map { |arm| source_line(arm.pattern) || source_line(arm.value) }.first
|
|
525
|
+
when AST::AwaitExpr then source_line(node.expression)
|
|
526
|
+
when AST::FormatExprPart then source_line(node.expression)
|
|
527
|
+
when AST::PrefixCast then source_line(node.target_type)
|
|
528
|
+
else nil
|
|
529
|
+
end
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
def source_length(node)
|
|
533
|
+
return nil unless node
|
|
534
|
+
return node.length if node.respond_to?(:length) && node.length
|
|
535
|
+
return node.name.to_s.length if node.respond_to?(:name) && node.name
|
|
536
|
+
|
|
537
|
+
case node
|
|
538
|
+
when AST::Identifier then node.name.to_s.length
|
|
539
|
+
when AST::MemberAccess then node.member.to_s.length
|
|
540
|
+
when AST::Assignment then source_length(node.target) || source_length(node.value)
|
|
541
|
+
when AST::ExpressionStmt then source_length(node.expression)
|
|
542
|
+
when AST::StaticAssert then source_length(node.condition)
|
|
543
|
+
when AST::IfStmt
|
|
544
|
+
node.branches.filter_map { |branch| branch.length || source_length(branch.condition) }.first
|
|
545
|
+
else
|
|
546
|
+
nil
|
|
547
|
+
end
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
def source_column(node)
|
|
551
|
+
return nil unless node
|
|
552
|
+
return node.column if node.respond_to?(:column) && node.column
|
|
553
|
+
|
|
554
|
+
case node
|
|
555
|
+
when AST::MemberAccess then source_column(node.receiver)
|
|
556
|
+
when AST::IndexAccess then source_column(node.receiver) || source_column(node.index)
|
|
557
|
+
when AST::Specialization then source_column(node.callee)
|
|
558
|
+
when AST::Call then source_column(node.callee) || node.arguments.filter_map { |argument| source_column(argument.value) }.first
|
|
559
|
+
when AST::Argument then source_column(node.value)
|
|
560
|
+
when AST::UnaryOp then source_column(node.operand)
|
|
561
|
+
when AST::BinaryOp then source_column(node.left) || source_column(node.right)
|
|
562
|
+
when AST::IfExpr then source_column(node.condition) || source_column(node.then_expression) || source_column(node.else_expression)
|
|
563
|
+
when AST::MatchExpr then source_column(node.expression) || node.arms.filter_map { |arm| source_column(arm.pattern) || source_column(arm.value) }.first
|
|
564
|
+
when AST::AwaitExpr then source_column(node.expression)
|
|
565
|
+
when AST::FormatExprPart then source_column(node.expression)
|
|
566
|
+
when AST::PrefixCast then source_column(node.target_type)
|
|
567
|
+
when AST::Assignment then source_column(node.target) || source_column(node.value)
|
|
568
|
+
when AST::ExpressionStmt then source_column(node.expression)
|
|
569
|
+
when AST::StaticAssert then source_column(node.condition)
|
|
570
|
+
when AST::IfStmt then node.branches.filter_map { |branch| branch.column || source_column(branch.condition) }.first || node.else_column
|
|
571
|
+
else nil
|
|
572
|
+
end
|
|
573
|
+
end
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
def span_type?(type)
|
|
577
|
+
type.is_a?(Types::Span)
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
def string_view_type?(type)
|
|
581
|
+
type.is_a?(Types::StringView)
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
def infer_layout_query_type(type_ref, context:)
|
|
585
|
+
type = resolve_type_ref(type_ref)
|
|
586
|
+
return type if sized_layout_type?(type)
|
|
587
|
+
|
|
588
|
+
raise_sema_error("#{context} requires a concrete sized type, got #{type_ref}")
|
|
589
|
+
end
|
|
590
|
+
|
|
591
|
+
def check_layout_type_via_ct(type_ref, context:, scopes:)
|
|
592
|
+
return false unless scopes && type_ref.name.parts.length >= 1
|
|
593
|
+
|
|
594
|
+
first_part = type_ref.name.parts.first
|
|
595
|
+
binding = lookup_value(first_part, scopes)
|
|
596
|
+
return false unless binding && !binding.const_value.nil?
|
|
597
|
+
|
|
598
|
+
expression = AST.build_chain_from_parts(type_ref.name.parts)
|
|
599
|
+
return false unless expression
|
|
600
|
+
|
|
601
|
+
ct_value = evaluate_compile_time_const_value(expression, scopes:)
|
|
602
|
+
if ct_value.is_a?(Types::Struct) || ct_value.is_a?(Types::Primitive) ||
|
|
603
|
+
ct_value.is_a?(Types::Union) || ct_value.is_a?(Types::Nullable) ||
|
|
604
|
+
ct_value.is_a?(Types::StructInstance)
|
|
605
|
+
if sized_layout_type?(ct_value)
|
|
606
|
+
return true
|
|
607
|
+
end
|
|
608
|
+
end
|
|
609
|
+
|
|
610
|
+
false
|
|
611
|
+
end
|
|
612
|
+
|
|
613
|
+
|
|
614
|
+
|
|
615
|
+
|
|
616
|
+
def resolve_and_store_offset(expression, scopes:)
|
|
617
|
+
type = resolve_type_ref(expression.type)
|
|
618
|
+
return unless layout_aggregate_type?(type)
|
|
619
|
+
|
|
620
|
+
binding = lookup_value(expression.field, scopes)
|
|
621
|
+
return unless binding && binding.const_value.is_a?(Types::FieldHandle)
|
|
622
|
+
|
|
623
|
+
offset = CompileTime::Layout.offset_of(type, binding.const_value.field_name)
|
|
624
|
+
return unless offset
|
|
625
|
+
|
|
626
|
+
@const_values[@ctx.ast.node_ids[expression.object_id]] = offset
|
|
627
|
+
end
|
|
628
|
+
|
|
629
|
+
def infer_offsetof_type(type_ref, field_name, scopes: nil)
|
|
630
|
+
type = resolve_type_ref(type_ref)
|
|
631
|
+
unless layout_aggregate_type?(type)
|
|
632
|
+
raise_sema_error("offset_of requires a struct, union, span, or str type, got #{type}")
|
|
633
|
+
end
|
|
634
|
+
|
|
635
|
+
field_type = type.field(field_name)
|
|
636
|
+
return type if field_type
|
|
637
|
+
|
|
638
|
+
if scopes
|
|
639
|
+
binding = lookup_value(field_name, scopes)
|
|
640
|
+
if binding && binding.storage_type.is_a?(Types::ReflectionHandleType) && binding.storage_type.name == "field_handle"
|
|
641
|
+
return type
|
|
642
|
+
end
|
|
643
|
+
end
|
|
644
|
+
|
|
645
|
+
raise_sema_error("unknown field #{type}.#{field_name}")
|
|
646
|
+
end
|
|
647
|
+
|
|
648
|
+
def sized_layout_type?(type)
|
|
649
|
+
case type
|
|
650
|
+
when Types::Primitive, Types::Struct, Types::StructInstance, Types::Union, Types::Enum, Types::Flags, Types::Variant, Types::Span, Types::StringView, Types::Task, Types::Event, Types::Subscription
|
|
651
|
+
true
|
|
652
|
+
when Types::Nullable
|
|
653
|
+
true
|
|
654
|
+
when Types::GenericInstance
|
|
655
|
+
pointer_type?(type) || array_type?(type) || str_buffer_type?(type)
|
|
656
|
+
else
|
|
657
|
+
false
|
|
658
|
+
end
|
|
659
|
+
end
|
|
660
|
+
|
|
661
|
+
def reinterpretable_type?(type)
|
|
662
|
+
return false if array_type?(type)
|
|
663
|
+
return false if type.is_a?(Types::Primitive) && type.void?
|
|
664
|
+
|
|
665
|
+
sized_layout_type?(type)
|
|
666
|
+
end
|
|
667
|
+
|
|
668
|
+
def zero_initializable_type?(type, operation: "zero")
|
|
669
|
+
return true if type.is_a?(Types::Primitive) && !type.void?
|
|
670
|
+
return true if type.is_a?(Types::Nullable)
|
|
671
|
+
return true if type.is_a?(Types::EnumBase)
|
|
672
|
+
return true if span_type?(type)
|
|
673
|
+
return true if string_view_type?(type)
|
|
674
|
+
return true if task_type?(type)
|
|
675
|
+
return true if event_type?(type)
|
|
676
|
+
return true if subscription_type?(type)
|
|
677
|
+
return true if type.is_a?(Types::Struct)
|
|
678
|
+
return true if type.is_a?(Types::Variant)
|
|
679
|
+
return true if pointer_type?(type)
|
|
680
|
+
return true if type.is_a?(Types::Opaque) && !type.external
|
|
681
|
+
return true if array_type?(type)
|
|
682
|
+
return true if str_buffer_type?(type)
|
|
683
|
+
return true if vector_type?(type)
|
|
684
|
+
return true if matrix_type?(type)
|
|
685
|
+
return true if quaternion_type?(type)
|
|
686
|
+
return true if soa_type?(type)
|
|
687
|
+
return true if atomic_type?(type)
|
|
688
|
+
|
|
689
|
+
raise_sema_error("#{operation} does not support type #{type}")
|
|
690
|
+
end
|
|
691
|
+
|
|
692
|
+
def layout_aggregate_type?(type)
|
|
693
|
+
type.respond_to?(:field) && !type.is_a?(Types::Opaque) && !type.is_a?(Types::EnumBase)
|
|
694
|
+
end
|
|
695
|
+
|
|
696
|
+
def power_of_two?(value)
|
|
697
|
+
(value & (value - 1)).zero?
|
|
698
|
+
end
|
|
699
|
+
|
|
700
|
+
def aggregate_type?(type)
|
|
701
|
+
type.is_a?(Types::Struct) || type.is_a?(Types::Tuple) || span_type?(type) || string_view_type?(type) || task_type?(type) || vector_type?(type) || matrix_type?(type) || quaternion_type?(type)
|
|
702
|
+
end
|
|
703
|
+
|
|
704
|
+
def vector_type?(type)
|
|
705
|
+
type.is_a?(Types::Vector)
|
|
706
|
+
end
|
|
707
|
+
|
|
708
|
+
def matrix_type?(type)
|
|
709
|
+
type.is_a?(Types::Matrix)
|
|
710
|
+
end
|
|
711
|
+
|
|
712
|
+
def quaternion_type?(type)
|
|
713
|
+
type.is_a?(Types::Quaternion)
|
|
714
|
+
end
|
|
715
|
+
|
|
716
|
+
def soa_type?(type)
|
|
717
|
+
type.is_a?(Types::SoA)
|
|
718
|
+
end
|
|
719
|
+
|
|
720
|
+
def array_type?(type)
|
|
721
|
+
type.is_a?(Types::GenericInstance) && type.name == "array" && type.arguments.length == 2 &&
|
|
722
|
+
!type.arguments.first.is_a?(Types::LiteralTypeArg) && type.arguments[1].is_a?(Types::LiteralTypeArg)
|
|
723
|
+
end
|
|
724
|
+
|
|
725
|
+
def array_element_type(type)
|
|
726
|
+
return unless array_type?(type)
|
|
727
|
+
|
|
728
|
+
type.arguments.first
|
|
729
|
+
end
|
|
730
|
+
|
|
731
|
+
def array_length(type)
|
|
732
|
+
return unless array_type?(type)
|
|
733
|
+
|
|
734
|
+
type.arguments[1].value
|
|
735
|
+
end
|
|
736
|
+
|
|
737
|
+
def char_array_text_type?(type)
|
|
738
|
+
array_type?(type) && array_element_type(type) == @ctx.types.fetch("char")
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
def str_buffer_type?(type)
|
|
742
|
+
type.is_a?(Types::GenericInstance) && type.name == "str_buffer" && type.arguments.length == 1 &&
|
|
743
|
+
generic_integer_type_argument?(type.arguments.first)
|
|
744
|
+
end
|
|
745
|
+
|
|
746
|
+
def event_type?(type)
|
|
747
|
+
type.is_a?(Types::Event)
|
|
748
|
+
end
|
|
749
|
+
|
|
750
|
+
def atomic_type?(type)
|
|
751
|
+
type.is_a?(Types::GenericInstance) && type.name == "atomic" && type.arguments.length == 1
|
|
752
|
+
end
|
|
753
|
+
|
|
754
|
+
def atomic_element_type(type)
|
|
755
|
+
type.arguments.first
|
|
756
|
+
end
|
|
757
|
+
|
|
758
|
+
def subscription_type?(type)
|
|
759
|
+
type.is_a?(Types::Subscription)
|
|
760
|
+
end
|
|
761
|
+
|
|
762
|
+
def event_carrier_type?(type)
|
|
763
|
+
case type
|
|
764
|
+
when Types::StructInstance
|
|
765
|
+
type.definition.respond_to?(:has_events?) && type.definition.has_events?
|
|
766
|
+
when Types::Struct
|
|
767
|
+
type.respond_to?(:has_events?) && type.has_events?
|
|
768
|
+
else
|
|
769
|
+
false
|
|
770
|
+
end
|
|
771
|
+
end
|
|
772
|
+
|
|
773
|
+
def noncopyable_event_storage_type?(type)
|
|
774
|
+
event_type?(type) || event_carrier_type?(type)
|
|
775
|
+
end
|
|
776
|
+
|
|
777
|
+
def str_buffer_capacity(type)
|
|
778
|
+
type.arguments.first.value
|
|
779
|
+
end
|
|
780
|
+
|
|
781
|
+
def integer_type_argument?(argument)
|
|
782
|
+
argument.is_a?(Types::LiteralTypeArg) && argument.value.is_a?(Integer)
|
|
783
|
+
end
|
|
784
|
+
|
|
785
|
+
def generic_integer_type_argument?(argument)
|
|
786
|
+
integer_type_argument?(argument) || argument.is_a?(Types::TypeVar)
|
|
787
|
+
end
|
|
788
|
+
|
|
789
|
+
def pointer_to(type)
|
|
790
|
+
Types.pointer_to(type)
|
|
791
|
+
end
|
|
792
|
+
|
|
793
|
+
def contains_type_var?(type)
|
|
794
|
+
super
|
|
795
|
+
end
|
|
796
|
+
|
|
797
|
+
def resolve_nested_type_ref(parts)
|
|
798
|
+
current = @ctx.types[parts.first]
|
|
799
|
+
return nil unless current.is_a?(Types::Struct) || current.is_a?(Types::GenericStructDefinition)
|
|
800
|
+
parts[1..].each do |part|
|
|
801
|
+
nested = current.respond_to?(:nested_types) ? current.nested_types[part] : nil
|
|
802
|
+
return nil unless nested
|
|
803
|
+
current = nested
|
|
804
|
+
end
|
|
805
|
+
current
|
|
806
|
+
end
|
|
807
|
+
|
|
808
|
+
def resolve_named_generic_type(parts)
|
|
809
|
+
if parts.length == 1
|
|
810
|
+
type = @ctx.types[parts.first]
|
|
811
|
+
return type if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
|
|
812
|
+
elsif parts.length >= 2
|
|
813
|
+
type = resolve_nested_type_ref(parts)
|
|
814
|
+
return type if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
|
|
815
|
+
if @ctx.imports.key?(parts.first)
|
|
816
|
+
type = @ctx.imports.fetch(parts.first).types[parts.last]
|
|
817
|
+
return type if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
|
|
818
|
+
end
|
|
819
|
+
end
|
|
820
|
+
|
|
821
|
+
nil
|
|
822
|
+
end
|
|
823
|
+
|
|
824
|
+
|
|
825
|
+
|
|
826
|
+
def aggregate_display_name(type)
|
|
827
|
+
type.is_a?(Types::StructInstance) ? type.to_s : type.name
|
|
828
|
+
end
|
|
829
|
+
|
|
830
|
+
def validate_generic_type!(name, arguments)
|
|
831
|
+
super(name, arguments) { |msg| raise_sema_error(msg) }
|
|
832
|
+
end
|
|
833
|
+
|
|
834
|
+
def integer_type?(type)
|
|
835
|
+
type.is_a?(Types::Primitive) && type.integer?
|
|
836
|
+
end
|
|
837
|
+
|
|
838
|
+
def struct_instance_type?(type)
|
|
839
|
+
type.is_a?(Types::Struct) || type.is_a?(Types::Variant)
|
|
840
|
+
end
|
|
841
|
+
|
|
842
|
+
def c_natively_equality_comparable_type?(type)
|
|
843
|
+
return true if type.is_a?(Types::Primitive)
|
|
844
|
+
return true if type.is_a?(Types::EnumBase)
|
|
845
|
+
return true if type.is_a?(Types::Opaque)
|
|
846
|
+
return true if type.is_a?(Types::Nullable)
|
|
847
|
+
return true if type.is_a?(Types::Null)
|
|
848
|
+
return true if type.is_a?(Types::Function)
|
|
849
|
+
return true if type.is_a?(Types::Error)
|
|
850
|
+
return true if type.is_a?(Types::StringView)
|
|
851
|
+
return true if pointer_type?(type)
|
|
852
|
+
return true if ref_type?(type)
|
|
853
|
+
return true if type.is_a?(Types::Variant)
|
|
854
|
+
return true if type.is_a?(Types::VariantArmPayload)
|
|
855
|
+
|
|
856
|
+
false
|
|
857
|
+
end
|
|
858
|
+
|
|
859
|
+
def collection_loop_type(type)
|
|
860
|
+
super
|
|
861
|
+
end
|
|
862
|
+
|
|
863
|
+
def collection_loop_binding_type(iterable_type, element_type)
|
|
864
|
+
super
|
|
865
|
+
end
|
|
866
|
+
|
|
867
|
+
def collection_loop_ref_element_type?(type)
|
|
868
|
+
super
|
|
869
|
+
end
|
|
870
|
+
|
|
871
|
+
def iterator_loop_type(type)
|
|
872
|
+
type = referenced_type(type) if ref_type?(type)
|
|
873
|
+
iter_method = lookup_method(type, "iter")
|
|
874
|
+
return nil unless iter_method
|
|
875
|
+
|
|
876
|
+
iter_method = instantiate_function_binding_with_receiver(iter_method, [], receiver_type: type) if iter_method.type_params.any?
|
|
877
|
+
|
|
878
|
+
unless iter_method.type.params.empty?
|
|
879
|
+
raise_sema_error("for iterator #{type}.iter expects 0 arguments")
|
|
880
|
+
end
|
|
881
|
+
if iter_method.type.receiver_editable
|
|
882
|
+
raise_sema_error("for iterator #{type}.iter cannot be an editable method")
|
|
883
|
+
end
|
|
884
|
+
|
|
885
|
+
iterator_type = iter_method.type.return_type
|
|
886
|
+
next_method = lookup_method(iterator_type, "next")
|
|
887
|
+
raise_sema_error("for iterator #{iterator_type} must define next()") unless next_method
|
|
888
|
+
next_method = instantiate_function_binding_with_receiver(next_method, [], receiver_type: iterator_type) if next_method.type_params.any?
|
|
889
|
+
unless next_method.type.params.empty?
|
|
890
|
+
raise_sema_error("for iterator #{iterator_type}.next expects 0 arguments")
|
|
891
|
+
end
|
|
892
|
+
|
|
893
|
+
next_type = next_method.type.return_type
|
|
894
|
+
if next_type.is_a?(Types::Nullable) && typed_null_target_type?(next_type.base)
|
|
895
|
+
return next_type.base
|
|
896
|
+
end
|
|
897
|
+
|
|
898
|
+
if next_type == @ctx.types.fetch("bool")
|
|
899
|
+
current_method = lookup_method(iterator_type, "current")
|
|
900
|
+
raise_sema_error("for iterator #{iterator_type} must define current() when next() returns bool") unless current_method
|
|
901
|
+
current_method = instantiate_function_binding_with_receiver(current_method, [], receiver_type: iterator_type) if current_method.type_params.any?
|
|
902
|
+
unless current_method.type.params.empty?
|
|
903
|
+
raise_sema_error("for iterator #{iterator_type}.current expects 0 arguments")
|
|
904
|
+
end
|
|
905
|
+
raise_sema_error("for iterator #{iterator_type}.current cannot return void") if current_method.type.return_type == @ctx.types.fetch("void")
|
|
906
|
+
|
|
907
|
+
return current_method.type.return_type
|
|
908
|
+
end
|
|
909
|
+
|
|
910
|
+
raise_sema_error("for iterator #{iterator_type}.next must return bool or a nullable pointer-like item, got #{next_type}")
|
|
911
|
+
end
|
|
912
|
+
|
|
913
|
+
def string_like_type?(type)
|
|
914
|
+
type == @ctx.types.fetch("str") || type == @ctx.types.fetch("cstr")
|
|
915
|
+
end
|
|
916
|
+
|
|
917
|
+
def infer_index_result_type(receiver_type, index_type)
|
|
918
|
+
raise_sema_error("index must be an integer type, got #{index_type}") unless integer_type?(index_type)
|
|
919
|
+
|
|
920
|
+
if array_type?(receiver_type)
|
|
921
|
+
return array_element_type(receiver_type)
|
|
922
|
+
end
|
|
923
|
+
|
|
924
|
+
if span_type?(receiver_type)
|
|
925
|
+
return receiver_type.element_type
|
|
926
|
+
end
|
|
927
|
+
|
|
928
|
+
if soa_type?(receiver_type)
|
|
929
|
+
return receiver_type.element_type
|
|
930
|
+
end
|
|
931
|
+
|
|
932
|
+
if pointer_type?(receiver_type)
|
|
933
|
+
require_unsafe!("pointer indexing requires unsafe") unless own_type?(receiver_type)
|
|
934
|
+
|
|
935
|
+
return pointee_type(receiver_type)
|
|
936
|
+
end
|
|
937
|
+
|
|
938
|
+
raise_sema_error("cannot index #{receiver_type}")
|
|
939
|
+
end
|
|
940
|
+
|
|
941
|
+
def addressable_storage_expression?(expression, scopes:)
|
|
942
|
+
case expression
|
|
943
|
+
when AST::Identifier
|
|
944
|
+
true
|
|
945
|
+
when AST::MemberAccess, AST::IndexAccess
|
|
946
|
+
addressable_storage_expression?(expression.receiver, scopes:)
|
|
947
|
+
when AST::Call
|
|
948
|
+
return false unless expression.arguments.length == 1 && expression.arguments.first.name.nil?
|
|
949
|
+
|
|
950
|
+
read_call?(expression) && ref_type?(infer_expression(expression.arguments.first.value, scopes:))
|
|
951
|
+
else
|
|
952
|
+
false
|
|
953
|
+
end
|
|
954
|
+
end
|
|
955
|
+
|
|
956
|
+
def match_member_name(expression, enum_type)
|
|
957
|
+
return unless expression.is_a?(AST::MemberAccess)
|
|
958
|
+
|
|
959
|
+
receiver_type = resolve_type_expression(expression.receiver)
|
|
960
|
+
return unless receiver_type == enum_type
|
|
961
|
+
return expression.member if enum_type.member(expression.member)
|
|
962
|
+
|
|
963
|
+
nil
|
|
964
|
+
end
|
|
965
|
+
|
|
966
|
+
def resolve_type_expression(expression)
|
|
967
|
+
case expression
|
|
968
|
+
when AST::Identifier
|
|
969
|
+
return current_type_params[expression.name] if current_type_params.key?(expression.name)
|
|
970
|
+
|
|
971
|
+
@ctx.types[expression.name]
|
|
972
|
+
when AST::MemberAccess
|
|
973
|
+
return nil unless expression.receiver.is_a?(AST::Identifier)
|
|
974
|
+
|
|
975
|
+
if @ctx.imports.key?(expression.receiver.name)
|
|
976
|
+
imported_module = @ctx.imports.fetch(expression.receiver.name)
|
|
977
|
+
if imported_module.private_type?(expression.member)
|
|
978
|
+
raise_sema_error("#{expression.receiver.name}.#{expression.member} is private to module #{imported_module.name}")
|
|
979
|
+
end
|
|
980
|
+
|
|
981
|
+
return imported_module.types[expression.member]
|
|
982
|
+
end
|
|
983
|
+
|
|
984
|
+
parent_type = @ctx.types[expression.receiver.name]
|
|
985
|
+
return parent_type.nested_types[expression.member] if parent_type.respond_to?(:nested_types) && parent_type.nested_types.key?(expression.member)
|
|
986
|
+
|
|
987
|
+
nil
|
|
988
|
+
when AST::Specialization
|
|
989
|
+
type_ref = type_ref_from_specialization(expression)
|
|
990
|
+
return nil unless type_ref
|
|
991
|
+
|
|
992
|
+
resolve_type_ref(type_ref)
|
|
993
|
+
end
|
|
994
|
+
end
|
|
995
|
+
|
|
996
|
+
def imported_module_with_private_method(receiver_type, method_name)
|
|
997
|
+
imported_module = imported_module_with_private_method_local(receiver_type, method_name)
|
|
998
|
+
return imported_module if imported_module
|
|
999
|
+
|
|
1000
|
+
fallback_owner = specialization_lookup_owner
|
|
1001
|
+
return nil unless fallback_owner
|
|
1002
|
+
|
|
1003
|
+
fallback_owner.send(:imported_module_with_private_method_local, receiver_type, method_name)
|
|
1004
|
+
end
|
|
1005
|
+
|
|
1006
|
+
def imported_module_with_private_method_local(receiver_type, method_name)
|
|
1007
|
+
@ctx.imports.each_value do |module_binding|
|
|
1008
|
+
return module_binding if module_binding.private_method?(receiver_type, method_name)
|
|
1009
|
+
end
|
|
1010
|
+
|
|
1011
|
+
nil
|
|
1012
|
+
end
|
|
1013
|
+
|
|
1014
|
+
|
|
1015
|
+
|
|
1016
|
+
def resolve_methods_receiver_target(type_ref)
|
|
1017
|
+
if type_ref.is_a?(AST::TypeRef)
|
|
1018
|
+
generic_type = resolve_named_generic_type(type_ref.name.parts)
|
|
1019
|
+
if generic_type.is_a?(Types::GenericStructDefinition) || generic_type.is_a?(Types::GenericVariantDefinition)
|
|
1020
|
+
receiver_type_param_names = validate_methods_receiver_type_arguments!(type_ref, generic_type)
|
|
1021
|
+
receiver_type_params = receiver_type_param_names.to_h { |name| [name, Types::TypeVar.new(name)] }
|
|
1022
|
+
receiver_type_param_constraints = generic_type.respond_to?(:type_param_constraints) ? generic_type.type_param_constraints : {}
|
|
1023
|
+
receiver_type = resolve_type_ref(type_ref, type_params: receiver_type_params, type_param_constraints: receiver_type_param_constraints)
|
|
1024
|
+
return [generic_type, receiver_type, receiver_type_param_names, receiver_type_param_constraints]
|
|
1025
|
+
end
|
|
1026
|
+
|
|
1027
|
+
begin
|
|
1028
|
+
receiver_type = resolve_type_ref(type_ref)
|
|
1029
|
+
unless receiver_type.is_a?(Types::Struct) || receiver_type.is_a?(Types::StructInstance) || receiver_type.is_a?(Types::Opaque) || receiver_type.is_a?(Types::GenericInstance) || receiver_type.is_a?(Types::Nullable) || receiver_type.is_a?(Types::StringView) || receiver_type.is_a?(Types::Primitive) || receiver_type.is_a?(Types::Variant) || receiver_type.is_a?(Types::VariantInstance) || vector_type?(receiver_type) || matrix_type?(receiver_type) || quaternion_type?(receiver_type)
|
|
1030
|
+
raise_sema_error("extending target #{type_ref} must be a struct, opaque, nullable/generic receiver, variant, or str")
|
|
1031
|
+
end
|
|
1032
|
+
|
|
1033
|
+
return [receiver_type, receiver_type, [], {}]
|
|
1034
|
+
rescue MilkTea::SemanticError => error
|
|
1035
|
+
receiver_type_param_names = methods_receiver_type_argument_names!(type_ref)
|
|
1036
|
+
raise error if receiver_type_param_names.empty?
|
|
1037
|
+
|
|
1038
|
+
receiver_type_params = receiver_type_param_names.to_h { |name| [name, Types::TypeVar.new(name)] }
|
|
1039
|
+
receiver_type = resolve_type_ref(type_ref, type_params: receiver_type_params)
|
|
1040
|
+
return [method_dispatch_receiver_type(receiver_type), receiver_type, receiver_type_param_names, {}]
|
|
1041
|
+
end
|
|
1042
|
+
end
|
|
1043
|
+
|
|
1044
|
+
receiver_type = resolve_type_ref(type_ref)
|
|
1045
|
+
unless receiver_type.is_a?(Types::Struct) || receiver_type.is_a?(Types::StructInstance) || receiver_type.is_a?(Types::Opaque) || receiver_type.is_a?(Types::GenericInstance) || receiver_type.is_a?(Types::Nullable) || receiver_type.is_a?(Types::StringView) || receiver_type.is_a?(Types::Primitive) || receiver_type.is_a?(Types::Variant) || receiver_type.is_a?(Types::VariantInstance) || vector_type?(receiver_type) || matrix_type?(receiver_type) || quaternion_type?(receiver_type)
|
|
1046
|
+
raise_sema_error("extending target #{type_ref} must be a struct, opaque, nullable/generic receiver, variant, or str")
|
|
1047
|
+
end
|
|
1048
|
+
|
|
1049
|
+
[receiver_type, receiver_type, [], {}]
|
|
1050
|
+
end
|
|
1051
|
+
|
|
1052
|
+
def methods_receiver_type_argument_names!(type_ref)
|
|
1053
|
+
names = type_ref.arguments.map do |argument|
|
|
1054
|
+
value = argument.value
|
|
1055
|
+
next unless value.is_a?(AST::TypeRef)
|
|
1056
|
+
next unless value.arguments.empty? && !value.nullable && value.name.parts.length == 1
|
|
1057
|
+
|
|
1058
|
+
value.name.parts.first
|
|
1059
|
+
end
|
|
1060
|
+
|
|
1061
|
+
raise_sema_error("extending target #{type_ref} must use the receiver type parameters directly") if names.any?(&:nil?)
|
|
1062
|
+
|
|
1063
|
+
names
|
|
1064
|
+
end
|
|
1065
|
+
|
|
1066
|
+
def validate_methods_receiver_type_arguments!(type_ref, generic_type)
|
|
1067
|
+
names = type_ref.arguments.map do |argument|
|
|
1068
|
+
value = argument.value
|
|
1069
|
+
next unless value.is_a?(AST::TypeRef)
|
|
1070
|
+
next unless value.arguments.empty? && !value.nullable && value.name.parts.length == 1
|
|
1071
|
+
|
|
1072
|
+
value.name.parts.first
|
|
1073
|
+
end
|
|
1074
|
+
|
|
1075
|
+
expected_names = generic_type.type_params
|
|
1076
|
+
unless names == expected_names
|
|
1077
|
+
raise_sema_error("extending target #{type_ref} must use the receiver type parameters directly")
|
|
1078
|
+
end
|
|
1079
|
+
|
|
1080
|
+
expected_names
|
|
1081
|
+
end
|
|
1082
|
+
|
|
1083
|
+
def proc_type_compatible?(actual_type, expected_type)
|
|
1084
|
+
return true unless expected_type
|
|
1085
|
+
if proc_type?(expected_type)
|
|
1086
|
+
return true if expected_type.is_a?(Types::Proc) && actual_type.is_a?(Types::Proc) &&
|
|
1087
|
+
contains_type_var?(expected_type)
|
|
1088
|
+
return actual_type == expected_type
|
|
1089
|
+
end
|
|
1090
|
+
|
|
1091
|
+
false
|
|
1092
|
+
end
|
|
1093
|
+
|
|
1094
|
+
|
|
1095
|
+
def freeze_scope_bindings(scope)
|
|
1096
|
+
frozen_scope = scope.is_a?(FlowScope) ? FlowScope.new : {}
|
|
1097
|
+
scope.each do |name, binding|
|
|
1098
|
+
frozen_scope[name] = ValueBinding.new(
|
|
1099
|
+
id: binding.id,
|
|
1100
|
+
name: binding.name,
|
|
1101
|
+
storage_type: binding.storage_type,
|
|
1102
|
+
flow_type: binding.flow_type,
|
|
1103
|
+
mutable: false,
|
|
1104
|
+
kind: binding.kind,
|
|
1105
|
+
const_value: binding.const_value,
|
|
1106
|
+
)
|
|
1107
|
+
end
|
|
1108
|
+
frozen_scope
|
|
1109
|
+
end
|
|
1110
|
+
|
|
1111
|
+
def validate_stored_ref_type!(type, context, allow_lifetimes: [])
|
|
1112
|
+
return unless contains_ref_type?(type, allow_lifetimes:)
|
|
1113
|
+
return if stored_ref_supported_type?(type, allow_lifetimes:)
|
|
1114
|
+
|
|
1115
|
+
if callable_type?(type) || contains_callable_ref_type?(type)
|
|
1116
|
+
raise_sema_error("#{context} cannot store ref types outside callable parameter positions")
|
|
1117
|
+
end
|
|
1118
|
+
|
|
1119
|
+
if context.start_with?("field ")
|
|
1120
|
+
raise_sema_error("#{context} cannot store ref types; declare a lifetime on the struct and use ref[@lt, T] (e.g. struct MyStruct[@a]: field: ref[@a, SomeType])")
|
|
1121
|
+
end
|
|
1122
|
+
|
|
1123
|
+
raise_sema_error("#{context} cannot store ref types")
|
|
1124
|
+
end
|
|
1125
|
+
|
|
1126
|
+
def stored_ref_supported_type?(type, visited = {}, allow_lifetimes: [])
|
|
1127
|
+
visitor = StoredRefSupportedVisitor.new(allow_lifetimes:)
|
|
1128
|
+
visitor.visit(type)
|
|
1129
|
+
visitor.result?
|
|
1130
|
+
end
|
|
1131
|
+
|
|
1132
|
+
def contains_callable_ref_type?(type, visited = {})
|
|
1133
|
+
visitor = ContainsCallableRefTypeVisitor.new
|
|
1134
|
+
visitor.visit(type)
|
|
1135
|
+
visitor.found?
|
|
1136
|
+
end
|
|
1137
|
+
|
|
1138
|
+
def contains_proc_type?(type, visited = {})
|
|
1139
|
+
visitor = ContainsProcTypeVisitor.new
|
|
1140
|
+
visitor.visit(type)
|
|
1141
|
+
visitor.found?
|
|
1142
|
+
end
|
|
1143
|
+
|
|
1144
|
+
def proc_storage_supported_type?(type, visited = {})
|
|
1145
|
+
return true unless contains_proc_type?(type)
|
|
1146
|
+
visitor = ProcStorageSupportedVisitor.new
|
|
1147
|
+
visitor.visit(type)
|
|
1148
|
+
visitor.result?
|
|
1149
|
+
end
|
|
1150
|
+
|
|
1151
|
+
def validate_parameter_ref_type!(type, function_name:, parameter_name:, external:)
|
|
1152
|
+
if ref_type?(type)
|
|
1153
|
+
raise_sema_error("external function #{function_name} cannot take ref parameters") if external
|
|
1154
|
+
|
|
1155
|
+
return
|
|
1156
|
+
end
|
|
1157
|
+
|
|
1158
|
+
return if callable_param_ref_supported?(type)
|
|
1159
|
+
|
|
1160
|
+
raise_sema_error("parameter #{parameter_name} of #{function_name} cannot nest ref types") if contains_ref_type?(type)
|
|
1161
|
+
end
|
|
1162
|
+
|
|
1163
|
+
def validate_parameter_proc_type!(type, function_name:, parameter_name:, external:, foreign:)
|
|
1164
|
+
if contains_proc_type?(type)
|
|
1165
|
+
raise_sema_error("external function #{function_name} cannot take proc parameters") if external
|
|
1166
|
+
raise_sema_error("foreign function #{function_name} cannot take proc parameters") if foreign
|
|
1167
|
+
raise_sema_error("parameter #{parameter_name} of #{function_name} uses unsupported proc nesting") unless proc_storage_supported_type?(type)
|
|
1168
|
+
end
|
|
1169
|
+
end
|
|
1170
|
+
|
|
1171
|
+
def validate_return_ref_type!(type, function_name:)
|
|
1172
|
+
if contains_ref_type?(type)
|
|
1173
|
+
if (type.is_a?(Types::Struct) || type.is_a?(Types::StructInstance)) && type.fields.any?
|
|
1174
|
+
raise_sema_error("function #{function_name} cannot return non-owning struct #{type.name} (contains borrowed ref)")
|
|
1175
|
+
end
|
|
1176
|
+
raise_sema_error("function #{function_name} cannot return ref types")
|
|
1177
|
+
end
|
|
1178
|
+
end
|
|
1179
|
+
|
|
1180
|
+
def validate_return_proc_type!(type, function_name:)
|
|
1181
|
+
if contains_proc_type?(type)
|
|
1182
|
+
raise_sema_error("function #{function_name} uses unsupported proc nesting in return type") unless proc_storage_supported_type?(type)
|
|
1183
|
+
end
|
|
1184
|
+
end
|
|
1185
|
+
|
|
1186
|
+
def validate_local_ref_type!(type, local_name)
|
|
1187
|
+
return if ref_type?(type)
|
|
1188
|
+
return if (type.is_a?(Types::Struct) || type.is_a?(Types::StructInstance)) && type.fields.any? && contains_ref_type?(type)
|
|
1189
|
+
return if stored_ref_supported_type?(type)
|
|
1190
|
+
|
|
1191
|
+
if contains_ref_type?(type)
|
|
1192
|
+
if callable_type?(type) || contains_callable_ref_type?(type)
|
|
1193
|
+
raise_sema_error("local #{local_name} cannot store ref types outside callable parameter positions")
|
|
1194
|
+
end
|
|
1195
|
+
|
|
1196
|
+
raise_sema_error("local #{local_name} cannot store nested ref types")
|
|
1197
|
+
end
|
|
1198
|
+
end
|
|
1199
|
+
|
|
1200
|
+
def validate_local_proc_type!(type, local_name, initializer:)
|
|
1201
|
+
return unless contains_proc_type?(type)
|
|
1202
|
+
|
|
1203
|
+
raise_sema_error("local #{local_name} uses unsupported proc nesting") unless proc_storage_supported_type?(type)
|
|
1204
|
+
end
|
|
1205
|
+
|
|
1206
|
+
def preassigned_local_binding_id_for(node)
|
|
1207
|
+
@preassigned_local_binding_ids[node.object_id] ||= allocate_binding_id
|
|
1208
|
+
end
|
|
1209
|
+
|
|
1210
|
+
def error_type?(type)
|
|
1211
|
+
type.is_a?(Types::Error)
|
|
1212
|
+
end
|
|
1213
|
+
|
|
1214
|
+
def array_to_span_call_argument_compatible?(actual_type, expected_type, expression:, scopes:)
|
|
1215
|
+
return false unless expected_type.is_a?(Types::Span)
|
|
1216
|
+
|
|
1217
|
+
if array_type?(actual_type)
|
|
1218
|
+
return false unless array_element_type(actual_type) == expected_type.element_type
|
|
1219
|
+
|
|
1220
|
+
infer_addr_source_type(expression, scopes:)
|
|
1221
|
+
record_mutable_lvalue_argument_identifier(expression)
|
|
1222
|
+
return true
|
|
1223
|
+
end
|
|
1224
|
+
|
|
1225
|
+
if str_buffer_type?(actual_type)
|
|
1226
|
+
return false unless expected_type.element_type == @ctx.types.fetch("char")
|
|
1227
|
+
|
|
1228
|
+
infer_addr_source_type(expression, scopes:)
|
|
1229
|
+
record_mutable_lvalue_argument_identifier(expression)
|
|
1230
|
+
return true
|
|
1231
|
+
end
|
|
1232
|
+
|
|
1233
|
+
false
|
|
1234
|
+
rescue SemanticError
|
|
1235
|
+
false
|
|
1236
|
+
end
|
|
1237
|
+
|
|
1238
|
+
def safe_reference_source_expression?(expression, scopes:)
|
|
1239
|
+
case expression
|
|
1240
|
+
when AST::Identifier
|
|
1241
|
+
true
|
|
1242
|
+
when AST::MemberAccess, AST::IndexAccess
|
|
1243
|
+
safe_reference_source_expression?(expression.receiver, scopes:)
|
|
1244
|
+
when AST::BinaryOp
|
|
1245
|
+
unsafe_context?
|
|
1246
|
+
when AST::Call
|
|
1247
|
+
return false unless expression.arguments.length == 1 && expression.arguments.first.name.nil?
|
|
1248
|
+
|
|
1249
|
+
if read_call?(expression)
|
|
1250
|
+
argument_type = infer_expression(expression.arguments.first.value, scopes:)
|
|
1251
|
+
ref_type?(argument_type) || pointer_type?(argument_type)
|
|
1252
|
+
else
|
|
1253
|
+
false
|
|
1254
|
+
end
|
|
1255
|
+
else
|
|
1256
|
+
false
|
|
1257
|
+
end
|
|
1258
|
+
end
|
|
1259
|
+
|
|
1260
|
+
def infer_ro_addr_source_type(expression, scopes:)
|
|
1261
|
+
raise_sema_error("const_ptr_of requires a safe lvalue source") unless safe_reference_source_expression?(expression, scopes:)
|
|
1262
|
+
|
|
1263
|
+
source_type = infer_expression(expression, scopes:)
|
|
1264
|
+
if contains_ref_type?(source_type)
|
|
1265
|
+
unless (source_type.is_a?(Types::Struct) || source_type.is_a?(Types::StructInstance)) && source_type.lifetime_params&.any?
|
|
1266
|
+
raise_sema_error("const_ptr_of cannot target ref values")
|
|
1267
|
+
end
|
|
1268
|
+
end
|
|
1269
|
+
|
|
1270
|
+
source_type
|
|
1271
|
+
end
|
|
1272
|
+
|
|
1273
|
+
def infer_addr_source_type(expression, scopes:)
|
|
1274
|
+
raise_sema_error("ref_of requires a mutable safe lvalue source") unless safe_reference_source_expression?(expression, scopes:)
|
|
1275
|
+
|
|
1276
|
+
source_type = infer_lvalue(expression, scopes:)
|
|
1277
|
+
if contains_ref_type?(source_type)
|
|
1278
|
+
unless (source_type.is_a?(Types::Struct) || source_type.is_a?(Types::StructInstance)) && source_type.lifetime_params&.any?
|
|
1279
|
+
raise_sema_error("ref_of cannot target ref values")
|
|
1280
|
+
end
|
|
1281
|
+
end
|
|
1282
|
+
|
|
1283
|
+
source_type
|
|
1284
|
+
end
|
|
1285
|
+
|
|
1286
|
+
def validate_read_call_arguments!(arguments)
|
|
1287
|
+
raise_sema_error("read does not support named arguments") if arguments.any?(&:name)
|
|
1288
|
+
raise_sema_error("read expects 1 argument, got #{arguments.length}") unless arguments.length == 1
|
|
1289
|
+
end
|
|
1290
|
+
|
|
1291
|
+
def infer_reference_value_type(handle_expression, scopes:)
|
|
1292
|
+
handle_type = infer_expression(handle_expression, scopes:)
|
|
1293
|
+
return referenced_type(handle_type) if ref_type?(handle_type)
|
|
1294
|
+
|
|
1295
|
+
pointee = pointee_type(handle_type)
|
|
1296
|
+
if pointee
|
|
1297
|
+
require_unsafe!("raw pointer dereference requires unsafe") unless own_type?(handle_type)
|
|
1298
|
+
|
|
1299
|
+
return pointee
|
|
1300
|
+
end
|
|
1301
|
+
|
|
1302
|
+
raise_sema_error("read expects ref[...] or ptr[...], got #{handle_type}")
|
|
1303
|
+
end
|
|
1304
|
+
|
|
1305
|
+
def infer_method_receiver_type(receiver_expression, scopes:, member_name: nil)
|
|
1306
|
+
receiver_type = infer_expression(receiver_expression, scopes:)
|
|
1307
|
+
project_method_receiver_type(receiver_type, member_name:)
|
|
1308
|
+
end
|
|
1309
|
+
|
|
1310
|
+
def infer_field_receiver_type(receiver_expression, scopes:, require_mutable_pointer: false)
|
|
1311
|
+
receiver_type = infer_expression(receiver_expression, scopes:)
|
|
1312
|
+
project_field_receiver_type(receiver_type, require_mutable_pointer:)
|
|
1313
|
+
end
|
|
1314
|
+
|
|
1315
|
+
def project_field_receiver_type(receiver_type, require_mutable_pointer: false)
|
|
1316
|
+
return referenced_type(receiver_type) if ref_type?(receiver_type)
|
|
1317
|
+
return receiver_type unless pointer_type?(receiver_type)
|
|
1318
|
+
|
|
1319
|
+
require_unsafe!("raw pointer dereference requires unsafe") unless own_type?(receiver_type)
|
|
1320
|
+
if require_mutable_pointer && const_pointer_type?(receiver_type)
|
|
1321
|
+
raise_sema_error("cannot assign through read-only raw pointer #{receiver_type}")
|
|
1322
|
+
end
|
|
1323
|
+
|
|
1324
|
+
pointee_type(receiver_type)
|
|
1325
|
+
end
|
|
1326
|
+
|
|
1327
|
+
def project_method_receiver_type(receiver_type, member_name: nil)
|
|
1328
|
+
receiver_type = referenced_type(receiver_type) if ref_type?(receiver_type)
|
|
1329
|
+
return receiver_type unless pointer_type?(receiver_type)
|
|
1330
|
+
|
|
1331
|
+
return receiver_type if member_name && lookup_method(receiver_type, member_name)
|
|
1332
|
+
|
|
1333
|
+
require_unsafe!("raw pointer dereference requires unsafe") unless own_type?(receiver_type)
|
|
1334
|
+
|
|
1335
|
+
pointee_type(receiver_type)
|
|
1336
|
+
end
|
|
1337
|
+
|
|
1338
|
+
def read_call?(expression)
|
|
1339
|
+
expression.is_a?(AST::Call) && expression.callee.is_a?(AST::Identifier) && expression.callee.name == "read"
|
|
1340
|
+
end
|
|
1341
|
+
|
|
1342
|
+
def raw_module?
|
|
1343
|
+
@ctx.module_kind == :raw_module
|
|
1344
|
+
end
|
|
1345
|
+
|
|
1346
|
+
def assignable_receiver?(receiver_expression, scopes)
|
|
1347
|
+
infer_lvalue_receiver(receiver_expression, scopes:, allow_ref_identifier: true, allow_pointer_identifier: true, require_mutable_pointer: true)
|
|
1348
|
+
true
|
|
1349
|
+
rescue SemanticError
|
|
1350
|
+
false
|
|
1351
|
+
end
|
|
1352
|
+
|
|
1353
|
+
def value_binding(name:, type:, mutable:, kind:, flow_type: nil, const_value: nil, id: nil)
|
|
1354
|
+
id ||= allocate_binding_id
|
|
1355
|
+
@binding_name_by_id[id] = name
|
|
1356
|
+
@binding_type_by_id[id] = flow_type == type ? type : (flow_type || type)
|
|
1357
|
+
ValueBinding.new(id:, name:, storage_type: type, flow_type: flow_type == type ? nil : flow_type, mutable:, kind:, const_value:)
|
|
1358
|
+
end
|
|
1359
|
+
|
|
1360
|
+
def binding_resolution_snapshot
|
|
1361
|
+
BindingResolution.new(
|
|
1362
|
+
identifier_binding_ids: @identifier_binding_ids.dup.freeze,
|
|
1363
|
+
declaration_binding_ids: @declaration_binding_ids.dup.freeze,
|
|
1364
|
+
mutating_argument_identifier_ids: @mutating_argument_identifier_ids.dup.freeze,
|
|
1365
|
+
editable_receiver_expression_ids: @editable_receiver_expression_ids.dup.freeze,
|
|
1366
|
+
mutable_lvalue_argument_identifier_ids: @mutable_lvalue_argument_identifier_ids.dup.freeze,
|
|
1367
|
+
binding_types: @binding_type_by_id.dup.freeze,
|
|
1368
|
+
)
|
|
1369
|
+
end
|
|
1370
|
+
|
|
1371
|
+
def allocate_binding_id
|
|
1372
|
+
id = @next_binding_id
|
|
1373
|
+
@next_binding_id += 1
|
|
1374
|
+
id
|
|
1375
|
+
end
|
|
1376
|
+
|
|
1377
|
+
def record_identifier_binding(expression, binding)
|
|
1378
|
+
return unless expression.is_a?(AST::Identifier)
|
|
1379
|
+
return unless binding&.id
|
|
1380
|
+
|
|
1381
|
+
@identifier_binding_ids[expression.object_id] = binding.id
|
|
1382
|
+
end
|
|
1383
|
+
|
|
1384
|
+
def record_callable_value_identifier_site(expression)
|
|
1385
|
+
return unless expression.is_a?(AST::Identifier)
|
|
1386
|
+
return unless expression.line && expression.column
|
|
1387
|
+
|
|
1388
|
+
@callable_value_identifier_sites[[expression.line, expression.column]] = true
|
|
1389
|
+
end
|
|
1390
|
+
|
|
1391
|
+
def record_callable_value_expression_site(expression)
|
|
1392
|
+
case expression
|
|
1393
|
+
when AST::Identifier
|
|
1394
|
+
record_callable_value_identifier_site(expression)
|
|
1395
|
+
when AST::MemberAccess
|
|
1396
|
+
record_callable_value_member_access_site(expression)
|
|
1397
|
+
end
|
|
1398
|
+
end
|
|
1399
|
+
|
|
1400
|
+
def record_callable_value_member_access_site(expression)
|
|
1401
|
+
return unless expression.is_a?(AST::MemberAccess)
|
|
1402
|
+
return unless expression.receiver.is_a?(AST::Identifier)
|
|
1403
|
+
return unless expression.receiver.line && expression.receiver.column
|
|
1404
|
+
|
|
1405
|
+
@callable_value_member_access_sites[
|
|
1406
|
+
[expression.receiver.name, expression.receiver.line, expression.receiver.column, expression.member]
|
|
1407
|
+
] = true
|
|
1408
|
+
end
|
|
1409
|
+
|
|
1410
|
+
def record_declaration_binding(node, binding)
|
|
1411
|
+
return unless node
|
|
1412
|
+
return unless binding&.id
|
|
1413
|
+
|
|
1414
|
+
@declaration_binding_ids[node.object_id] = binding.id
|
|
1415
|
+
end
|
|
1416
|
+
|
|
1417
|
+
def import_suggestion_for_type(type_name)
|
|
1418
|
+
return nil if @ctx.global_import_index.nil? || @ctx.global_import_index.empty?
|
|
1419
|
+
|
|
1420
|
+
type_str = type_name.to_s
|
|
1421
|
+
return nil if type_str.empty?
|
|
1422
|
+
|
|
1423
|
+
if @ctx.global_import_index.key?(type_str)
|
|
1424
|
+
entry = @ctx.global_import_index[type_str]
|
|
1425
|
+
return nil if entry.nil?
|
|
1426
|
+
module_path = entry.is_a?(Array) ? entry.first : entry
|
|
1427
|
+
if module_path && !@ctx.imports.key?(module_path.to_s.split(".").first) && !@ctx.imports.key?(module_path.to_s)
|
|
1428
|
+
return "type '#{type_str}' is available via 'import #{module_path}'"
|
|
1429
|
+
end
|
|
1430
|
+
end
|
|
1431
|
+
|
|
1432
|
+
nil
|
|
1433
|
+
end
|
|
1434
|
+
|
|
1435
|
+
|
|
1436
|
+
end
|
|
1437
|
+
end
|
|
1438
|
+
end
|