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,2516 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MilkTea
|
|
4
|
+
module LowererResolve
|
|
5
|
+
private
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def direct_function_to_proc_contextual_compatibility?(expression, actual_type, env:, expected_type:)
|
|
9
|
+
return false unless actual_type.is_a?(Types::Function) && proc_type?(expected_type)
|
|
10
|
+
return false unless direct_function_identity_expression?(expression, env)
|
|
11
|
+
|
|
12
|
+
function_type_matches_proc_type?(actual_type, expected_type)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def direct_function_identity_expression?(expression, env)
|
|
16
|
+
case expression
|
|
17
|
+
when AST::Identifier
|
|
18
|
+
return false if lookup_value(expression.name, env)
|
|
19
|
+
return false unless @ctx.functions.key?(expression.name)
|
|
20
|
+
|
|
21
|
+
binding = @ctx.functions.fetch(expression.name)
|
|
22
|
+
!binding.type_params.any? && !foreign_function_binding?(binding)
|
|
23
|
+
when AST::MemberAccess
|
|
24
|
+
return false unless expression.receiver.is_a?(AST::Identifier) && @ctx.imports.key?(expression.receiver.name)
|
|
25
|
+
|
|
26
|
+
imported_module = @ctx.imports.fetch(expression.receiver.name)
|
|
27
|
+
return false unless imported_module.functions.key?(expression.member)
|
|
28
|
+
|
|
29
|
+
binding = imported_module.functions.fetch(expression.member)
|
|
30
|
+
!binding.type_params.any? && !foreign_function_binding?(binding)
|
|
31
|
+
when AST::Specialization
|
|
32
|
+
callable_resolution = resolve_specialized_callable_binding(expression, env:)
|
|
33
|
+
return false unless callable_resolution
|
|
34
|
+
|
|
35
|
+
callable_kind, binding, = callable_resolution
|
|
36
|
+
callable_kind == :function && !foreign_function_binding?(binding)
|
|
37
|
+
else
|
|
38
|
+
false
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def lower_direct_function_to_proc_expression(source_expression, source_function, env:, expected_type:)
|
|
43
|
+
raise LoweringError, "function-to-proc coercion requires a direct function name" unless source_function.is_a?(IR::Name)
|
|
44
|
+
|
|
45
|
+
proc_id = fresh_proc_symbol
|
|
46
|
+
invoke_c_name = "#{@ctx.module_prefix}__proc_#{proc_id}__invoke"
|
|
47
|
+
release_linkage_name = "#{@ctx.module_prefix}__proc_#{proc_id}__release"
|
|
48
|
+
retain_c_name = "#{@ctx.module_prefix}__proc_#{proc_id}__retain"
|
|
49
|
+
|
|
50
|
+
@artifacts.synthetic_functions << build_direct_function_proc_invoke_function(source_expression, source_function.name, source_function.type, expected_type, invoke_c_name)
|
|
51
|
+
@artifacts.synthetic_functions << build_proc_noop_release_function(release_linkage_name)
|
|
52
|
+
@artifacts.synthetic_functions << build_proc_noop_retain_function(retain_c_name)
|
|
53
|
+
|
|
54
|
+
IR::AggregateLiteral.new(
|
|
55
|
+
type: expected_type,
|
|
56
|
+
fields: [
|
|
57
|
+
IR::AggregateField.new(name: "env", value: IR::NullLiteral.new(type: proc_env_pointer_type)),
|
|
58
|
+
IR::AggregateField.new(name: "invoke", value: IR::Name.new(name: invoke_c_name, type: proc_invoke_function_type(expected_type), pointer: false)),
|
|
59
|
+
IR::AggregateField.new(name: "release", value: IR::Name.new(name: release_linkage_name, type: proc_release_function_type, pointer: false)),
|
|
60
|
+
IR::AggregateField.new(name: "retain", value: IR::Name.new(name: retain_c_name, type: proc_retain_function_type, pointer: false)),
|
|
61
|
+
],
|
|
62
|
+
)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def build_direct_function_proc_invoke_function(source_expression, function_c_name, function_type, proc_type, invoke_c_name)
|
|
66
|
+
env = empty_env
|
|
67
|
+
params = [IR::Param.new(name: "env", linkage_name: "__mt_proc_env", type: proc_env_pointer_type, pointer: false)]
|
|
68
|
+
parameter_setup = []
|
|
69
|
+
call_arguments = []
|
|
70
|
+
|
|
71
|
+
proc_type.params.each_with_index do |param, index|
|
|
72
|
+
linkage_name = c_local_name(param.name || "arg#{index}")
|
|
73
|
+
if array_type?(param.type)
|
|
74
|
+
input_linkage_name = "#{linkage_name}_input"
|
|
75
|
+
params << IR::Param.new(name: param.name || "arg#{index}", linkage_name: input_linkage_name, type: param.type, pointer: false)
|
|
76
|
+
env[:scopes].last[param.name || "arg#{index}"] = local_binding(type: param.type, linkage_name:, mutable: param.mutable, pointer: false)
|
|
77
|
+
parameter_setup << IR::LocalDecl.new(
|
|
78
|
+
name: param.name || "arg#{index}",
|
|
79
|
+
linkage_name:,
|
|
80
|
+
type: param.type,
|
|
81
|
+
value: IR::Name.new(name: input_linkage_name, type: param.type, pointer: false),
|
|
82
|
+
)
|
|
83
|
+
call_arguments << IR::Name.new(name: linkage_name, type: param.type, pointer: false)
|
|
84
|
+
else
|
|
85
|
+
env[:scopes].last[param.name || "arg#{index}"] = local_binding(type: param.type, linkage_name:, mutable: param.mutable, pointer: false)
|
|
86
|
+
params << IR::Param.new(name: param.name || "arg#{index}", linkage_name:, type: param.type, pointer: false)
|
|
87
|
+
call_arguments << IR::Name.new(name: linkage_name, type: param.type, pointer: false)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
call = IR::Call.new(callee: function_c_name, arguments: call_arguments, type: proc_type.return_type)
|
|
92
|
+
body = if proc_type.return_type == @ctx.types.fetch("void")
|
|
93
|
+
parameter_setup + [IR::ExpressionStmt.new(expression: call), IR::ReturnStmt.new(value: nil)]
|
|
94
|
+
else
|
|
95
|
+
parameter_setup + [IR::ReturnStmt.new(value: call)]
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
IR::Function.new(name: invoke_c_name, linkage_name: invoke_c_name, params:, return_type: proc_type.return_type, body:, entry_point: false)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def lower_array_to_span_expression(expression, target_type)
|
|
102
|
+
IR::AggregateLiteral.new(
|
|
103
|
+
type: target_type,
|
|
104
|
+
fields: [
|
|
105
|
+
IR::AggregateField.new(
|
|
106
|
+
name: "data",
|
|
107
|
+
value: IR::AddressOf.new(
|
|
108
|
+
expression: IR::Index.new(
|
|
109
|
+
receiver: expression,
|
|
110
|
+
index: IR::IntegerLiteral.new(value: 0, type: @ctx.types.fetch("ptr_uint")),
|
|
111
|
+
type: target_type.element_type,
|
|
112
|
+
),
|
|
113
|
+
type: pointer_to(target_type.element_type),
|
|
114
|
+
),
|
|
115
|
+
),
|
|
116
|
+
IR::AggregateField.new(
|
|
117
|
+
name: "len",
|
|
118
|
+
value: IR::IntegerLiteral.new(value: array_length(expression.type), type: @ctx.types.fetch("ptr_uint")),
|
|
119
|
+
),
|
|
120
|
+
],
|
|
121
|
+
)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def lower_str_buffer_to_span_expression(expression, target_type)
|
|
125
|
+
IR::AggregateLiteral.new(
|
|
126
|
+
type: target_type,
|
|
127
|
+
fields: [
|
|
128
|
+
IR::AggregateField.new(
|
|
129
|
+
name: "data",
|
|
130
|
+
value: IR::Call.new(
|
|
131
|
+
callee: "mt_str_buffer_prepare_write",
|
|
132
|
+
arguments: [
|
|
133
|
+
lower_str_buffer_data_pointer_from_lowered(expression),
|
|
134
|
+
IR::IntegerLiteral.new(value: str_buffer_capacity(expression.type), type: @ctx.types.fetch("ptr_uint")),
|
|
135
|
+
lower_str_buffer_dirty_pointer_from_lowered(expression),
|
|
136
|
+
],
|
|
137
|
+
type: pointer_to(target_type.element_type),
|
|
138
|
+
),
|
|
139
|
+
),
|
|
140
|
+
IR::AggregateField.new(
|
|
141
|
+
name: "len",
|
|
142
|
+
value: IR::IntegerLiteral.new(value: str_buffer_storage_capacity(expression.type), type: @ctx.types.fetch("ptr_uint")),
|
|
143
|
+
),
|
|
144
|
+
],
|
|
145
|
+
)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def contextual_numeric_compatibility?(expression, actual_type, expected_type, env:, external_numeric: false, contextual_int_to_float: false)
|
|
149
|
+
return true if exact_compile_time_numeric_compatibility?(actual_type, expression, expected_type, env:)
|
|
150
|
+
return true if integer_to_char_compatibility?(actual_type, expected_type)
|
|
151
|
+
return true if external_numeric && external_numeric_compatibility?(actual_type, expected_type)
|
|
152
|
+
return true if contextual_int_to_float && contextual_int_to_float_compatibility?(actual_type, expected_type)
|
|
153
|
+
|
|
154
|
+
false
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def cstr_backed_expression?(expression, env)
|
|
158
|
+
return true if infer_expression_type(expression, env:) == @ctx.types.fetch("cstr")
|
|
159
|
+
|
|
160
|
+
case expression
|
|
161
|
+
when AST::StringLiteral
|
|
162
|
+
true
|
|
163
|
+
when AST::Identifier
|
|
164
|
+
binding_cstr_backed?(lookup_value(expression.name, env))
|
|
165
|
+
when AST::IfExpr
|
|
166
|
+
then_env = env_with_refinements(env, flow_refinements(expression.condition, truthy: true, env:))
|
|
167
|
+
else_env = env_with_refinements(env, flow_refinements(expression.condition, truthy: false, env:))
|
|
168
|
+
cstr_backed_expression?(expression.then_expression, then_env) &&
|
|
169
|
+
cstr_backed_expression?(expression.else_expression, else_env)
|
|
170
|
+
when AST::UnsafeExpr
|
|
171
|
+
cstr_backed_expression?(expression.expression, env)
|
|
172
|
+
else
|
|
173
|
+
false
|
|
174
|
+
end
|
|
175
|
+
rescue LoweringError
|
|
176
|
+
false
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def cstr_list_backed_expression?(expression, env)
|
|
180
|
+
actual_type = infer_expression_type(expression, env:)
|
|
181
|
+
return false unless array_type?(actual_type)
|
|
182
|
+
|
|
183
|
+
element_type = array_element_type(actual_type)
|
|
184
|
+
return false unless element_type == @ctx.types.fetch("str") || element_type == @ctx.types.fetch("cstr")
|
|
185
|
+
|
|
186
|
+
case expression
|
|
187
|
+
when AST::Identifier
|
|
188
|
+
binding_cstr_list_backed?(lookup_value(expression.name, env))
|
|
189
|
+
when AST::Call
|
|
190
|
+
expression.arguments.all? { |argument| cstr_backed_expression?(argument.value, env) }
|
|
191
|
+
when AST::IfExpr
|
|
192
|
+
then_env = env_with_refinements(env, flow_refinements(expression.condition, truthy: true, env:))
|
|
193
|
+
else_env = env_with_refinements(env, flow_refinements(expression.condition, truthy: false, env:))
|
|
194
|
+
cstr_list_backed_expression?(expression.then_expression, then_env) &&
|
|
195
|
+
cstr_list_backed_expression?(expression.else_expression, else_env)
|
|
196
|
+
when AST::UnsafeExpr
|
|
197
|
+
cstr_list_backed_expression?(expression.expression, env)
|
|
198
|
+
else
|
|
199
|
+
false
|
|
200
|
+
end
|
|
201
|
+
rescue LoweringError
|
|
202
|
+
false
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def cstr_backed_storage_value?(type, expression, env)
|
|
206
|
+
return false unless expression
|
|
207
|
+
return true if type == @ctx.types.fetch("cstr")
|
|
208
|
+
return false unless type == @ctx.types.fetch("str")
|
|
209
|
+
|
|
210
|
+
cstr_backed_expression?(expression, env)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def cstr_list_backed_storage_value?(type, expression, env)
|
|
214
|
+
return false unless expression
|
|
215
|
+
return false unless cstr_list_trackable_type?(type)
|
|
216
|
+
|
|
217
|
+
cstr_list_backed_expression?(expression, env)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def update_cstr_metadata_for_assignment!(statement, prepared_value, env)
|
|
221
|
+
if statement.target.is_a?(AST::Identifier)
|
|
222
|
+
binding = lookup_value(statement.target.name, env)
|
|
223
|
+
return unless binding
|
|
224
|
+
|
|
225
|
+
replace_binding_cstr_metadata!(
|
|
226
|
+
statement.target.name,
|
|
227
|
+
env,
|
|
228
|
+
cstr_backed: statement.operator == "=" ? cstr_backed_storage_value?(binding[:type], prepared_value, env) : false,
|
|
229
|
+
cstr_list_backed: statement.operator == "=" ? cstr_list_backed_storage_value?(binding[:type], prepared_value, env) : false,
|
|
230
|
+
)
|
|
231
|
+
return
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
return unless statement.target.is_a?(AST::IndexAccess) && statement.target.receiver.is_a?(AST::Identifier)
|
|
235
|
+
|
|
236
|
+
binding = lookup_value(statement.target.receiver.name, env)
|
|
237
|
+
return unless binding && cstr_list_trackable_type?(binding[:type])
|
|
238
|
+
|
|
239
|
+
replace_binding_cstr_metadata!(statement.target.receiver.name, env, cstr_backed: binding_cstr_backed?(binding), cstr_list_backed: false)
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def merge_cstr_metadata_after_if_statement!(statement, env)
|
|
243
|
+
exit_envs = cstr_metadata_exit_envs_for_if_statement(statement, env)
|
|
244
|
+
return if exit_envs.empty?
|
|
245
|
+
|
|
246
|
+
trackable_binding_names(env).each do |name|
|
|
247
|
+
binding = lookup_value(name, env)
|
|
248
|
+
next unless binding
|
|
249
|
+
|
|
250
|
+
replace_binding_cstr_metadata!(
|
|
251
|
+
name,
|
|
252
|
+
env,
|
|
253
|
+
cstr_backed: cstr_trackable_type?(binding[:type]) && exit_envs.all? { |exit_env| binding_cstr_backed?(lookup_value(name, exit_env)) },
|
|
254
|
+
cstr_list_backed: cstr_list_trackable_type?(binding[:type]) && exit_envs.all? { |exit_env| binding_cstr_list_backed?(lookup_value(name, exit_env)) },
|
|
255
|
+
)
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def cstr_metadata_exit_envs_for_if_statement(statement, env)
|
|
260
|
+
false_refinements = {}
|
|
261
|
+
exit_envs = []
|
|
262
|
+
|
|
263
|
+
statement.branches.each do |branch|
|
|
264
|
+
branch_env = env_with_refinements(env, false_refinements)
|
|
265
|
+
true_refinements = merge_refinements(false_refinements, flow_refinements(branch.condition, truthy: true, env: branch_env))
|
|
266
|
+
simulated = simulate_cstr_metadata_block(branch.body, env: env_with_refinements(env, true_refinements))
|
|
267
|
+
exit_envs << simulated if simulated
|
|
268
|
+
false_refinements = merge_refinements(false_refinements, flow_refinements(branch.condition, truthy: false, env: branch_env))
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
if statement.else_body
|
|
272
|
+
simulated = simulate_cstr_metadata_block(statement.else_body, env: env_with_refinements(env, false_refinements))
|
|
273
|
+
exit_envs << simulated if simulated
|
|
274
|
+
else
|
|
275
|
+
exit_envs << env
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
exit_envs
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
def simulate_cstr_metadata_block(statements, env:)
|
|
282
|
+
simulated_env = duplicate_env(env)
|
|
283
|
+
|
|
284
|
+
statements.each do |statement|
|
|
285
|
+
case statement
|
|
286
|
+
when AST::LocalDecl
|
|
287
|
+
storage_type = if statement.else_body
|
|
288
|
+
infer_expression_type(statement.value, env: simulated_env)
|
|
289
|
+
elsif statement.type
|
|
290
|
+
resolve_type_ref(statement.type)
|
|
291
|
+
else
|
|
292
|
+
infer_expression_type(statement.value, env: simulated_env)
|
|
293
|
+
end
|
|
294
|
+
type = if statement.else_body
|
|
295
|
+
statement.type ? resolve_type_ref(statement.type) : let_else_success_type(storage_type)
|
|
296
|
+
else
|
|
297
|
+
storage_type
|
|
298
|
+
end
|
|
299
|
+
unless let_else_discard_binding_syntax?(statement)
|
|
300
|
+
current_actual_scope(simulated_env[:scopes])[statement.name] = local_binding(
|
|
301
|
+
type:,
|
|
302
|
+
storage_type:,
|
|
303
|
+
linkage_name: c_local_name(statement.name),
|
|
304
|
+
mutable: statement.kind == :var,
|
|
305
|
+
pointer: false,
|
|
306
|
+
projection: statement.else_body ? let_else_binding_projection(storage_type) : nil,
|
|
307
|
+
cstr_backed: cstr_backed_storage_value?(storage_type, statement.value, simulated_env),
|
|
308
|
+
cstr_list_backed: cstr_list_backed_storage_value?(storage_type, statement.value, simulated_env),
|
|
309
|
+
const_value: statement.else_body ? nil : statement.kind == :let && statement.value ? compile_time_const_value(statement.value, env: simulated_env) : nil,
|
|
310
|
+
)
|
|
311
|
+
end
|
|
312
|
+
when AST::Assignment
|
|
313
|
+
update_cstr_metadata_for_assignment!(statement, statement.value, simulated_env)
|
|
314
|
+
when AST::IfStmt
|
|
315
|
+
merge_cstr_metadata_after_if_statement!(statement, simulated_env)
|
|
316
|
+
when AST::UnsafeStmt
|
|
317
|
+
nested_env = simulate_cstr_metadata_block(statement.body, env: simulated_env)
|
|
318
|
+
return nil unless nested_env
|
|
319
|
+
|
|
320
|
+
copy_cstr_metadata!(simulated_env, nested_env)
|
|
321
|
+
when AST::ReturnStmt, AST::BreakStmt, AST::ContinueStmt
|
|
322
|
+
return nil
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
simulated_env
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
def copy_cstr_metadata!(target_env, source_env)
|
|
330
|
+
trackable_binding_names(target_env).each do |name|
|
|
331
|
+
binding = lookup_value(name, target_env)
|
|
332
|
+
source_binding = lookup_value(name, source_env)
|
|
333
|
+
next unless binding && source_binding
|
|
334
|
+
|
|
335
|
+
replace_binding_cstr_metadata!(
|
|
336
|
+
name,
|
|
337
|
+
target_env,
|
|
338
|
+
cstr_backed: binding_cstr_backed?(source_binding),
|
|
339
|
+
cstr_list_backed: binding_cstr_list_backed?(source_binding),
|
|
340
|
+
)
|
|
341
|
+
end
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
def replace_binding_cstr_metadata!(name, env, cstr_backed:, cstr_list_backed:)
|
|
345
|
+
env[:scopes].reverse_each do |scope|
|
|
346
|
+
next if scope.is_a?(FlowScope)
|
|
347
|
+
next unless scope.key?(name)
|
|
348
|
+
|
|
349
|
+
scope[name] = scope.fetch(name).merge(cstr_backed:, cstr_list_backed:)
|
|
350
|
+
return
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
def trackable_binding_names(env)
|
|
355
|
+
env[:scopes].each_with_object([]) do |scope, names|
|
|
356
|
+
next if scope.is_a?(FlowScope)
|
|
357
|
+
|
|
358
|
+
scope.each do |name, binding|
|
|
359
|
+
next unless cstr_trackable_type?(binding[:type]) || cstr_list_trackable_type?(binding[:type])
|
|
360
|
+
|
|
361
|
+
names << name unless names.include?(name)
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
def binding_cstr_backed?(binding)
|
|
367
|
+
binding && binding[:cstr_backed]
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
def binding_cstr_list_backed?(binding)
|
|
371
|
+
binding && binding[:cstr_list_backed]
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
def exact_compile_time_numeric_compatibility?(actual_type, expression, expected_type, env: nil)
|
|
375
|
+
return false unless expected_type.is_a?(Types::Primitive) && expected_type.numeric?
|
|
376
|
+
return false if actual_type.is_a?(Types::EnumBase)
|
|
377
|
+
|
|
378
|
+
value = compile_time_const_value(expression, env:)
|
|
379
|
+
return false unless value.is_a?(Numeric)
|
|
380
|
+
|
|
381
|
+
numeric_constant_fits_type?(value, expected_type)
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
def external_numeric_assignment_target?(expression, env:)
|
|
385
|
+
case expression
|
|
386
|
+
when AST::MemberAccess
|
|
387
|
+
receiver_type = infer_field_receiver_type(expression.receiver, env:)
|
|
388
|
+
receiver_type.respond_to?(:external) && receiver_type.external
|
|
389
|
+
else
|
|
390
|
+
false
|
|
391
|
+
end
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
def resolve_callee(callee, env, arguments: nil)
|
|
395
|
+
case callee
|
|
396
|
+
when AST::Identifier
|
|
397
|
+
if (binding = lookup_value(callee.name, env))
|
|
398
|
+
return [:callable_value, nil, nil, binding[:type], nil] if callable_type?(binding[:type])
|
|
399
|
+
|
|
400
|
+
raise LoweringError, "#{callee.name} is not callable"
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
if @ctx.functions.key?(callee.name)
|
|
404
|
+
binding = specialize_function_binding(@ctx.functions.fetch(callee.name), arguments, env)
|
|
405
|
+
callee_name = if binding.external
|
|
406
|
+
external_function_c_name(binding)
|
|
407
|
+
else
|
|
408
|
+
function_binding_c_name(binding, module_name: @ctx.module_name)
|
|
409
|
+
end
|
|
410
|
+
[ :function, callee_name, nil, binding.type, binding ]
|
|
411
|
+
elsif callee.name == "fatal"
|
|
412
|
+
[:fatal, nil, nil, nil]
|
|
413
|
+
elsif callee.name == "ref_of"
|
|
414
|
+
[:ref_of, nil, nil, nil]
|
|
415
|
+
elsif callee.name == "const_ptr_of"
|
|
416
|
+
[:const_ptr_of, nil, nil, nil]
|
|
417
|
+
elsif callee.name == "read"
|
|
418
|
+
[:read, nil, nil, nil]
|
|
419
|
+
elsif callee.name == "ptr_of"
|
|
420
|
+
[:ptr_of, nil, nil, nil]
|
|
421
|
+
elsif callee.name == "field_of"
|
|
422
|
+
[:compile_time_builtin, "field_of", nil, compile_time_builtin_function_type("field_of", arguments, env)]
|
|
423
|
+
elsif callee.name == "callable_of"
|
|
424
|
+
[:compile_time_builtin, "callable_of", nil, compile_time_builtin_function_type("callable_of", arguments, env)]
|
|
425
|
+
elsif callee.name == "has_attribute"
|
|
426
|
+
[:compile_time_builtin, "has_attribute", nil, compile_time_builtin_function_type("has_attribute", arguments, env)]
|
|
427
|
+
elsif callee.name == "attribute_of"
|
|
428
|
+
[:compile_time_builtin, "attribute_of", nil, compile_time_builtin_function_type("attribute_of", arguments, env)]
|
|
429
|
+
elsif callee.name == "get"
|
|
430
|
+
[:get, nil, nil, nil]
|
|
431
|
+
elsif (type = @ctx.types[callee.name]).is_a?(Types::Struct) || type.is_a?(Types::StringView) || task_type?(type) || type.is_a?(Types::Vector) || type.is_a?(Types::Matrix) || type.is_a?(Types::Quaternion)
|
|
432
|
+
[ :struct_literal, nil, nil, type ]
|
|
433
|
+
else
|
|
434
|
+
emit_fn = @artifacts.emitted_declarations.find { |d| d.is_a?(IR::Function) && d.name == callee.name }
|
|
435
|
+
if emit_fn
|
|
436
|
+
return [:function, emit_fn.linkage_name, nil, emit_fn.return_type, nil]
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
raise LoweringError, "unknown callee #{callee.name}"
|
|
440
|
+
end
|
|
441
|
+
when AST::MemberAccess
|
|
442
|
+
if callee.receiver.is_a?(AST::Identifier) && @ctx.imports.key?(callee.receiver.name)
|
|
443
|
+
imported_module = @ctx.imports.fetch(callee.receiver.name)
|
|
444
|
+
|
|
445
|
+
if imported_module.functions.key?(callee.member)
|
|
446
|
+
binding = specialize_function_binding(imported_module.functions.fetch(callee.member), arguments, env)
|
|
447
|
+
unless binding.owner
|
|
448
|
+
binding = binding.with(owner: imported_module.respond_to?(:analysis) ? imported_module.analysis : imported_module)
|
|
449
|
+
end
|
|
450
|
+
return [:function, function_binding_c_name(binding, module_name: imported_module.name), nil, binding.type, binding] unless binding.external
|
|
451
|
+
|
|
452
|
+
return [:function, external_function_c_name(binding), nil, binding.type, binding]
|
|
453
|
+
end
|
|
454
|
+
imported_type = imported_module.types[callee.member]
|
|
455
|
+
if imported_type.is_a?(Types::Struct) || imported_type.is_a?(Types::StringView) || task_type?(imported_type) || imported_type.is_a?(Types::Vector) || imported_type.is_a?(Types::Matrix) || imported_type.is_a?(Types::Quaternion)
|
|
456
|
+
return [:struct_literal, nil, nil, imported_module.types.fetch(callee.member)]
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
if imported_type.is_a?(Types::Variant) && imported_type.arm_names.include?(callee.member)
|
|
460
|
+
arm_name = callee.member
|
|
461
|
+
return [:variant_arm_ctor, nil, nil, imported_type, [imported_type, arm_name]]
|
|
462
|
+
end
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
if (type_expr = resolve_type_expression(callee.receiver))
|
|
466
|
+
if type_expr.is_a?(Types::Variant) && type_expr.arm_names.include?(callee.member)
|
|
467
|
+
arm_name = callee.member
|
|
468
|
+
return [:variant_arm_ctor, nil, nil, type_expr, [type_expr, arm_name]]
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
if type_expr.respond_to?(:nested_types) && type_expr.nested_types.key?(callee.member)
|
|
472
|
+
return [:struct_literal, nil, nil, type_expr.nested_types[callee.member]]
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
dispatch_receiver_type = method_dispatch_receiver_type(type_expr)
|
|
476
|
+
method_entry_receiver_type = type_expr
|
|
477
|
+
method_entry = @method_definitions[[type_expr, callee.member]]
|
|
478
|
+
method_entry ||= @method_definitions[[type_expr, "static:#{callee.member}"]]
|
|
479
|
+
unless method_entry || dispatch_receiver_type == type_expr
|
|
480
|
+
method_entry_receiver_type = dispatch_receiver_type
|
|
481
|
+
method_entry = @method_definitions[[dispatch_receiver_type, callee.member]]
|
|
482
|
+
method_entry ||= @method_definitions[[dispatch_receiver_type, "static:#{callee.member}"]]
|
|
483
|
+
end
|
|
484
|
+
if method_entry
|
|
485
|
+
method_analysis, method_ast = method_entry
|
|
486
|
+
method_binding = method_analysis.methods.fetch(method_entry_receiver_type).fetch(method_analysis_key(method_ast))
|
|
487
|
+
if method_binding.type.receiver_type.nil?
|
|
488
|
+
method_binding = specialize_function_binding(method_binding, arguments, env, receiver_type: type_expr) if method_binding.type_params.any?
|
|
489
|
+
return [:associated_method, function_binding_c_name(method_binding, module_name: method_analysis.module_name, receiver_type: method_entry_receiver_type), nil, method_binding.type, method_binding]
|
|
490
|
+
end
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
raise LoweringError, "unknown associated function #{type_expr}.#{callee.member}"
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
resolved_receiver_type = infer_method_receiver_type(callee.receiver, env:, member_name: callee.member)
|
|
497
|
+
|
|
498
|
+
if dyn_type?(resolved_receiver_type)
|
|
499
|
+
interface = resolved_receiver_type.interface_binding
|
|
500
|
+
method_binding = interface.methods[callee.member]
|
|
501
|
+
raise LoweringError, "no method '#{callee.member}' on interface #{interface.name}" unless method_binding
|
|
502
|
+
return [:dyn_method, nil, callee.receiver, method_binding, nil]
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
dispatch_receiver_type = method_dispatch_receiver_type(resolved_receiver_type)
|
|
506
|
+
method_entry_receiver_type = resolved_receiver_type
|
|
507
|
+
method_entry = @method_definitions[[resolved_receiver_type, callee.member]]
|
|
508
|
+
unless method_entry || dispatch_receiver_type == resolved_receiver_type
|
|
509
|
+
method_entry_receiver_type = dispatch_receiver_type
|
|
510
|
+
method_entry = @method_definitions[[dispatch_receiver_type, callee.member]]
|
|
511
|
+
end
|
|
512
|
+
if method_entry
|
|
513
|
+
method_analysis, method_ast = method_entry
|
|
514
|
+
method_analysis_key = method_ast.kind == :static ? "static:#{method_ast.name}" : method_ast.name
|
|
515
|
+
method_binding = method_analysis.methods.fetch(method_entry_receiver_type).fetch(method_analysis_key)
|
|
516
|
+
method_binding = specialize_function_binding(method_binding, arguments, env, receiver_type: resolved_receiver_type)
|
|
517
|
+
return [
|
|
518
|
+
:method,
|
|
519
|
+
function_binding_c_name(method_binding, module_name: method_analysis.module_name, receiver_type: method_entry_receiver_type),
|
|
520
|
+
callee.receiver,
|
|
521
|
+
method_binding.type,
|
|
522
|
+
method_binding,
|
|
523
|
+
]
|
|
524
|
+
end
|
|
525
|
+
|
|
526
|
+
if callee.member == "with" && struct_with_target_type?(resolved_receiver_type)
|
|
527
|
+
return [:struct_with, nil, callee.receiver, resolved_receiver_type]
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
if (precomputed = @ctx.resolved_call_kinds[@ctx.ast.node_ids[callee.object_id]])
|
|
531
|
+
case precomputed
|
|
532
|
+
when :str_buffer_clear, :str_buffer_assign, :str_buffer_append, :str_buffer_assign_format, :str_buffer_append_format,
|
|
533
|
+
:str_buffer_len, :str_buffer_capacity, :str_buffer_as_str, :str_buffer_as_cstr
|
|
534
|
+
return [precomputed, nil, callee.receiver, str_buffer_method_type(precomputed, resolved_receiver_type)]
|
|
535
|
+
when :event_subscribe, :event_subscribe_once, :event_unsubscribe, :event_emit, :event_wait
|
|
536
|
+
event_type = infer_expression_type(callee.receiver, env:)
|
|
537
|
+
return [precomputed, nil, callee.receiver, event_method_type(precomputed, event_type)]
|
|
538
|
+
when :atomic_load, :atomic_store, :atomic_add, :atomic_sub, :atomic_exchange, :atomic_compare_exchange
|
|
539
|
+
elem = atomic_element_type(resolved_receiver_type)
|
|
540
|
+
ret = case precomputed
|
|
541
|
+
when :atomic_load, :atomic_add, :atomic_sub, :atomic_exchange then elem
|
|
542
|
+
when :atomic_store then @ctx.types.fetch("void")
|
|
543
|
+
when :atomic_compare_exchange then @ctx.types.fetch("bool")
|
|
544
|
+
end
|
|
545
|
+
return [precomputed, nil, callee.receiver, Types::Registry.function(nil, params: [], return_type: ret)]
|
|
546
|
+
end
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
if (str_buffer_method = str_buffer_method_kind(resolved_receiver_type, callee.member))
|
|
550
|
+
return [str_buffer_method, nil, callee.receiver, str_buffer_method_type(str_buffer_method, resolved_receiver_type)]
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
if (event_method = event_method_kind(resolved_receiver_type, callee.member))
|
|
554
|
+
event_type = infer_expression_type(callee.receiver, env:)
|
|
555
|
+
return [event_method, nil, callee.receiver, event_method_type(event_method, event_type)]
|
|
556
|
+
end
|
|
557
|
+
|
|
558
|
+
if (atomic_method = atomic_method_kind(resolved_receiver_type, callee.member))
|
|
559
|
+
elem = atomic_element_type(resolved_receiver_type)
|
|
560
|
+
ret = case atomic_method
|
|
561
|
+
when :atomic_load, :atomic_add, :atomic_sub, :atomic_exchange then elem
|
|
562
|
+
when :atomic_store then @ctx.types.fetch("void")
|
|
563
|
+
when :atomic_compare_exchange then @ctx.types.fetch("bool")
|
|
564
|
+
end
|
|
565
|
+
return [atomic_method, nil, callee.receiver, Types::Registry.function(nil, params: [], return_type: ret)]
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
field_receiver_type = infer_field_receiver_type(callee.receiver, env:)
|
|
569
|
+
if array_type?(field_receiver_type) && callee.member == "as_span"
|
|
570
|
+
return [:array_as_span, nil, callee.receiver, Types::Registry.span(array_element_type(field_receiver_type))]
|
|
571
|
+
end
|
|
572
|
+
|
|
573
|
+
member_type = field_receiver_type.respond_to?(:field) ? field_receiver_type.field(callee.member) : nil
|
|
574
|
+
member_type = field_receiver_type.respond_to?(:field) ? field_receiver_type.field(callee.member) : nil
|
|
575
|
+
return [:callable_value, nil, nil, member_type, nil] if callable_type?(member_type)
|
|
576
|
+
|
|
577
|
+
raise LoweringError, "unknown callee #{callee.receiver}.#{callee.member}"
|
|
578
|
+
when AST::Specialization
|
|
579
|
+
if callee.callee.is_a?(AST::Identifier) && callee.callee.name == "reinterpret"
|
|
580
|
+
target_type = resolve_type_ref(callee.arguments.fetch(0).value)
|
|
581
|
+
return [:reinterpret, nil, nil, Types::Registry.function("reinterpret", params: [Types::Registry.parameter("value", target_type)], return_type: target_type)]
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
if callee.callee.is_a?(AST::Identifier) && callee.callee.name == "array"
|
|
585
|
+
array_type = resolve_type_ref(AST::TypeRef.new(name: AST::QualifiedName.new(parts: ["array"]), arguments: callee.arguments, nullable: false))
|
|
586
|
+
return [:array, nil, nil, array_type]
|
|
587
|
+
end
|
|
588
|
+
|
|
589
|
+
if callee.callee.is_a?(AST::Identifier) && callee.callee.name == "span"
|
|
590
|
+
span_type = resolve_type_ref(AST::TypeRef.new(name: AST::QualifiedName.new(parts: ["span"]), arguments: callee.arguments, nullable: false))
|
|
591
|
+
return [:struct_literal, nil, nil, span_type]
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
if callee.callee.is_a?(AST::Identifier) && callee.callee.name == "zero"
|
|
595
|
+
target_type = resolve_type_ref(callee.arguments.fetch(0).value)
|
|
596
|
+
return [:zero, nil, nil, Types::Registry.function("zero", params: [], return_type: target_type)]
|
|
597
|
+
end
|
|
598
|
+
|
|
599
|
+
if callee.callee.is_a?(AST::Identifier) && callee.callee.name == "hash"
|
|
600
|
+
resolution = resolve_hash_specialization(callee, env:)
|
|
601
|
+
return [:hash, resolution.callee_name, nil, Types::Registry.function("hash", params: [Types::Registry.parameter("value", resolution.target_type)], return_type: @ctx.types.fetch("uint")), resolution.binding]
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
if callee.callee.is_a?(AST::Identifier) && callee.callee.name == "equal"
|
|
605
|
+
resolution = resolve_equal_specialization(callee, env:)
|
|
606
|
+
params = [
|
|
607
|
+
Types::Registry.parameter("left", resolution.target_type),
|
|
608
|
+
Types::Registry.parameter("right", resolution.target_type),
|
|
609
|
+
]
|
|
610
|
+
return [:equal, resolution.callee_name, nil, Types::Registry.function("equal", params:, return_type: @ctx.types.fetch("bool")), resolution.binding]
|
|
611
|
+
end
|
|
612
|
+
|
|
613
|
+
if callee.callee.is_a?(AST::Identifier) && callee.callee.name == "order"
|
|
614
|
+
resolution = resolve_order_specialization(callee, env:)
|
|
615
|
+
params = [
|
|
616
|
+
Types::Registry.parameter("left", resolution.target_type),
|
|
617
|
+
Types::Registry.parameter("right", resolution.target_type),
|
|
618
|
+
]
|
|
619
|
+
return [:order, resolution.callee_name, nil, Types::Registry.function("order", params:, return_type: @ctx.types.fetch("int")), resolution.binding]
|
|
620
|
+
end
|
|
621
|
+
|
|
622
|
+
if callee.callee.is_a?(AST::Identifier) && callee.callee.name == "attribute_arg"
|
|
623
|
+
return [:compile_time_builtin, "attribute_arg", nil, compile_time_builtin_specialization_function_type(callee)]
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
if callee.callee.is_a?(AST::Identifier) && callee.callee.name == "adapt"
|
|
627
|
+
raise LoweringError, "adapt requires exactly one type argument" unless callee.arguments.length == 1
|
|
628
|
+
|
|
629
|
+
type_arg = callee.arguments.first.value
|
|
630
|
+
raise LoweringError, "adapt type argument must be a type" unless type_arg.is_a?(AST::TypeRef)
|
|
631
|
+
|
|
632
|
+
parts = type_arg.name.parts
|
|
633
|
+
type_args = type_arg.arguments.map { |a| a.value }
|
|
634
|
+
interface = resolve_interface_ref(AST::QualifiedName.new(parts:, type_arguments: type_args))
|
|
635
|
+
dyn_type = Types::Dyn.new(interface, interface.respond_to?(:type_arguments) ? (interface.type_arguments || []) : [])
|
|
636
|
+
return [:adapt, nil, nil, dyn_type, interface]
|
|
637
|
+
end
|
|
638
|
+
|
|
639
|
+
if (callable_resolution = resolve_specialized_callable_binding(callee, env:))
|
|
640
|
+
callable_kind, function_binding, receiver = callable_resolution
|
|
641
|
+
if callable_kind == :method
|
|
642
|
+
return [
|
|
643
|
+
:method,
|
|
644
|
+
function_binding_c_name(function_binding, module_name: function_binding.owner.module_name, receiver_type: function_binding.type.receiver_type),
|
|
645
|
+
receiver,
|
|
646
|
+
function_binding.type,
|
|
647
|
+
function_binding,
|
|
648
|
+
]
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
if function_binding.external
|
|
652
|
+
return [:function, external_function_c_name(function_binding), nil, function_binding.type, function_binding]
|
|
653
|
+
end
|
|
654
|
+
|
|
655
|
+
return [:function, function_binding_c_name(function_binding, module_name: function_binding.owner.module_name), nil, function_binding.type, function_binding]
|
|
656
|
+
end
|
|
657
|
+
|
|
658
|
+
if (type_ref = type_ref_from_specialization(callee))
|
|
659
|
+
specialized_type = resolve_type_ref(type_ref)
|
|
660
|
+
return [:struct_literal, nil, nil, specialized_type] if specialized_type.is_a?(Types::Struct) || task_type?(specialized_type) || specialized_type.is_a?(Types::Vector) || specialized_type.is_a?(Types::Matrix) || specialized_type.is_a?(Types::Quaternion)
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
raise LoweringError, "unsupported specialization callee"
|
|
664
|
+
else
|
|
665
|
+
callee_type = infer_expression_type(callee, env:)
|
|
666
|
+
return [:callable_value, nil, nil, callee_type, nil] if callable_type?(callee_type)
|
|
667
|
+
|
|
668
|
+
raise LoweringError, "unsupported callee #{callee.class.name}"
|
|
669
|
+
end
|
|
670
|
+
end
|
|
671
|
+
|
|
672
|
+
def infer_expression_type(expression, env:, expected_type: nil)
|
|
673
|
+
if !@bypass_sema_type_cache && expected_type.nil? && (id = @ctx.ast.node_ids[expression.object_id]) && (resolved = @ctx.resolved_expr_types[id])
|
|
674
|
+
return resolved
|
|
675
|
+
end
|
|
676
|
+
|
|
677
|
+
case expression
|
|
678
|
+
when AST::AwaitExpr
|
|
679
|
+
task_type = infer_expression_type(expression.expression, env:)
|
|
680
|
+
raise LoweringError, "await requires a Task value, got #{task_type}" unless task_type.is_a?(Types::Task)
|
|
681
|
+
|
|
682
|
+
task_type.result_type
|
|
683
|
+
when AST::IntegerLiteral
|
|
684
|
+
if expected_type.is_a?(Types::Primitive) && expected_type.integer?
|
|
685
|
+
expected_type
|
|
686
|
+
else
|
|
687
|
+
@ctx.types.fetch("int")
|
|
688
|
+
end
|
|
689
|
+
when AST::CharLiteral
|
|
690
|
+
@ctx.types.fetch("ubyte")
|
|
691
|
+
when AST::FloatLiteral
|
|
692
|
+
if expression.lexeme.end_with?("f")
|
|
693
|
+
@ctx.types.fetch("float")
|
|
694
|
+
elsif expression.lexeme.end_with?("d")
|
|
695
|
+
@ctx.types.fetch("double")
|
|
696
|
+
elsif expected_type.is_a?(Types::Primitive) && expected_type.float?
|
|
697
|
+
expected_type
|
|
698
|
+
else
|
|
699
|
+
@ctx.types.fetch("float")
|
|
700
|
+
end
|
|
701
|
+
when AST::SizeofExpr, AST::AlignofExpr, AST::OffsetofExpr
|
|
702
|
+
@ctx.types.fetch("ptr_uint")
|
|
703
|
+
when AST::StringLiteral
|
|
704
|
+
@ctx.types.fetch(expression.cstring ? "cstr" : "str")
|
|
705
|
+
when AST::FormatString
|
|
706
|
+
@ctx.types.fetch("str")
|
|
707
|
+
when AST::BooleanLiteral
|
|
708
|
+
@ctx.types.fetch("bool")
|
|
709
|
+
when AST::NullLiteral
|
|
710
|
+
infer_null_literal_type(expression, expected_type)
|
|
711
|
+
when AST::Identifier
|
|
712
|
+
binding = lookup_value(expression.name, env)
|
|
713
|
+
return binding[:type] if binding
|
|
714
|
+
return function_type_for_name(expression.name) if @ctx.functions.key?(expression.name)
|
|
715
|
+
|
|
716
|
+
raise LoweringError.new("unknown identifier #{expression.name}", line: expression.line, column: expression.column)
|
|
717
|
+
when AST::MemberAccess
|
|
718
|
+
if (type_expr = resolve_type_expression(expression.receiver))
|
|
719
|
+
member_type = resolve_type_member(type_expr, expression.member)
|
|
720
|
+
return member_type if member_type
|
|
721
|
+
|
|
722
|
+
dispatch_receiver_type = method_dispatch_receiver_type(type_expr)
|
|
723
|
+
method_entry_receiver_type = type_expr
|
|
724
|
+
method_entry = @method_definitions[[type_expr, expression.member]]
|
|
725
|
+
method_entry ||= @method_definitions[[type_expr, "static:#{expression.member}"]]
|
|
726
|
+
unless method_entry || dispatch_receiver_type == type_expr
|
|
727
|
+
method_entry_receiver_type = dispatch_receiver_type
|
|
728
|
+
method_entry = @method_definitions[[dispatch_receiver_type, expression.member]]
|
|
729
|
+
method_entry ||= @method_definitions[[dispatch_receiver_type, "static:#{expression.member}"]]
|
|
730
|
+
end
|
|
731
|
+
if method_entry
|
|
732
|
+
method_analysis, method_ast = method_entry
|
|
733
|
+
method_binding = method_analysis.methods.fetch(method_entry_receiver_type).fetch(method_analysis_key(method_ast))
|
|
734
|
+
return method_binding.type if method_binding.type.receiver_type.nil?
|
|
735
|
+
end
|
|
736
|
+
end
|
|
737
|
+
if expression.receiver.is_a?(AST::Identifier) && @ctx.imports.key?(expression.receiver.name)
|
|
738
|
+
imported_module = @ctx.imports.fetch(expression.receiver.name)
|
|
739
|
+
return imported_module.values.fetch(expression.member).type if imported_module.values.key?(expression.member)
|
|
740
|
+
return imported_module.functions.fetch(expression.member).type if imported_module.functions.key?(expression.member)
|
|
741
|
+
end
|
|
742
|
+
receiver_type = infer_field_receiver_type(expression.receiver, env:)
|
|
743
|
+
if (event_type = event_member_from_owner_type(receiver_type, expression.member))
|
|
744
|
+
return event_type
|
|
745
|
+
end
|
|
746
|
+
|
|
747
|
+
if receiver_type == @ctx.types["field_handle"]
|
|
748
|
+
return infer_field_handle_member_type(expression)
|
|
749
|
+
end
|
|
750
|
+
if receiver_type == @ctx.types["member_handle"]
|
|
751
|
+
return infer_member_handle_member_type(expression)
|
|
752
|
+
end
|
|
753
|
+
|
|
754
|
+
return receiver_type.field(expression.member) if receiver_type.respond_to?(:field)
|
|
755
|
+
raise LoweringError.new("unknown member #{expression.member}", line: expression.line, column: expression.column)
|
|
756
|
+
when AST::IndexAccess
|
|
757
|
+
receiver_type = infer_expression_type(expression.receiver, env:)
|
|
758
|
+
index_type = infer_expression_type(expression.index, env:)
|
|
759
|
+
infer_index_result_type(receiver_type, index_type)
|
|
760
|
+
when AST::UnaryOp
|
|
761
|
+
return infer_result_propagation_type(expression, env:) if expression.operator == "?"
|
|
762
|
+
|
|
763
|
+
operand_type = infer_expression_type(expression.operand, env:, expected_type:)
|
|
764
|
+
case expression.operator
|
|
765
|
+
when "not"
|
|
766
|
+
@ctx.types.fetch("bool")
|
|
767
|
+
else
|
|
768
|
+
operand_type
|
|
769
|
+
end
|
|
770
|
+
when AST::BinaryOp
|
|
771
|
+
left_type, right_type = infer_binary_operand_types(expression, env:, expected_type: expected_type)
|
|
772
|
+
|
|
773
|
+
case expression.operator
|
|
774
|
+
when "and", "or", "<", "<=", ">", ">=", "==", "!="
|
|
775
|
+
@ctx.types.fetch("bool")
|
|
776
|
+
when "+", "-", "*", "/"
|
|
777
|
+
aggregate_arithmetic_result_type(expression.operator, left_type, right_type) || pointer_arithmetic_result_type(expression.operator, left_type, right_type) || common_numeric_type(left_type, right_type) || left_type
|
|
778
|
+
when "%"
|
|
779
|
+
common_integer_type(left_type, right_type) || left_type
|
|
780
|
+
else
|
|
781
|
+
left_type
|
|
782
|
+
end
|
|
783
|
+
when AST::IfExpr
|
|
784
|
+
then_env = env_with_refinements(env, flow_refinements(expression.condition, truthy: true, env:))
|
|
785
|
+
else_env = env_with_refinements(env, flow_refinements(expression.condition, truthy: false, env:))
|
|
786
|
+
then_type = infer_expression_type(expression.then_expression, env: then_env, expected_type: expected_type)
|
|
787
|
+
else_type = infer_expression_type(expression.else_expression, env: else_env, expected_type: expected_type)
|
|
788
|
+
|
|
789
|
+
if expected_type &&
|
|
790
|
+
if_expression_branch_compatible?(then_type, expected_type) &&
|
|
791
|
+
if_expression_branch_compatible?(else_type, expected_type)
|
|
792
|
+
return expected_type
|
|
793
|
+
end
|
|
794
|
+
|
|
795
|
+
conditional_common_type(then_type, else_type) || raise(LoweringError, "if expression branches require compatible types, got #{then_type} and #{else_type}")
|
|
796
|
+
when AST::MatchExpr
|
|
797
|
+
scrutinee_type = infer_expression_type(expression.expression, env:)
|
|
798
|
+
arm_types = expression.arms.map do |arm|
|
|
799
|
+
arm_env = duplicate_env(env)
|
|
800
|
+
if scrutinee_type.is_a?(Types::Variant) && arm.binding_name && !wildcard_arm_pattern?(arm.pattern)
|
|
801
|
+
arm_name = variant_match_arm_name_from_pattern(arm.pattern)
|
|
802
|
+
if arm_name && scrutinee_type.has_payload?(arm_name)
|
|
803
|
+
fields = scrutinee_type.arm(arm_name)
|
|
804
|
+
payload_type = Types::VariantArmPayload.new(scrutinee_type, arm_name, fields)
|
|
805
|
+
arm_env[:scopes].last[arm.binding_name] = local_binding(type: payload_type, linkage_name: c_local_name(arm.binding_name), mutable: false, pointer: false)
|
|
806
|
+
end
|
|
807
|
+
end
|
|
808
|
+
infer_expression_type(arm.value, env: arm_env, expected_type: expected_type)
|
|
809
|
+
end
|
|
810
|
+
|
|
811
|
+
if expected_type && arm_types.all? { |arm_type| if_expression_branch_compatible?(arm_type, expected_type) }
|
|
812
|
+
return expected_type
|
|
813
|
+
end
|
|
814
|
+
|
|
815
|
+
common_type = arm_types.first
|
|
816
|
+
arm_types.drop(1).each do |arm_type|
|
|
817
|
+
common_type = conditional_common_type(common_type, arm_type) || raise(LoweringError, "match expression arms require compatible types, got #{common_type} and #{arm_type}")
|
|
818
|
+
end
|
|
819
|
+
common_type
|
|
820
|
+
when AST::UnsafeExpr
|
|
821
|
+
infer_expression_type(expression.expression, env:, expected_type:)
|
|
822
|
+
when AST::ProcExpr
|
|
823
|
+
resolve_type_ref(AST::ProcType.new(params: expression.params, return_type: expression.return_type))
|
|
824
|
+
when AST::Call
|
|
825
|
+
kind, _callee_name, _receiver, callee_type = resolve_callee(expression.callee, env, arguments: expression.arguments)
|
|
826
|
+
case kind
|
|
827
|
+
when :function, :method, :associated_method, :callable_value,
|
|
828
|
+
:str_buffer_clear, :str_buffer_assign, :str_buffer_append, :str_buffer_assign_format, :str_buffer_append_format,
|
|
829
|
+
:str_buffer_len, :str_buffer_capacity, :str_buffer_as_str, :str_buffer_as_cstr,
|
|
830
|
+
:event_subscribe, :event_subscribe_once, :event_unsubscribe, :event_emit, :event_wait,
|
|
831
|
+
:compile_time_builtin,
|
|
832
|
+
:reinterpret, :zero, :hash, :equal, :order,
|
|
833
|
+
:dyn_method
|
|
834
|
+
callee_type.return_type
|
|
835
|
+
when :struct_literal, :struct_with, :array, :variant_arm_ctor, :adapt
|
|
836
|
+
callee_type
|
|
837
|
+
when :ref_of
|
|
838
|
+
argument_type = infer_expression_type(expression.arguments.fetch(0).value, env:)
|
|
839
|
+
Types::Registry.generic_instance("ref", [argument_type])
|
|
840
|
+
when :const_ptr_of
|
|
841
|
+
argument_type = infer_expression_type(expression.arguments.fetch(0).value, env:)
|
|
842
|
+
Types::Registry.generic_instance("const_ptr", [argument_type])
|
|
843
|
+
when :read
|
|
844
|
+
infer_value_type(expression.arguments.fetch(0).value, env:)
|
|
845
|
+
when :ptr_of
|
|
846
|
+
argument_type = infer_expression_type(expression.arguments.fetch(0).value, env:)
|
|
847
|
+
if ref_type?(argument_type)
|
|
848
|
+
Types::Registry.generic_instance("ptr", [referenced_type(argument_type)])
|
|
849
|
+
else
|
|
850
|
+
Types::Registry.generic_instance("ptr", [infer_expression_type(expression.arguments.fetch(0).value, env:, expected_type: expected_type && pointer_type?(expected_type) ? pointee_type(expected_type) : nil)])
|
|
851
|
+
end
|
|
852
|
+
when :array_as_span
|
|
853
|
+
callee_type
|
|
854
|
+
when :fatal
|
|
855
|
+
@ctx.types.fetch("void")
|
|
856
|
+
when :get
|
|
857
|
+
receiver_type = infer_expression_type(expression.arguments.fetch(0).value, env:)
|
|
858
|
+
elem_type = if array_type?(receiver_type)
|
|
859
|
+
array_element_type(receiver_type)
|
|
860
|
+
else
|
|
861
|
+
receiver_type.element_type
|
|
862
|
+
end
|
|
863
|
+
Types::Registry.nullable(Types::Registry.generic_instance("ptr", [elem_type]))
|
|
864
|
+
when :atomic_load, :atomic_add, :atomic_sub, :atomic_exchange, :atomic_store, :atomic_compare_exchange
|
|
865
|
+
callee_type.return_type
|
|
866
|
+
else
|
|
867
|
+
raise LoweringError, "unsupported call kind #{kind}"
|
|
868
|
+
end
|
|
869
|
+
when AST::PrefixCast
|
|
870
|
+
resolve_type_ref(expression.target_type)
|
|
871
|
+
when AST::Specialization
|
|
872
|
+
if expression.callee.is_a?(AST::Identifier) && expression.callee.name == "zero"
|
|
873
|
+
_, _, _, function_type = resolve_callee(expression, env, arguments: [])
|
|
874
|
+
function_type.return_type
|
|
875
|
+
elsif expression.callee.is_a?(AST::Identifier) && expression.callee.name == "default"
|
|
876
|
+
resolve_default_specialization(expression, env:).target_type
|
|
877
|
+
elsif (callable_resolution = resolve_specialized_callable_binding(expression, env:))
|
|
878
|
+
callable_kind, function_binding, = callable_resolution
|
|
879
|
+
raise LoweringError, "specialized method must be called" if callable_kind == :method
|
|
880
|
+
|
|
881
|
+
function_binding.type
|
|
882
|
+
else
|
|
883
|
+
raise LoweringError, "unsupported specialization"
|
|
884
|
+
end
|
|
885
|
+
when AST::RangeExpr
|
|
886
|
+
raise LoweringError, "range expression is not valid in this context; use it as a for-loop iterable"
|
|
887
|
+
when AST::ExpressionList
|
|
888
|
+
names = []
|
|
889
|
+
element_types = []
|
|
890
|
+
expression.elements.each do |element|
|
|
891
|
+
if element.is_a?(AST::Argument)
|
|
892
|
+
names << element.name
|
|
893
|
+
element_types << infer_expression_type(element.value, env:)
|
|
894
|
+
else
|
|
895
|
+
names << nil
|
|
896
|
+
element_types << infer_expression_type(element, env:)
|
|
897
|
+
end
|
|
898
|
+
end
|
|
899
|
+
has_named = names.any?
|
|
900
|
+
Types::Registry.tuple(element_types, field_names: has_named ? names : nil)
|
|
901
|
+
when AST::DetachExpr
|
|
902
|
+
Types::Handle.new
|
|
903
|
+
else
|
|
904
|
+
raise LoweringError, "unsupported expression type #{expression.class.name}"
|
|
905
|
+
end
|
|
906
|
+
end
|
|
907
|
+
|
|
908
|
+
def infer_binary_operand_types(expression, env:, expected_type: nil)
|
|
909
|
+
propagated_type = propagating_expected_type(expression.operator, expected_type)
|
|
910
|
+
left_type = infer_expression_type(expression.left, env:, expected_type: propagated_type)
|
|
911
|
+
right_env = binary_right_env(expression, env)
|
|
912
|
+
right_expected_type = case expression.operator
|
|
913
|
+
when "<<", ">>"
|
|
914
|
+
propagated_type || left_type
|
|
915
|
+
when "+", "-", "*", "/", "%"
|
|
916
|
+
propagated_type || left_type
|
|
917
|
+
when "|", "&", "^"
|
|
918
|
+
left_type
|
|
919
|
+
else
|
|
920
|
+
left_type
|
|
921
|
+
end
|
|
922
|
+
right_type = infer_expression_type(expression.right, env: right_env, expected_type: right_expected_type)
|
|
923
|
+
left_type, right_type = harmonize_binary_float_literal_types(expression.left, expression.right, left_type, right_type, env: right_env)
|
|
924
|
+
harmonize_binary_integer_literal_types(expression.left, expression.right, left_type, right_type, env: right_env)
|
|
925
|
+
end
|
|
926
|
+
|
|
927
|
+
def binary_right_env(expression, env)
|
|
928
|
+
case expression.operator
|
|
929
|
+
when "and"
|
|
930
|
+
env_with_refinements(env, flow_refinements(expression.left, truthy: true, env:))
|
|
931
|
+
when "or"
|
|
932
|
+
env_with_refinements(env, flow_refinements(expression.left, truthy: false, env:))
|
|
933
|
+
else
|
|
934
|
+
env
|
|
935
|
+
end
|
|
936
|
+
end
|
|
937
|
+
|
|
938
|
+
def harmonize_binary_float_literal_types(left_expression, right_expression, left_type, right_type, env:)
|
|
939
|
+
if float_literal_expression?(left_expression) && right_type.is_a?(Types::Primitive) && right_type.float?
|
|
940
|
+
left_type = infer_expression_type(left_expression, env:, expected_type: right_type)
|
|
941
|
+
end
|
|
942
|
+
|
|
943
|
+
if float_literal_expression?(right_expression) && left_type.is_a?(Types::Primitive) && left_type.float?
|
|
944
|
+
right_type = infer_expression_type(right_expression, env:, expected_type: left_type)
|
|
945
|
+
end
|
|
946
|
+
|
|
947
|
+
[left_type, right_type]
|
|
948
|
+
end
|
|
949
|
+
|
|
950
|
+
def float_literal_expression?(expression)
|
|
951
|
+
expression.is_a?(AST::FloatLiteral) ||
|
|
952
|
+
(expression.is_a?(AST::UnaryOp) && ["+", "-"].include?(expression.operator) && float_literal_expression?(expression.operand))
|
|
953
|
+
end
|
|
954
|
+
|
|
955
|
+
def harmonize_binary_integer_literal_types(left_expression, right_expression, left_type, right_type, env:)
|
|
956
|
+
if integer_literal_expression?(left_expression) && right_type.is_a?(Types::Primitive) && right_type.integer?
|
|
957
|
+
if exact_compile_time_numeric_compatibility?(left_type, left_expression, right_type, env:)
|
|
958
|
+
left_type = infer_expression_type(left_expression, env:, expected_type: right_type)
|
|
959
|
+
end
|
|
960
|
+
end
|
|
961
|
+
|
|
962
|
+
if integer_literal_expression?(right_expression) && left_type.is_a?(Types::Primitive) && left_type.integer?
|
|
963
|
+
if exact_compile_time_numeric_compatibility?(right_type, right_expression, left_type, env:)
|
|
964
|
+
right_type = infer_expression_type(right_expression, env:, expected_type: left_type)
|
|
965
|
+
end
|
|
966
|
+
end
|
|
967
|
+
|
|
968
|
+
[left_type, right_type]
|
|
969
|
+
end
|
|
970
|
+
|
|
971
|
+
def integer_literal_expression?(expression)
|
|
972
|
+
expression.is_a?(AST::IntegerLiteral)
|
|
973
|
+
end
|
|
974
|
+
|
|
975
|
+
def propagating_expected_type(operator, expected_type)
|
|
976
|
+
case operator
|
|
977
|
+
when "+", "-", "*", "/", "%", "<<", ">>"
|
|
978
|
+
return expected_type if expected_type.is_a?(Types::Primitive) && expected_type.numeric?
|
|
979
|
+
when "|", "&", "^"
|
|
980
|
+
return expected_type if expected_type.is_a?(Types::Primitive) && expected_type.integer?
|
|
981
|
+
return expected_type if expected_type.is_a?(Types::Flags)
|
|
982
|
+
end
|
|
983
|
+
|
|
984
|
+
nil
|
|
985
|
+
end
|
|
986
|
+
|
|
987
|
+
def promoted_binary_operand_type(operator, left_type, right_type)
|
|
988
|
+
case operator
|
|
989
|
+
when "+", "-", "*", "/", "<", "<=", ">", ">=", "==", "!="
|
|
990
|
+
common_numeric_type(left_type, right_type)
|
|
991
|
+
when "%"
|
|
992
|
+
common_integer_type(left_type, right_type)
|
|
993
|
+
end
|
|
994
|
+
end
|
|
995
|
+
|
|
996
|
+
def cast_expression(expression, target_type)
|
|
997
|
+
return expression if expression.type == target_type
|
|
998
|
+
|
|
999
|
+
IR::Cast.new(target_type:, expression:, type: target_type)
|
|
1000
|
+
end
|
|
1001
|
+
|
|
1002
|
+
def pointer_lowered_sync_method_receiver?(binding)
|
|
1003
|
+
return false if binding.async
|
|
1004
|
+
|
|
1005
|
+
pointer_lowered_method_receiver?(binding.type, binding)
|
|
1006
|
+
end
|
|
1007
|
+
|
|
1008
|
+
def pointer_lowered_method_receiver?(callee_type, callee_binding)
|
|
1009
|
+
return true if callee_type.receiver_editable
|
|
1010
|
+
|
|
1011
|
+
receiver_type_uses_pointer_lowering?(callee_type.receiver_type) && !callee_binding&.async
|
|
1012
|
+
end
|
|
1013
|
+
|
|
1014
|
+
def receiver_type_uses_pointer_lowering?(type)
|
|
1015
|
+
case type
|
|
1016
|
+
when Types::Nullable
|
|
1017
|
+
receiver_type_uses_pointer_lowering?(type.base)
|
|
1018
|
+
when Types::Struct, Types::StructInstance
|
|
1019
|
+
type_contains_array_storage?(type)
|
|
1020
|
+
else
|
|
1021
|
+
false
|
|
1022
|
+
end
|
|
1023
|
+
end
|
|
1024
|
+
|
|
1025
|
+
def type_contains_array_storage?(type, visited = Set.new)
|
|
1026
|
+
visitor = ContainsArrayStorageVisitor.new
|
|
1027
|
+
visitor.visit(type)
|
|
1028
|
+
visitor.found?
|
|
1029
|
+
end
|
|
1030
|
+
|
|
1031
|
+
def reinterpret_expression(expression, target_type)
|
|
1032
|
+
return expression if expression.type == target_type
|
|
1033
|
+
|
|
1034
|
+
IR::ReinterpretExpr.new(target_type:, source_type: expression.type, expression:, type: target_type)
|
|
1035
|
+
end
|
|
1036
|
+
|
|
1037
|
+
def foreign_identity_projection_expression(expression, target_type)
|
|
1038
|
+
return expression if expression.type == target_type
|
|
1039
|
+
return cast_expression(expression, target_type) if foreign_identity_projection_cast_compatible?(expression.type, target_type)
|
|
1040
|
+
|
|
1041
|
+
if foreign_identity_projection_reinterpret_compatible?(expression.type, target_type)
|
|
1042
|
+
record_external_layout_assertion(expression.type, target_type)
|
|
1043
|
+
return reinterpret_expression(expression, target_type)
|
|
1044
|
+
end
|
|
1045
|
+
|
|
1046
|
+
nil
|
|
1047
|
+
end
|
|
1048
|
+
|
|
1049
|
+
def record_external_layout_assertion(source_type, target_type)
|
|
1050
|
+
source_root = ffi_external_layout_root_type(source_type)
|
|
1051
|
+
target_root = ffi_external_layout_root_type(target_type)
|
|
1052
|
+
return unless source_root && target_root
|
|
1053
|
+
return unless source_root.external && target_root.external
|
|
1054
|
+
return if source_root.module_name == target_root.module_name
|
|
1055
|
+
|
|
1056
|
+
pair_key = [[source_root.module_name, source_root.name], [target_root.module_name, target_root.name]].sort.freeze
|
|
1057
|
+
return if @artifacts.emitted_external_layout_pairs[pair_key]
|
|
1058
|
+
|
|
1059
|
+
@artifacts.emitted_external_layout_pairs[pair_key] = true
|
|
1060
|
+
@artifacts.external_layout_assertions << IR::StaticAssert.new(
|
|
1061
|
+
condition: IR::Binary.new(
|
|
1062
|
+
operator: "==",
|
|
1063
|
+
left: IR::SizeofExpr.new(target_type: source_root, type: @ctx.types.fetch("ptr_uint")),
|
|
1064
|
+
right: IR::SizeofExpr.new(target_type: target_root, type: @ctx.types.fetch("ptr_uint")),
|
|
1065
|
+
type: @ctx.types.fetch("bool"),
|
|
1066
|
+
),
|
|
1067
|
+
message: IR::StringLiteral.new(
|
|
1068
|
+
value: "FFI layout mismatch: #{source_root} vs #{target_root}",
|
|
1069
|
+
type: @ctx.types.fetch("str"),
|
|
1070
|
+
cstring: false,
|
|
1071
|
+
),
|
|
1072
|
+
)
|
|
1073
|
+
end
|
|
1074
|
+
|
|
1075
|
+
def ffi_external_layout_root_type(type)
|
|
1076
|
+
type = type.base while type.is_a?(Types::Nullable)
|
|
1077
|
+
return pointee_type(type) if pointer_type?(type)
|
|
1078
|
+
|
|
1079
|
+
type
|
|
1080
|
+
end
|
|
1081
|
+
|
|
1082
|
+
def infer_null_literal_type(expression, expected_type)
|
|
1083
|
+
return Types::Null.new(resolve_type_ref(expression.type)) if expression.type
|
|
1084
|
+
|
|
1085
|
+
expected_type || null_type
|
|
1086
|
+
end
|
|
1087
|
+
|
|
1088
|
+
def common_numeric_type(left_type, right_type)
|
|
1089
|
+
left_type = left_type.backing_type if left_type.is_a?(Types::EnumBase)
|
|
1090
|
+
right_type = right_type.backing_type if right_type.is_a?(Types::EnumBase)
|
|
1091
|
+
return left_type if left_type == right_type
|
|
1092
|
+
return unless left_type.is_a?(Types::Primitive) && right_type.is_a?(Types::Primitive)
|
|
1093
|
+
return unless left_type.numeric? && right_type.numeric?
|
|
1094
|
+
|
|
1095
|
+
return common_integer_type(left_type, right_type) if left_type.integer? && right_type.integer?
|
|
1096
|
+
return wider_float_type(left_type, right_type) if left_type.float? && right_type.float?
|
|
1097
|
+
|
|
1098
|
+
float_type, integer_type = left_type.float? ? [left_type, right_type] : [right_type, left_type]
|
|
1099
|
+
return unless integer_type.integer? && integer_type.fixed_width_integer?
|
|
1100
|
+
|
|
1101
|
+
float_type
|
|
1102
|
+
end
|
|
1103
|
+
|
|
1104
|
+
def common_integer_type(left_type, right_type)
|
|
1105
|
+
left_type = left_type.backing_type if left_type.is_a?(Types::EnumBase)
|
|
1106
|
+
right_type = right_type.backing_type if right_type.is_a?(Types::EnumBase)
|
|
1107
|
+
return left_type if left_type == right_type
|
|
1108
|
+
return unless left_type.is_a?(Types::Primitive) && right_type.is_a?(Types::Primitive)
|
|
1109
|
+
return unless left_type.integer? && right_type.integer?
|
|
1110
|
+
return unless left_type.fixed_width_integer? && right_type.fixed_width_integer?
|
|
1111
|
+
return unless left_type.signed_integer? == right_type.signed_integer?
|
|
1112
|
+
|
|
1113
|
+
left_type.integer_width >= right_type.integer_width ? left_type : right_type
|
|
1114
|
+
end
|
|
1115
|
+
|
|
1116
|
+
def wider_float_type(left_type, right_type)
|
|
1117
|
+
left_type.float_width >= right_type.float_width ? left_type : right_type
|
|
1118
|
+
end
|
|
1119
|
+
|
|
1120
|
+
def aggregate_arithmetic_result_type(operator, left_type, right_type)
|
|
1121
|
+
if left_type.is_a?(Types::Vector) && right_type.is_a?(Types::Vector) && left_type.name == right_type.name
|
|
1122
|
+
return left_type
|
|
1123
|
+
end
|
|
1124
|
+
if left_type.is_a?(Types::Matrix) && right_type.is_a?(Types::Matrix) && left_type.name == right_type.name
|
|
1125
|
+
return left_type
|
|
1126
|
+
end
|
|
1127
|
+
if left_type.is_a?(Types::Quaternion) && right_type.is_a?(Types::Quaternion)
|
|
1128
|
+
return left_type
|
|
1129
|
+
end
|
|
1130
|
+
|
|
1131
|
+
scalar_result = aggregate_scalar_result(left_type, right_type)
|
|
1132
|
+
return scalar_result if scalar_result
|
|
1133
|
+
|
|
1134
|
+
case operator
|
|
1135
|
+
when "+", "-"
|
|
1136
|
+
nil
|
|
1137
|
+
when "*", "/"
|
|
1138
|
+
aggregate_scalar_result(right_type, left_type)
|
|
1139
|
+
else
|
|
1140
|
+
nil
|
|
1141
|
+
end
|
|
1142
|
+
end
|
|
1143
|
+
|
|
1144
|
+
def aggregate_scalar_result(aggregate_type, scalar_type)
|
|
1145
|
+
return nil unless aggregate_type.is_a?(Types::Vector) || aggregate_type.is_a?(Types::Matrix)
|
|
1146
|
+
return nil unless scalar_type.is_a?(Types::Primitive) && scalar_type.numeric?
|
|
1147
|
+
|
|
1148
|
+
aggregate_type
|
|
1149
|
+
end
|
|
1150
|
+
|
|
1151
|
+
def pointer_arithmetic_result_type(operator, left_type, right_type)
|
|
1152
|
+
return left_type if pointer_type?(left_type) && integer_type?(right_type) && (operator == "+" || operator == "-")
|
|
1153
|
+
return right_type if operator == "+" && integer_type?(left_type) && pointer_type?(right_type)
|
|
1154
|
+
|
|
1155
|
+
nil
|
|
1156
|
+
end
|
|
1157
|
+
|
|
1158
|
+
def resolve_type_expression(expression)
|
|
1159
|
+
case expression
|
|
1160
|
+
when AST::Identifier
|
|
1161
|
+
return current_type_params[expression.name] if current_type_params.key?(expression.name)
|
|
1162
|
+
|
|
1163
|
+
@ctx.types[expression.name]
|
|
1164
|
+
when AST::MemberAccess
|
|
1165
|
+
return nil unless expression.receiver.is_a?(AST::Identifier)
|
|
1166
|
+
|
|
1167
|
+
if @ctx.imports.key?(expression.receiver.name)
|
|
1168
|
+
return @ctx.imports.fetch(expression.receiver.name).types[expression.member]
|
|
1169
|
+
end
|
|
1170
|
+
|
|
1171
|
+
parent_type = @ctx.types[expression.receiver.name]
|
|
1172
|
+
return parent_type.nested_types[expression.member] if parent_type.respond_to?(:nested_types) && parent_type.nested_types.key?(expression.member)
|
|
1173
|
+
|
|
1174
|
+
nil
|
|
1175
|
+
when AST::Specialization
|
|
1176
|
+
type_ref = type_ref_from_specialization(expression)
|
|
1177
|
+
return nil unless type_ref
|
|
1178
|
+
|
|
1179
|
+
resolve_type_ref(type_ref)
|
|
1180
|
+
end
|
|
1181
|
+
end
|
|
1182
|
+
|
|
1183
|
+
def resolve_type_member(type, name)
|
|
1184
|
+
case type
|
|
1185
|
+
when Types::Enum, Types::Flags
|
|
1186
|
+
type.member(name)
|
|
1187
|
+
when Types::Variant
|
|
1188
|
+
type if type.arm_names.include?(name)
|
|
1189
|
+
end
|
|
1190
|
+
end
|
|
1191
|
+
|
|
1192
|
+
def function_type_for_name(name)
|
|
1193
|
+
binding = @ctx.functions.fetch(name)
|
|
1194
|
+
raise LoweringError, "generic function #{name} cannot be used as a value" if binding.type_params.any?
|
|
1195
|
+
raise LoweringError, "foreign function #{name} cannot be used as a value" if foreign_function_binding?(binding)
|
|
1196
|
+
|
|
1197
|
+
binding.type
|
|
1198
|
+
end
|
|
1199
|
+
|
|
1200
|
+
def resolve_specialized_callable_binding(expression, env:)
|
|
1201
|
+
callable_kind = :function
|
|
1202
|
+
receiver = nil
|
|
1203
|
+
receiver_type = nil
|
|
1204
|
+
binding = case expression.callee
|
|
1205
|
+
when AST::Identifier
|
|
1206
|
+
@ctx.functions[expression.callee.name]
|
|
1207
|
+
when AST::MemberAccess
|
|
1208
|
+
if expression.callee.receiver.is_a?(AST::Identifier) && @ctx.imports.key?(expression.callee.receiver.name)
|
|
1209
|
+
@ctx.imports.fetch(expression.callee.receiver.name).functions[expression.callee.member]
|
|
1210
|
+
elsif (type_expr = resolve_type_expression(expression.callee.receiver))
|
|
1211
|
+
dispatch_receiver_type = method_dispatch_receiver_type(type_expr)
|
|
1212
|
+
method_entry_receiver_type = type_expr
|
|
1213
|
+
method_entry = @method_definitions[[type_expr, expression.callee.member]]
|
|
1214
|
+
method_entry ||= @method_definitions[[type_expr, "static:#{expression.callee.member}"]]
|
|
1215
|
+
unless method_entry || dispatch_receiver_type == type_expr
|
|
1216
|
+
method_entry_receiver_type = dispatch_receiver_type
|
|
1217
|
+
method_entry = @method_definitions[[dispatch_receiver_type, expression.callee.member]]
|
|
1218
|
+
method_entry ||= @method_definitions[[dispatch_receiver_type, "static:#{expression.callee.member}"]]
|
|
1219
|
+
end
|
|
1220
|
+
if method_entry
|
|
1221
|
+
method_analysis, method_ast = method_entry
|
|
1222
|
+
method_binding = method_analysis.methods.fetch(method_entry_receiver_type).fetch(method_analysis_key(method_ast))
|
|
1223
|
+
if method_binding.type.receiver_type.nil?
|
|
1224
|
+
receiver_type = type_expr
|
|
1225
|
+
method_binding
|
|
1226
|
+
end
|
|
1227
|
+
end
|
|
1228
|
+
else
|
|
1229
|
+
resolved_receiver_type = infer_method_receiver_type(expression.callee.receiver, env:, member_name: expression.callee.member)
|
|
1230
|
+
dispatch_receiver_type = method_dispatch_receiver_type(resolved_receiver_type)
|
|
1231
|
+
method_entry_receiver_type = resolved_receiver_type
|
|
1232
|
+
method_entry = @method_definitions[[resolved_receiver_type, expression.callee.member]]
|
|
1233
|
+
unless method_entry || dispatch_receiver_type == resolved_receiver_type
|
|
1234
|
+
method_entry_receiver_type = dispatch_receiver_type
|
|
1235
|
+
method_entry = @method_definitions[[dispatch_receiver_type, expression.callee.member]]
|
|
1236
|
+
end
|
|
1237
|
+
if method_entry
|
|
1238
|
+
method_analysis, method_ast = method_entry
|
|
1239
|
+
callable_kind = :method
|
|
1240
|
+
receiver = expression.callee.receiver
|
|
1241
|
+
receiver_type = resolved_receiver_type
|
|
1242
|
+
method_analysis.methods.fetch(method_entry_receiver_type).fetch(method_analysis_key(method_ast))
|
|
1243
|
+
end
|
|
1244
|
+
end
|
|
1245
|
+
end
|
|
1246
|
+
return nil unless binding
|
|
1247
|
+
|
|
1248
|
+
type_arguments = resolve_specialization_type_arguments(expression)
|
|
1249
|
+
[callable_kind, instantiate_function_binding_with_receiver(binding, type_arguments, receiver_type:), receiver]
|
|
1250
|
+
end
|
|
1251
|
+
|
|
1252
|
+
def resolve_default_specialization(expression, env:)
|
|
1253
|
+
target_type = resolve_type_ref(expression.arguments.fetch(0).value)
|
|
1254
|
+
|
|
1255
|
+
explicit_default = resolve_explicit_default_binding(target_type, context: "default[#{target_type}]")
|
|
1256
|
+
raise LoweringError, "default[#{target_type}] requires associated function #{target_type}.default()" unless explicit_default
|
|
1257
|
+
|
|
1258
|
+
DefaultResolution.new(target_type:, binding: explicit_default.binding, callee_name: explicit_default.callee_name)
|
|
1259
|
+
end
|
|
1260
|
+
|
|
1261
|
+
def resolve_hash_specialization(expression, env:)
|
|
1262
|
+
target_type = resolve_type_ref(expression.arguments.fetch(0).value)
|
|
1263
|
+
explicit_hash = resolve_explicit_hash_binding(target_type, context: "hash[#{target_type}]")
|
|
1264
|
+
raise LoweringError, "hash[#{target_type}] requires associated function #{target_type}.hash(value: const_ptr[#{target_type}]) -> uint" unless explicit_hash
|
|
1265
|
+
|
|
1266
|
+
HashResolution.new(target_type:, binding: explicit_hash.binding, callee_name: explicit_hash.callee_name)
|
|
1267
|
+
end
|
|
1268
|
+
|
|
1269
|
+
def resolve_equal_specialization(expression, env:)
|
|
1270
|
+
target_type = resolve_type_ref(expression.arguments.fetch(0).value)
|
|
1271
|
+
explicit_equal = resolve_explicit_equal_binding(target_type, context: "equal[#{target_type}]")
|
|
1272
|
+
raise LoweringError, "equal[#{target_type}] requires associated function #{target_type}.equal(left: const_ptr[#{target_type}], right: const_ptr[#{target_type}]) -> bool" unless explicit_equal
|
|
1273
|
+
|
|
1274
|
+
EqualResolution.new(target_type:, binding: explicit_equal.binding, callee_name: explicit_equal.callee_name)
|
|
1275
|
+
end
|
|
1276
|
+
|
|
1277
|
+
def resolve_order_specialization(expression, env:)
|
|
1278
|
+
target_type = resolve_type_ref(expression.arguments.fetch(0).value)
|
|
1279
|
+
explicit_order = resolve_explicit_order_binding(target_type, context: "order[#{target_type}]")
|
|
1280
|
+
raise LoweringError, "order[#{target_type}] requires associated function #{target_type}.order(left: const_ptr[#{target_type}], right: const_ptr[#{target_type}]) -> int" unless explicit_order
|
|
1281
|
+
|
|
1282
|
+
OrderResolution.new(target_type:, binding: explicit_order.binding, callee_name: explicit_order.callee_name)
|
|
1283
|
+
end
|
|
1284
|
+
|
|
1285
|
+
def resolve_explicit_default_binding(target_type, context:)
|
|
1286
|
+
requirement_message = "#{context} requires associated function #{target_type}.default()"
|
|
1287
|
+
resolve_explicit_associated_binding(target_type, "default", requirement_message:) do |method_binding, _method_analysis, _method_entry_receiver_type|
|
|
1288
|
+
raise LoweringError, "#{context} requires #{target_type}.default() to take 0 arguments" unless method_binding.type.params.empty?
|
|
1289
|
+
unless method_binding.type.return_type == target_type
|
|
1290
|
+
raise LoweringError, "#{context} requires #{target_type}.default() to return #{target_type}, got #{method_binding.type.return_type}"
|
|
1291
|
+
end
|
|
1292
|
+
end
|
|
1293
|
+
end
|
|
1294
|
+
|
|
1295
|
+
def resolve_explicit_hash_binding(target_type, context:)
|
|
1296
|
+
requirement_message = "#{context} requires associated function #{target_type}.hash(value: const_ptr[#{target_type}]) -> uint"
|
|
1297
|
+
resolve_explicit_associated_binding(target_type, "hash", requirement_message:) do |method_binding, _method_analysis, _method_entry_receiver_type|
|
|
1298
|
+
unless method_binding.type.params.map(&:type) == [const_pointer_to(target_type)]
|
|
1299
|
+
raise LoweringError, "#{context} requires #{target_type}.hash(value: const_ptr[#{target_type}]) -> uint"
|
|
1300
|
+
end
|
|
1301
|
+
unless method_binding.type.return_type == @ctx.types.fetch("uint")
|
|
1302
|
+
raise LoweringError, "#{context} requires #{target_type}.hash(value: const_ptr[#{target_type}]) -> uint, got #{method_binding.type.return_type}"
|
|
1303
|
+
end
|
|
1304
|
+
end
|
|
1305
|
+
end
|
|
1306
|
+
|
|
1307
|
+
def resolve_explicit_equal_binding(target_type, context:)
|
|
1308
|
+
requirement_message = "#{context} requires associated function #{target_type}.equal(left: const_ptr[#{target_type}], right: const_ptr[#{target_type}]) -> bool"
|
|
1309
|
+
resolve_explicit_associated_binding(target_type, "equal", requirement_message:) do |method_binding, _method_analysis, _method_entry_receiver_type|
|
|
1310
|
+
expected_param_types = [const_pointer_to(target_type), const_pointer_to(target_type)]
|
|
1311
|
+
unless method_binding.type.params.map(&:type) == expected_param_types
|
|
1312
|
+
raise LoweringError, "#{context} requires #{target_type}.equal(left: const_ptr[#{target_type}], right: const_ptr[#{target_type}]) -> bool"
|
|
1313
|
+
end
|
|
1314
|
+
unless method_binding.type.return_type == @ctx.types.fetch("bool")
|
|
1315
|
+
raise LoweringError, "#{context} requires #{target_type}.equal(left: const_ptr[#{target_type}], right: const_ptr[#{target_type}]) -> bool, got #{method_binding.type.return_type}"
|
|
1316
|
+
end
|
|
1317
|
+
end
|
|
1318
|
+
end
|
|
1319
|
+
|
|
1320
|
+
def resolve_explicit_order_binding(target_type, context:)
|
|
1321
|
+
requirement_message = "#{context} requires associated function #{target_type}.order(left: const_ptr[#{target_type}], right: const_ptr[#{target_type}]) -> int"
|
|
1322
|
+
resolve_explicit_associated_binding(target_type, "order", requirement_message:) do |method_binding, _method_analysis, _method_entry_receiver_type|
|
|
1323
|
+
expected_param_types = [const_pointer_to(target_type), const_pointer_to(target_type)]
|
|
1324
|
+
unless method_binding.type.params.map(&:type) == expected_param_types
|
|
1325
|
+
raise LoweringError, "#{context} requires #{target_type}.order(left: const_ptr[#{target_type}], right: const_ptr[#{target_type}]) -> int"
|
|
1326
|
+
end
|
|
1327
|
+
unless method_binding.type.return_type == @ctx.types.fetch("int")
|
|
1328
|
+
raise LoweringError, "#{context} requires #{target_type}.order(left: const_ptr[#{target_type}], right: const_ptr[#{target_type}]) -> int, got #{method_binding.type.return_type}"
|
|
1329
|
+
end
|
|
1330
|
+
end
|
|
1331
|
+
end
|
|
1332
|
+
|
|
1333
|
+
def resolve_explicit_format_binding(target_type, context:)
|
|
1334
|
+
length_binding = resolve_explicit_format_len_binding(target_type, context:)
|
|
1335
|
+
append_binding = resolve_explicit_format_append_binding(target_type, context:)
|
|
1336
|
+
|
|
1337
|
+
return ExplicitFormatBinding.new(
|
|
1338
|
+
length_binding: length_binding.fetch(:binding),
|
|
1339
|
+
length_callee_name: length_binding.fetch(:callee_name),
|
|
1340
|
+
append_binding: append_binding.fetch(:binding),
|
|
1341
|
+
append_callee_name: append_binding.fetch(:callee_name),
|
|
1342
|
+
) if length_binding && append_binding
|
|
1343
|
+
|
|
1344
|
+
if length_binding || append_binding
|
|
1345
|
+
raise LoweringError, "#{context} requires methods #{target_type}.format_len() -> ptr_uint and #{target_type}.append_format(output: ref[std.string.String]) -> void"
|
|
1346
|
+
end
|
|
1347
|
+
|
|
1348
|
+
nil
|
|
1349
|
+
end
|
|
1350
|
+
|
|
1351
|
+
def resolve_explicit_format_len_binding(target_type, context:)
|
|
1352
|
+
requirement_message = "#{context} requires method #{target_type}.format_len() -> ptr_uint"
|
|
1353
|
+
resolve_explicit_instance_binding(target_type, "format_len", requirement_message:) do |method_binding, _method_analysis, _method_entry_receiver_type|
|
|
1354
|
+
raise LoweringError, "#{context} requires #{target_type}.format_len() to take 0 arguments" unless method_binding.type.params.empty?
|
|
1355
|
+
raise LoweringError, "#{context} requires #{target_type}.format_len() to be non-editable" if method_binding.type.receiver_editable
|
|
1356
|
+
unless method_binding.type.return_type == @ctx.types.fetch("ptr_uint")
|
|
1357
|
+
raise LoweringError, "#{context} requires #{target_type}.format_len() -> ptr_uint, got #{method_binding.type.return_type}"
|
|
1358
|
+
end
|
|
1359
|
+
end
|
|
1360
|
+
end
|
|
1361
|
+
|
|
1362
|
+
def resolve_explicit_format_append_binding(target_type, context:)
|
|
1363
|
+
requirement_message = "#{context} requires method #{target_type}.append_format(output: ref[std.string.String]) -> void"
|
|
1364
|
+
resolve_explicit_instance_binding(target_type, "append_format", requirement_message:) do |method_binding, _method_analysis, _method_entry_receiver_type|
|
|
1365
|
+
raise LoweringError, "#{context} requires #{target_type}.append_format() to be non-editable" if method_binding.type.receiver_editable
|
|
1366
|
+
unless method_binding.type.params.length == 1 && string_builder_ref_type?(method_binding.type.params.first.type)
|
|
1367
|
+
raise LoweringError, "#{context} requires #{target_type}.append_format(output: ref[std.string.String]) -> void"
|
|
1368
|
+
end
|
|
1369
|
+
unless method_binding.type.return_type == @ctx.types.fetch("void")
|
|
1370
|
+
raise LoweringError, "#{context} requires #{target_type}.append_format(output: ref[std.string.String]) -> void, got #{method_binding.type.return_type}"
|
|
1371
|
+
end
|
|
1372
|
+
end
|
|
1373
|
+
end
|
|
1374
|
+
|
|
1375
|
+
def method_analysis_key(method_ast)
|
|
1376
|
+
method_ast.kind == :static ? "static:#{method_ast.name}" : method_ast.name
|
|
1377
|
+
end
|
|
1378
|
+
|
|
1379
|
+
def resolve_explicit_associated_binding(target_type, method_name, requirement_message:)
|
|
1380
|
+
dispatch_receiver_type = method_dispatch_receiver_type(target_type)
|
|
1381
|
+
method_entry_receiver_type = target_type
|
|
1382
|
+
static_method_name = "static:#{method_name}"
|
|
1383
|
+
method_entry = @method_definitions[[target_type, static_method_name]]
|
|
1384
|
+
unless method_entry || dispatch_receiver_type == target_type
|
|
1385
|
+
method_entry_receiver_type = dispatch_receiver_type
|
|
1386
|
+
method_entry = @method_definitions[[dispatch_receiver_type, static_method_name]]
|
|
1387
|
+
end
|
|
1388
|
+
return nil unless method_entry
|
|
1389
|
+
|
|
1390
|
+
method_analysis, method_ast = method_entry
|
|
1391
|
+
method_binding = method_analysis.methods.fetch(method_entry_receiver_type).fetch(method_analysis_key(method_ast))
|
|
1392
|
+
raise LoweringError, requirement_message unless method_binding.type.receiver_type.nil?
|
|
1393
|
+
|
|
1394
|
+
method_binding = instantiate_function_binding_with_receiver(method_binding, [], receiver_type: target_type) if method_binding.type_params.any?
|
|
1395
|
+
yield method_binding, method_analysis, method_entry_receiver_type
|
|
1396
|
+
|
|
1397
|
+
callee_name = if method_binding.external
|
|
1398
|
+
external_function_c_name(method_binding)
|
|
1399
|
+
else
|
|
1400
|
+
function_binding_c_name(method_binding, module_name: method_analysis.module_name, receiver_type: method_entry_receiver_type)
|
|
1401
|
+
end
|
|
1402
|
+
|
|
1403
|
+
case method_name
|
|
1404
|
+
when "default"
|
|
1405
|
+
ExplicitDefaultBinding.new(binding: method_binding, callee_name:)
|
|
1406
|
+
when "hash"
|
|
1407
|
+
ExplicitHashBinding.new(binding: method_binding, callee_name:)
|
|
1408
|
+
when "equal"
|
|
1409
|
+
ExplicitEqualBinding.new(binding: method_binding, callee_name:)
|
|
1410
|
+
when "order"
|
|
1411
|
+
ExplicitOrderBinding.new(binding: method_binding, callee_name:)
|
|
1412
|
+
else
|
|
1413
|
+
raise LoweringError, "unsupported associated hook #{method_name}"
|
|
1414
|
+
end
|
|
1415
|
+
end
|
|
1416
|
+
|
|
1417
|
+
def resolve_explicit_instance_binding(target_type, method_name, requirement_message:)
|
|
1418
|
+
dispatch_receiver_type = method_dispatch_receiver_type(target_type)
|
|
1419
|
+
method_entry_receiver_type = target_type
|
|
1420
|
+
method_entry = @method_definitions[[target_type, method_name]]
|
|
1421
|
+
unless method_entry || dispatch_receiver_type == target_type
|
|
1422
|
+
method_entry_receiver_type = dispatch_receiver_type
|
|
1423
|
+
method_entry = @method_definitions[[dispatch_receiver_type, method_name]]
|
|
1424
|
+
end
|
|
1425
|
+
return nil unless method_entry
|
|
1426
|
+
|
|
1427
|
+
method_analysis, method_ast = method_entry
|
|
1428
|
+
method_binding = method_analysis.methods.fetch(method_entry_receiver_type).fetch(method_analysis_key(method_ast))
|
|
1429
|
+
raise LoweringError, requirement_message if method_binding.type.receiver_type.nil?
|
|
1430
|
+
|
|
1431
|
+
method_binding = instantiate_function_binding_with_receiver(method_binding, [], receiver_type: target_type) if method_binding.type_params.any?
|
|
1432
|
+
yield method_binding, method_analysis, method_entry_receiver_type
|
|
1433
|
+
|
|
1434
|
+
callee_name = if method_binding.external
|
|
1435
|
+
external_function_c_name(method_binding)
|
|
1436
|
+
else
|
|
1437
|
+
function_binding_c_name(method_binding, module_name: method_analysis.module_name, receiver_type: method_entry_receiver_type)
|
|
1438
|
+
end
|
|
1439
|
+
|
|
1440
|
+
{
|
|
1441
|
+
binding: method_binding,
|
|
1442
|
+
callee_name: callee_name,
|
|
1443
|
+
}
|
|
1444
|
+
end
|
|
1445
|
+
|
|
1446
|
+
def resolve_specialization_type_arguments(expression)
|
|
1447
|
+
expression.arguments.map do |argument|
|
|
1448
|
+
resolve_type_argument(argument.value)
|
|
1449
|
+
end
|
|
1450
|
+
end
|
|
1451
|
+
|
|
1452
|
+
def resolve_type_argument(argument, type_params: current_type_params)
|
|
1453
|
+
case argument
|
|
1454
|
+
when AST::TypeRef
|
|
1455
|
+
resolve_type_argument_ref(argument, type_params:)
|
|
1456
|
+
when AST::FunctionType, AST::ProcType
|
|
1457
|
+
resolve_type_ref(argument, type_params:)
|
|
1458
|
+
when AST::IntegerLiteral, AST::FloatLiteral
|
|
1459
|
+
Types::LiteralTypeArg.new(argument.value)
|
|
1460
|
+
else
|
|
1461
|
+
raise LoweringError, "unsupported type argument #{argument.class.name}"
|
|
1462
|
+
end
|
|
1463
|
+
end
|
|
1464
|
+
|
|
1465
|
+
def resolve_type_argument_ref(type_ref, type_params:)
|
|
1466
|
+
return resolve_type_ref(type_ref, type_params:) unless literal_type_argument_name_candidate?(type_ref)
|
|
1467
|
+
|
|
1468
|
+
resolve_type_ref(type_ref, type_params:)
|
|
1469
|
+
rescue LoweringError => error
|
|
1470
|
+
literal_type_argument = resolve_named_literal_type_argument(type_ref)
|
|
1471
|
+
return literal_type_argument if literal_type_argument
|
|
1472
|
+
|
|
1473
|
+
raise error
|
|
1474
|
+
end
|
|
1475
|
+
|
|
1476
|
+
def literal_type_argument_name_candidate?(type_ref)
|
|
1477
|
+
type_ref.arguments.empty? && !type_ref.nullable
|
|
1478
|
+
end
|
|
1479
|
+
|
|
1480
|
+
def resolve_named_literal_type_argument(type_ref)
|
|
1481
|
+
value = case type_ref.name.parts.length
|
|
1482
|
+
when 1
|
|
1483
|
+
resolve_current_module_const_value(type_ref.name.parts.first)
|
|
1484
|
+
when 2
|
|
1485
|
+
resolve_imported_module_const_value(type_ref.name.parts.first, type_ref.name.parts.last)
|
|
1486
|
+
end
|
|
1487
|
+
|
|
1488
|
+
return unless value.is_a?(Integer) || value.is_a?(Float)
|
|
1489
|
+
|
|
1490
|
+
Types::LiteralTypeArg.new(value)
|
|
1491
|
+
end
|
|
1492
|
+
|
|
1493
|
+
def resolve_current_module_const_value(name)
|
|
1494
|
+
binding = @ctx.values[name]
|
|
1495
|
+
return unless binding&.kind == :const
|
|
1496
|
+
|
|
1497
|
+
binding.const_value
|
|
1498
|
+
end
|
|
1499
|
+
|
|
1500
|
+
def resolve_imported_module_const_value(import_name, value_name)
|
|
1501
|
+
imported_module = @ctx.imports[import_name]
|
|
1502
|
+
return unless imported_module
|
|
1503
|
+
if imported_module.private_value?(value_name)
|
|
1504
|
+
raise LoweringError, "#{import_name}.#{value_name} is private to module #{imported_module.name}"
|
|
1505
|
+
end
|
|
1506
|
+
|
|
1507
|
+
binding = imported_module.values[value_name]
|
|
1508
|
+
return unless binding&.kind == :const
|
|
1509
|
+
|
|
1510
|
+
binding.const_value
|
|
1511
|
+
end
|
|
1512
|
+
|
|
1513
|
+
def resolve_type_member_const_value(expression)
|
|
1514
|
+
type = resolve_type_expression(expression.receiver)
|
|
1515
|
+
return unless type.is_a?(Types::EnumBase)
|
|
1516
|
+
|
|
1517
|
+
type.member_value(expression.member)
|
|
1518
|
+
end
|
|
1519
|
+
|
|
1520
|
+
def compile_time_numeric_const_expression?(expression, env: nil)
|
|
1521
|
+
value = compile_time_const_value(expression, env:)
|
|
1522
|
+
value.is_a?(Integer) || value.is_a?(Float)
|
|
1523
|
+
end
|
|
1524
|
+
|
|
1525
|
+
def compile_time_const_value(expression, env: nil)
|
|
1526
|
+
CompileTime.evaluate(
|
|
1527
|
+
expression,
|
|
1528
|
+
resolve_identifier: lambda do |identifier_expression|
|
|
1529
|
+
if env
|
|
1530
|
+
binding = lookup_value(identifier_expression.name, env)
|
|
1531
|
+
return binding[:const_value] unless binding&.fetch(:const_value, nil).nil?
|
|
1532
|
+
end
|
|
1533
|
+
|
|
1534
|
+
value = resolve_current_module_const_value(identifier_expression.name)
|
|
1535
|
+
return value if value
|
|
1536
|
+
|
|
1537
|
+
# Resolve a bare type-parameter name (e.g. `T`) to its substituted
|
|
1538
|
+
# concrete type so `inline if T == int` folds during lowering too.
|
|
1539
|
+
current_type_params[identifier_expression.name] || @ctx.types[identifier_expression.name]
|
|
1540
|
+
end,
|
|
1541
|
+
resolve_member_access: lambda do |member_access_expression|
|
|
1542
|
+
if (receiver_value = CompileTime.evaluate(
|
|
1543
|
+
member_access_expression.receiver,
|
|
1544
|
+
resolve_identifier: lambda do |identifier_expression|
|
|
1545
|
+
if env
|
|
1546
|
+
binding = lookup_value(identifier_expression.name, env)
|
|
1547
|
+
return binding[:const_value] unless binding&.fetch(:const_value, nil).nil?
|
|
1548
|
+
end
|
|
1549
|
+
resolve_current_module_const_value(identifier_expression.name)
|
|
1550
|
+
end,
|
|
1551
|
+
resolve_member_access: lambda { |ma| nil },
|
|
1552
|
+
resolve_type_ref: lambda { |tr| resolve_type_ref(tr) },
|
|
1553
|
+
resolve_call: lambda { |ce| evaluate_compile_time_call(ce, env:) },
|
|
1554
|
+
))
|
|
1555
|
+
case receiver_value
|
|
1556
|
+
when Types::FieldHandle
|
|
1557
|
+
case member_access_expression.member
|
|
1558
|
+
when "name" then next receiver_value.field_name
|
|
1559
|
+
when "type" then next receiver_value.struct_handle.struct_type.field(receiver_value.field_name)
|
|
1560
|
+
end
|
|
1561
|
+
when Types::MemberHandle
|
|
1562
|
+
case member_access_expression.member
|
|
1563
|
+
when "name" then next receiver_value.member_name
|
|
1564
|
+
when "value" then next receiver_value.member_value
|
|
1565
|
+
end
|
|
1566
|
+
end
|
|
1567
|
+
end
|
|
1568
|
+
|
|
1569
|
+
value = if member_access_expression.receiver.is_a?(AST::Identifier)
|
|
1570
|
+
resolve_imported_module_const_value(member_access_expression.receiver.name, member_access_expression.member)
|
|
1571
|
+
end
|
|
1572
|
+
next value unless value.nil?
|
|
1573
|
+
|
|
1574
|
+
resolve_type_member_const_value(member_access_expression)
|
|
1575
|
+
end,
|
|
1576
|
+
resolve_type_ref: lambda do |type_ref|
|
|
1577
|
+
resolve_type_ref(type_ref)
|
|
1578
|
+
end,
|
|
1579
|
+
resolve_call: lambda do |call_expression|
|
|
1580
|
+
evaluate_compile_time_call(call_expression, env:)
|
|
1581
|
+
end,
|
|
1582
|
+
)
|
|
1583
|
+
end
|
|
1584
|
+
|
|
1585
|
+
def evaluate_compile_time_call(expression, env:)
|
|
1586
|
+
case expression.callee
|
|
1587
|
+
when AST::Identifier
|
|
1588
|
+
case expression.callee.name
|
|
1589
|
+
when "field_of"
|
|
1590
|
+
evaluate_field_of_call(expression.arguments, env:)
|
|
1591
|
+
when "fields_of"
|
|
1592
|
+
evaluate_fields_of_call(expression.arguments, env:)
|
|
1593
|
+
when "callable_of"
|
|
1594
|
+
evaluate_callable_of_call(expression.arguments)
|
|
1595
|
+
when "has_attribute"
|
|
1596
|
+
evaluate_has_attribute_call(expression.arguments, env:)
|
|
1597
|
+
when "attribute_of"
|
|
1598
|
+
evaluate_attribute_of_call(expression.arguments, env:)
|
|
1599
|
+
when "members_of"
|
|
1600
|
+
evaluate_members_of_call(expression.arguments, env:)
|
|
1601
|
+
when "attributes_of"
|
|
1602
|
+
evaluate_attributes_of_call(expression.arguments, env:)
|
|
1603
|
+
else
|
|
1604
|
+
func = @ctx.functions[expression.callee.name]
|
|
1605
|
+
if func&.ast&.respond_to?(:const) && func.ast.const
|
|
1606
|
+
evaluate_const_function_body_lower(func, expression.arguments)
|
|
1607
|
+
else
|
|
1608
|
+
evaluate_type_returning_call(expression, env:)
|
|
1609
|
+
end
|
|
1610
|
+
end
|
|
1611
|
+
when AST::Specialization
|
|
1612
|
+
if expression.callee.callee.is_a?(AST::Identifier) && expression.callee.callee.name == "attribute_arg"
|
|
1613
|
+
evaluate_attribute_arg_call(expression.arguments, env:)
|
|
1614
|
+
else
|
|
1615
|
+
callee_name = expression.callee.callee.is_a?(AST::Identifier) ? expression.callee.callee.name : nil
|
|
1616
|
+
if callee_name
|
|
1617
|
+
func = @ctx.functions[callee_name]
|
|
1618
|
+
if func&.ast&.respond_to?(:const) && func.ast.const
|
|
1619
|
+
evaluate_const_function_body_lower(func, expression.arguments)
|
|
1620
|
+
else
|
|
1621
|
+
evaluate_type_returning_call(expression, env:)
|
|
1622
|
+
end
|
|
1623
|
+
else
|
|
1624
|
+
evaluate_type_returning_call(expression, env:)
|
|
1625
|
+
end
|
|
1626
|
+
end
|
|
1627
|
+
end
|
|
1628
|
+
end
|
|
1629
|
+
|
|
1630
|
+
def evaluate_type_returning_call(expression, env:)
|
|
1631
|
+
callee_name, type_args = extract_type_callee_info(expression)
|
|
1632
|
+
return nil unless callee_name
|
|
1633
|
+
|
|
1634
|
+
CompileTime::Reflection.core_evaluate_type_returning(
|
|
1635
|
+
callee_name, type_args,
|
|
1636
|
+
evaluate_value: ->(v) { compile_time_const_value(v, env:) },
|
|
1637
|
+
resolve_type_ref: ->(tr) { resolve_type_ref(tr) },
|
|
1638
|
+
pointer_to: ->(t) { pointer_to(t) },
|
|
1639
|
+
const_pointer_to: ->(t) { const_pointer_to(t) },
|
|
1640
|
+
top_level_functions: ->(name) { nil },
|
|
1641
|
+
evaluate_type_returning_function_body: nil,
|
|
1642
|
+
)
|
|
1643
|
+
end
|
|
1644
|
+
|
|
1645
|
+
def extract_type_callee_info(expression)
|
|
1646
|
+
if expression.is_a?(AST::Call) && expression.callee.is_a?(AST::Identifier)
|
|
1647
|
+
[expression.callee.name, nil]
|
|
1648
|
+
elsif expression.is_a?(AST::Specialization)
|
|
1649
|
+
if expression.callee.is_a?(AST::Identifier)
|
|
1650
|
+
[expression.callee.name, expression.arguments]
|
|
1651
|
+
elsif expression.callee.is_a?(AST::Specialization) && expression.callee.callee.is_a?(AST::Identifier)
|
|
1652
|
+
[expression.callee.callee.name, expression.callee.arguments]
|
|
1653
|
+
end
|
|
1654
|
+
end
|
|
1655
|
+
end
|
|
1656
|
+
|
|
1657
|
+
def evaluate_field_of_call(arguments, env:)
|
|
1658
|
+
return nil unless reflection_positional_arguments?(arguments, 2)
|
|
1659
|
+
|
|
1660
|
+
struct_handle = resolve_struct_handle_argument(arguments.first.value, env:)
|
|
1661
|
+
return nil unless struct_handle
|
|
1662
|
+
|
|
1663
|
+
field_name = reflection_identifier_name(arguments[1].value)
|
|
1664
|
+
return nil unless field_name
|
|
1665
|
+
|
|
1666
|
+
CompileTime::Reflection.core_field_handle(struct_handle, field_name)
|
|
1667
|
+
end
|
|
1668
|
+
|
|
1669
|
+
def evaluate_fields_of_call(arguments, env:)
|
|
1670
|
+
return nil unless reflection_positional_arguments?(arguments, 1)
|
|
1671
|
+
|
|
1672
|
+
struct_handle = resolve_struct_handle_argument(arguments.first.value, env:)
|
|
1673
|
+
return nil unless struct_handle
|
|
1674
|
+
|
|
1675
|
+
CompileTime::Reflection.core_field_handles(struct_handle)
|
|
1676
|
+
end
|
|
1677
|
+
|
|
1678
|
+
def evaluate_members_of_call(arguments, env:)
|
|
1679
|
+
return nil unless reflection_positional_arguments?(arguments, 1)
|
|
1680
|
+
|
|
1681
|
+
type = resolve_type_expression(arguments.first.value)
|
|
1682
|
+
return nil unless type
|
|
1683
|
+
|
|
1684
|
+
return nil unless type.is_a?(Types::Enum) || type.is_a?(Types::Flags)
|
|
1685
|
+
|
|
1686
|
+
CompileTime::Reflection.core_member_handles(type)
|
|
1687
|
+
end
|
|
1688
|
+
|
|
1689
|
+
def evaluate_attributes_of_call(arguments, env:)
|
|
1690
|
+
return nil unless reflection_positional_arguments?(arguments, 1) || reflection_positional_arguments?(arguments, 2)
|
|
1691
|
+
|
|
1692
|
+
target = evaluate_reflection_target_argument(arguments.first.value, env:)
|
|
1693
|
+
return nil unless target
|
|
1694
|
+
|
|
1695
|
+
if arguments.length == 2
|
|
1696
|
+
attribute_binding = resolve_attribute_name_argument(arguments[1].value)
|
|
1697
|
+
application = find_attribute_application(target, attribute_binding)
|
|
1698
|
+
return [] unless application
|
|
1699
|
+
|
|
1700
|
+
[Types::AttributeHandle.new(
|
|
1701
|
+
attribute_binding.name,
|
|
1702
|
+
attribute_binding.module_name,
|
|
1703
|
+
target,
|
|
1704
|
+
attribute_binding.params,
|
|
1705
|
+
application.argument_values,
|
|
1706
|
+
)]
|
|
1707
|
+
else
|
|
1708
|
+
resolved_attribute_applications_for_target(target).map do |application|
|
|
1709
|
+
Types::AttributeHandle.new(
|
|
1710
|
+
application.binding.name,
|
|
1711
|
+
application.binding.module_name,
|
|
1712
|
+
target,
|
|
1713
|
+
application.binding.params,
|
|
1714
|
+
application.argument_values,
|
|
1715
|
+
)
|
|
1716
|
+
end
|
|
1717
|
+
end
|
|
1718
|
+
end
|
|
1719
|
+
|
|
1720
|
+
def evaluate_callable_of_call(arguments)
|
|
1721
|
+
return nil unless reflection_positional_arguments?(arguments, 1)
|
|
1722
|
+
|
|
1723
|
+
resolve_callable_handle_argument(arguments.first.value)
|
|
1724
|
+
end
|
|
1725
|
+
|
|
1726
|
+
def evaluate_has_attribute_call(arguments, env:)
|
|
1727
|
+
return nil unless reflection_positional_arguments?(arguments, 2)
|
|
1728
|
+
|
|
1729
|
+
target = evaluate_reflection_target_argument(arguments.first.value, env:)
|
|
1730
|
+
binding = resolve_attribute_name_argument(arguments[1].value)
|
|
1731
|
+
return nil unless attribute_binding_supports_target?(binding, target)
|
|
1732
|
+
|
|
1733
|
+
!find_attribute_application(target, binding).nil?
|
|
1734
|
+
end
|
|
1735
|
+
|
|
1736
|
+
def evaluate_attribute_of_call(arguments, env:)
|
|
1737
|
+
return nil unless reflection_positional_arguments?(arguments, 2)
|
|
1738
|
+
|
|
1739
|
+
target = evaluate_reflection_target_argument(arguments.first.value, env:)
|
|
1740
|
+
binding = resolve_attribute_name_argument(arguments[1].value)
|
|
1741
|
+
return nil unless attribute_binding_supports_target?(binding, target)
|
|
1742
|
+
|
|
1743
|
+
application = find_attribute_application(target, binding)
|
|
1744
|
+
return nil unless application
|
|
1745
|
+
|
|
1746
|
+
Types::AttributeHandle.new(
|
|
1747
|
+
binding.name,
|
|
1748
|
+
binding.module_name,
|
|
1749
|
+
target,
|
|
1750
|
+
binding.params,
|
|
1751
|
+
application.argument_values,
|
|
1752
|
+
)
|
|
1753
|
+
end
|
|
1754
|
+
|
|
1755
|
+
def evaluate_attribute_arg_call(arguments, env:)
|
|
1756
|
+
return nil unless reflection_positional_arguments?(arguments, 2)
|
|
1757
|
+
|
|
1758
|
+
attribute_handle = compile_time_const_value(arguments.first.value, env:)
|
|
1759
|
+
return nil unless attribute_handle.is_a?(Types::AttributeHandle)
|
|
1760
|
+
|
|
1761
|
+
param_name = reflection_identifier_name(arguments[1].value)
|
|
1762
|
+
return nil unless param_name && attribute_handle.argument_values
|
|
1763
|
+
|
|
1764
|
+
attribute_handle.argument_values[param_name]
|
|
1765
|
+
end
|
|
1766
|
+
|
|
1767
|
+
def evaluate_const_function_body_lower(func, arguments)
|
|
1768
|
+
return nil unless func.ast.params.length == arguments.length
|
|
1769
|
+
|
|
1770
|
+
initial_vars = {}
|
|
1771
|
+
func.ast.params.each_with_index do |param, idx|
|
|
1772
|
+
arg_expr = arguments[idx].value
|
|
1773
|
+
arg_value = compile_time_const_value(arg_expr, env: empty_env)
|
|
1774
|
+
return nil unless arg_value
|
|
1775
|
+
|
|
1776
|
+
initial_vars[param.name] = arg_value
|
|
1777
|
+
end
|
|
1778
|
+
|
|
1779
|
+
evaluator = ConstFnLowerEvaluator.new(self)
|
|
1780
|
+
ctx = CompileTime::BlockContext.new(evaluator, initial_variables: initial_vars)
|
|
1781
|
+
ctx.evaluate_block(func.ast.body, scopes: nil)
|
|
1782
|
+
rescue CompileTime::ReturnValue => e
|
|
1783
|
+
e.value
|
|
1784
|
+
end
|
|
1785
|
+
|
|
1786
|
+
class ConstFnLowerEvaluator
|
|
1787
|
+
def initialize(lowerer)
|
|
1788
|
+
@lowerer = lowerer
|
|
1789
|
+
end
|
|
1790
|
+
|
|
1791
|
+
def evaluate_compile_time_const_value(expression, scopes: nil)
|
|
1792
|
+
@lowerer.send(:compile_time_const_value, expression, env: @lowerer.send(:empty_env))
|
|
1793
|
+
end
|
|
1794
|
+
|
|
1795
|
+
def top_level_function(name)
|
|
1796
|
+
@lowerer.instance_variable_get(:@ctx.functions)&.[](name)
|
|
1797
|
+
end
|
|
1798
|
+
|
|
1799
|
+
def raise_sema_error(message)
|
|
1800
|
+
raise CompileTime::Error, message
|
|
1801
|
+
end
|
|
1802
|
+
end
|
|
1803
|
+
|
|
1804
|
+
def evaluate_reflection_target_argument(expression, env:)
|
|
1805
|
+
struct_handle = resolve_struct_handle_argument(expression, env:)
|
|
1806
|
+
return struct_handle if struct_handle
|
|
1807
|
+
|
|
1808
|
+
value = compile_time_const_value(expression, env:)
|
|
1809
|
+
return value if value.is_a?(Types::FieldHandle) || value.is_a?(Types::CallableHandle)
|
|
1810
|
+
|
|
1811
|
+
nil
|
|
1812
|
+
end
|
|
1813
|
+
|
|
1814
|
+
def reflection_positional_arguments?(arguments, expected_length)
|
|
1815
|
+
arguments.length == expected_length && arguments.none?(&:name)
|
|
1816
|
+
end
|
|
1817
|
+
|
|
1818
|
+
def resolve_struct_handle_argument(expression, env:)
|
|
1819
|
+
type = reflection_type_from_expression(expression, env:)
|
|
1820
|
+
return nil unless type
|
|
1821
|
+
|
|
1822
|
+
struct_handle_for_type(type)
|
|
1823
|
+
end
|
|
1824
|
+
|
|
1825
|
+
def reflection_type_from_expression(expression, env:)
|
|
1826
|
+
case expression
|
|
1827
|
+
when AST::Identifier
|
|
1828
|
+
return nil if env && lookup_value(expression.name, env)
|
|
1829
|
+
|
|
1830
|
+
current_type_params[expression.name] || @ctx.types[expression.name]
|
|
1831
|
+
when AST::MemberAccess
|
|
1832
|
+
return nil unless expression.receiver.is_a?(AST::Identifier)
|
|
1833
|
+
|
|
1834
|
+
if @ctx.imports.key?(expression.receiver.name)
|
|
1835
|
+
imported_module = @ctx.imports[expression.receiver.name]
|
|
1836
|
+
return nil if imported_module.private_type?(expression.member)
|
|
1837
|
+
return imported_module.types[expression.member]
|
|
1838
|
+
end
|
|
1839
|
+
|
|
1840
|
+
parent_type = @ctx.types[expression.receiver.name]
|
|
1841
|
+
return parent_type.nested_types[expression.member] if parent_type.respond_to?(:nested_types) && parent_type.nested_types.key?(expression.member)
|
|
1842
|
+
|
|
1843
|
+
nil
|
|
1844
|
+
else
|
|
1845
|
+
nil
|
|
1846
|
+
end
|
|
1847
|
+
end
|
|
1848
|
+
|
|
1849
|
+
def struct_handle_for_type(type)
|
|
1850
|
+
base_type = type.is_a?(Types::StructInstance) ? type.definition : type
|
|
1851
|
+
return nil unless base_type.is_a?(Types::Struct) || base_type.is_a?(Types::GenericStructDefinition)
|
|
1852
|
+
return nil unless base_type.respond_to?(:module_name)
|
|
1853
|
+
|
|
1854
|
+
analysis = analysis_for_module(base_type.module_name)
|
|
1855
|
+
declaration = find_struct_decl_by_name(analysis.ast.declarations, base_type.name)
|
|
1856
|
+
return nil unless declaration
|
|
1857
|
+
|
|
1858
|
+
Types::StructHandle.new(base_type, declaration)
|
|
1859
|
+
end
|
|
1860
|
+
|
|
1861
|
+
def find_struct_decl_by_name(declarations, name)
|
|
1862
|
+
declarations.each do |decl|
|
|
1863
|
+
next unless decl.is_a?(AST::StructDecl)
|
|
1864
|
+
return decl if decl.name == name
|
|
1865
|
+
if decl.nested_types&.any?
|
|
1866
|
+
found = find_struct_decl_by_name(decl.nested_types, name)
|
|
1867
|
+
return found if found
|
|
1868
|
+
end
|
|
1869
|
+
end
|
|
1870
|
+
nil
|
|
1871
|
+
end
|
|
1872
|
+
|
|
1873
|
+
def resolve_callable_handle_argument(expression)
|
|
1874
|
+
case expression
|
|
1875
|
+
when AST::Identifier
|
|
1876
|
+
binding = @ctx.functions[expression.name]
|
|
1877
|
+
return nil unless binding&.ast
|
|
1878
|
+
|
|
1879
|
+
Types::CallableHandle.new(expression.name, binding.ast)
|
|
1880
|
+
when AST::MemberAccess
|
|
1881
|
+
return nil unless expression.receiver.is_a?(AST::Identifier)
|
|
1882
|
+
|
|
1883
|
+
imported_module = @ctx.imports[expression.receiver.name]
|
|
1884
|
+
return nil unless imported_module
|
|
1885
|
+
return nil if imported_module.private_function?(expression.member)
|
|
1886
|
+
|
|
1887
|
+
binding = imported_module.functions[expression.member]
|
|
1888
|
+
return nil unless binding&.ast
|
|
1889
|
+
|
|
1890
|
+
Types::CallableHandle.new("#{expression.receiver.name}.#{expression.member}", binding.ast)
|
|
1891
|
+
else
|
|
1892
|
+
nil
|
|
1893
|
+
end
|
|
1894
|
+
end
|
|
1895
|
+
|
|
1896
|
+
def resolve_attribute_name_argument(expression)
|
|
1897
|
+
case expression
|
|
1898
|
+
when AST::Identifier
|
|
1899
|
+
@ctx.attributes[expression.name] || builtin_attribute_binding(expression.name)
|
|
1900
|
+
when AST::MemberAccess
|
|
1901
|
+
return nil unless expression.receiver.is_a?(AST::Identifier)
|
|
1902
|
+
|
|
1903
|
+
imported_module = @ctx.imports[expression.receiver.name]
|
|
1904
|
+
return nil unless imported_module
|
|
1905
|
+
return nil if imported_module.private_attribute?(expression.member)
|
|
1906
|
+
|
|
1907
|
+
imported_module.attributes[expression.member]
|
|
1908
|
+
else
|
|
1909
|
+
nil
|
|
1910
|
+
end
|
|
1911
|
+
end
|
|
1912
|
+
|
|
1913
|
+
def reflection_identifier_name(expression)
|
|
1914
|
+
expression.is_a?(AST::Identifier) ? expression.name : nil
|
|
1915
|
+
end
|
|
1916
|
+
|
|
1917
|
+
def attribute_binding_supports_target?(binding, target)
|
|
1918
|
+
binding && target && binding.targets.include?(attribute_target_kind(target))
|
|
1919
|
+
end
|
|
1920
|
+
|
|
1921
|
+
def attribute_target_kind(target)
|
|
1922
|
+
case target
|
|
1923
|
+
when Types::StructHandle then :struct
|
|
1924
|
+
when Types::FieldHandle then :field
|
|
1925
|
+
when Types::CallableHandle then :callable
|
|
1926
|
+
end
|
|
1927
|
+
end
|
|
1928
|
+
|
|
1929
|
+
def resolved_attribute_applications_for_target(target)
|
|
1930
|
+
target_id = case target
|
|
1931
|
+
when Types::StructHandle then target.declaration.object_id
|
|
1932
|
+
when Types::FieldHandle then target.field_declaration.object_id
|
|
1933
|
+
when Types::CallableHandle then target.declaration.object_id
|
|
1934
|
+
end
|
|
1935
|
+
return [] unless target_id
|
|
1936
|
+
|
|
1937
|
+
applications = @ctx.attribute_applications[target_id]
|
|
1938
|
+
return applications if applications
|
|
1939
|
+
|
|
1940
|
+
@ctx.imports.each_value do |imported_module|
|
|
1941
|
+
applications = imported_module.attribute_applications[target_id]
|
|
1942
|
+
return applications if applications
|
|
1943
|
+
end
|
|
1944
|
+
|
|
1945
|
+
[]
|
|
1946
|
+
end
|
|
1947
|
+
|
|
1948
|
+
def find_attribute_application(target, binding)
|
|
1949
|
+
resolved_attribute_applications_for_target(target).find do |application|
|
|
1950
|
+
same_attribute_binding?(application.binding, binding)
|
|
1951
|
+
end
|
|
1952
|
+
end
|
|
1953
|
+
|
|
1954
|
+
def same_attribute_binding?(left, right)
|
|
1955
|
+
left.name == right.name && left.module_name == right.module_name
|
|
1956
|
+
end
|
|
1957
|
+
|
|
1958
|
+
def builtin_attribute_binding(name)
|
|
1959
|
+
MilkTea.builtin_attribute_binding(name, @ctx.types)
|
|
1960
|
+
end
|
|
1961
|
+
|
|
1962
|
+
def specialize_function_binding(binding, arguments, env, receiver_type: nil)
|
|
1963
|
+
return binding if binding.type_params.empty?
|
|
1964
|
+
raise LoweringError, "generic function #{binding.name} must be called" unless arguments
|
|
1965
|
+
|
|
1966
|
+
type_arguments = infer_function_type_arguments(binding, arguments, env, receiver_type:)
|
|
1967
|
+
instantiate_function_binding(binding, type_arguments)
|
|
1968
|
+
end
|
|
1969
|
+
|
|
1970
|
+
def instantiate_function_binding_with_receiver(binding, explicit_type_arguments, receiver_type: nil)
|
|
1971
|
+
if binding.type_params.empty?
|
|
1972
|
+
raise LoweringError, "function #{binding.name} is not generic and cannot be specialized"
|
|
1973
|
+
end
|
|
1974
|
+
|
|
1975
|
+
receiver_substitutions = infer_receiver_type_substitutions(binding, receiver_type)
|
|
1976
|
+
remaining_type_params = binding.type_params.reject { |name| receiver_substitutions.key?(name) }
|
|
1977
|
+
unless remaining_type_params.length == explicit_type_arguments.length
|
|
1978
|
+
raise LoweringError, "function #{binding.name} expects #{remaining_type_params.length} type arguments, got #{explicit_type_arguments.length}"
|
|
1979
|
+
end
|
|
1980
|
+
|
|
1981
|
+
substitutions = receiver_substitutions.dup
|
|
1982
|
+
remaining_type_params.zip(explicit_type_arguments).each do |name, type_argument|
|
|
1983
|
+
raise LoweringError, "generic function #{binding.name} cannot be instantiated with ref types" if contains_ref_type?(type_argument)
|
|
1984
|
+
|
|
1985
|
+
substitutions[name] = type_argument
|
|
1986
|
+
end
|
|
1987
|
+
|
|
1988
|
+
type_arguments = binding.type_params.map do |name|
|
|
1989
|
+
inferred = substitutions[name]
|
|
1990
|
+
raise LoweringError, "cannot infer type argument #{name} for function #{binding.name}" unless inferred
|
|
1991
|
+
|
|
1992
|
+
inferred
|
|
1993
|
+
end
|
|
1994
|
+
|
|
1995
|
+
instantiate_function_binding(binding, type_arguments)
|
|
1996
|
+
end
|
|
1997
|
+
|
|
1998
|
+
def instantiate_function_binding(binding, type_arguments)
|
|
1999
|
+
if binding.type_params.empty?
|
|
2000
|
+
raise LoweringError, "function #{binding.name} is not generic and cannot be specialized"
|
|
2001
|
+
end
|
|
2002
|
+
|
|
2003
|
+
unless binding.type_params.length == type_arguments.length
|
|
2004
|
+
raise LoweringError, "function #{binding.name} expects #{binding.type_params.length} type arguments, got #{type_arguments.length}"
|
|
2005
|
+
end
|
|
2006
|
+
|
|
2007
|
+
if type_arguments.any? { |type_argument| contains_ref_type?(type_argument) }
|
|
2008
|
+
raise LoweringError, "generic function #{binding.name} cannot be instantiated with ref types"
|
|
2009
|
+
end
|
|
2010
|
+
|
|
2011
|
+
key = type_arguments.freeze
|
|
2012
|
+
return binding.instances.fetch(key) if binding.instances.key?(key)
|
|
2013
|
+
|
|
2014
|
+
substitutions = binding.type_params.zip(type_arguments).to_h
|
|
2015
|
+
validate_function_type_param_constraints!(binding, substitutions)
|
|
2016
|
+
instance = FunctionBinding.new(
|
|
2017
|
+
name: binding.name,
|
|
2018
|
+
type: substitute_type(binding.type, substitutions),
|
|
2019
|
+
body_params: binding.body_params.map { |param| substitute_value_binding(param, substitutions) },
|
|
2020
|
+
body_return_type: substitute_type(binding.body_return_type, substitutions),
|
|
2021
|
+
ast: binding.ast,
|
|
2022
|
+
external: binding.external,
|
|
2023
|
+
async: binding.async,
|
|
2024
|
+
type_params: [].freeze,
|
|
2025
|
+
type_param_constraints: {}.freeze,
|
|
2026
|
+
instances: {},
|
|
2027
|
+
type_arguments: key,
|
|
2028
|
+
owner: binding.owner,
|
|
2029
|
+
specialization_owner: nil,
|
|
2030
|
+
type_substitutions: substitutions.freeze,
|
|
2031
|
+
declared_receiver_type: binding.declared_receiver_type ? substitute_type(binding.declared_receiver_type, substitutions) : nil,
|
|
2032
|
+
)
|
|
2033
|
+
binding.instances[key] = instance
|
|
2034
|
+
end
|
|
2035
|
+
|
|
2036
|
+
def validate_function_type_param_constraints!(binding, substitutions)
|
|
2037
|
+
binding.type_param_constraints.each do |name, constraints|
|
|
2038
|
+
actual_type = substitutions[name]
|
|
2039
|
+
raise LoweringError, "cannot infer type argument #{name} for function #{binding.name}" unless actual_type
|
|
2040
|
+
|
|
2041
|
+
constraints.interfaces.each do |interface|
|
|
2042
|
+
next if type_implements_interface?(actual_type, interface)
|
|
2043
|
+
|
|
2044
|
+
raise LoweringError, "type #{actual_type} does not implement interface #{interface.name} for function #{binding.name}"
|
|
2045
|
+
end
|
|
2046
|
+
end
|
|
2047
|
+
end
|
|
2048
|
+
|
|
2049
|
+
|
|
2050
|
+
def interface_implementation_key(type)
|
|
2051
|
+
return type.definition if type.is_a?(Types::StructInstance)
|
|
2052
|
+
|
|
2053
|
+
type
|
|
2054
|
+
end
|
|
2055
|
+
|
|
2056
|
+
def type_implements_interface?(type, interface)
|
|
2057
|
+
key = interface_implementation_key(type)
|
|
2058
|
+
return true if @ctx.implemented_interfaces.fetch(key, []).include?(interface)
|
|
2059
|
+
|
|
2060
|
+
@ctx.imports.each_value do |module_binding|
|
|
2061
|
+
return true if module_binding.implemented_interfaces.fetch(key, []).include?(interface)
|
|
2062
|
+
end
|
|
2063
|
+
|
|
2064
|
+
false
|
|
2065
|
+
end
|
|
2066
|
+
|
|
2067
|
+
def infer_function_type_arguments(binding, arguments, env, receiver_type: nil)
|
|
2068
|
+
expected_params = binding.type.params
|
|
2069
|
+
unless call_arity_matches?(binding.type, arguments.length)
|
|
2070
|
+
raise LoweringError, arity_error_message(binding.type, binding.name, arguments.length)
|
|
2071
|
+
end
|
|
2072
|
+
|
|
2073
|
+
substitutions = infer_receiver_type_substitutions(binding, receiver_type)
|
|
2074
|
+
expected_params.each_with_index do |parameter, index|
|
|
2075
|
+
argument = arguments.fetch(index)
|
|
2076
|
+
candidate_type = substitute_type(parameter.type, substitutions)
|
|
2077
|
+
expected_argument_type = if callable_type?(candidate_type)
|
|
2078
|
+
candidate_type
|
|
2079
|
+
elsif contains_type_var?(candidate_type)
|
|
2080
|
+
nil
|
|
2081
|
+
else
|
|
2082
|
+
candidate_type
|
|
2083
|
+
end
|
|
2084
|
+
actual_type = infer_expression_type(argument.value, env:, expected_type: expected_argument_type)
|
|
2085
|
+
collect_type_substitutions(parameter.type, actual_type, substitutions, binding.name)
|
|
2086
|
+
end
|
|
2087
|
+
|
|
2088
|
+
binding.type_params.map do |name|
|
|
2089
|
+
inferred = substitutions[name]
|
|
2090
|
+
raise LoweringError, "cannot infer type argument #{name} for function #{binding.name}" unless inferred
|
|
2091
|
+
|
|
2092
|
+
inferred
|
|
2093
|
+
end
|
|
2094
|
+
end
|
|
2095
|
+
|
|
2096
|
+
|
|
2097
|
+
|
|
2098
|
+
def resolve_named_generic_type_for_analysis(analysis, parts)
|
|
2099
|
+
if parts.length == 1
|
|
2100
|
+
type = analysis.types[parts.first]
|
|
2101
|
+
return type if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
|
|
2102
|
+
elsif parts.length == 2 && analysis.imports.key?(parts.first)
|
|
2103
|
+
type = analysis.imports.fetch(parts.first).types[parts.last]
|
|
2104
|
+
return type if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
|
|
2105
|
+
end
|
|
2106
|
+
|
|
2107
|
+
nil
|
|
2108
|
+
end
|
|
2109
|
+
|
|
2110
|
+
def validate_methods_receiver_type_arguments!(type_ref, generic_type)
|
|
2111
|
+
names = type_ref.arguments.map do |argument|
|
|
2112
|
+
value = argument.value
|
|
2113
|
+
next unless value.is_a?(AST::TypeRef)
|
|
2114
|
+
next unless value.arguments.empty? && !value.nullable && value.name.parts.length == 1
|
|
2115
|
+
|
|
2116
|
+
value.name.parts.first
|
|
2117
|
+
end
|
|
2118
|
+
|
|
2119
|
+
expected_names = generic_type.type_params
|
|
2120
|
+
unless names == expected_names
|
|
2121
|
+
raise LoweringError, "extending target #{type_ref} must use the receiver type parameters directly"
|
|
2122
|
+
end
|
|
2123
|
+
|
|
2124
|
+
expected_names
|
|
2125
|
+
end
|
|
2126
|
+
|
|
2127
|
+
def methods_receiver_type_argument_names!(type_ref)
|
|
2128
|
+
names = type_ref.arguments.map do |argument|
|
|
2129
|
+
value = argument.value
|
|
2130
|
+
next unless value.is_a?(AST::TypeRef)
|
|
2131
|
+
next unless value.arguments.empty? && !value.nullable && value.name.parts.length == 1
|
|
2132
|
+
|
|
2133
|
+
value.name.parts.first
|
|
2134
|
+
end
|
|
2135
|
+
|
|
2136
|
+
raise LoweringError, "extending target #{type_ref} must use the receiver type parameters directly" if names.any?(&:nil?)
|
|
2137
|
+
|
|
2138
|
+
names
|
|
2139
|
+
end
|
|
2140
|
+
|
|
2141
|
+
def infer_receiver_type_substitutions(binding, receiver_type)
|
|
2142
|
+
declared_receiver_type = binding.declared_receiver_type
|
|
2143
|
+
return {} unless declared_receiver_type
|
|
2144
|
+
case declared_receiver_type
|
|
2145
|
+
when Types::Nullable
|
|
2146
|
+
unless receiver_type.is_a?(Types::Nullable)
|
|
2147
|
+
raise LoweringError, "cannot use method #{binding.name} with receiver #{receiver_type}"
|
|
2148
|
+
end
|
|
2149
|
+
|
|
2150
|
+
infer_receiver_type_substitutions(
|
|
2151
|
+
binding.with(declared_receiver_type: declared_receiver_type.base),
|
|
2152
|
+
receiver_type.base,
|
|
2153
|
+
)
|
|
2154
|
+
when Types::StructInstance
|
|
2155
|
+
return {} unless declared_receiver_type.definition.is_a?(Types::GenericStructDefinition)
|
|
2156
|
+
|
|
2157
|
+
unless receiver_type.is_a?(Types::StructInstance) && receiver_type.definition == declared_receiver_type.definition
|
|
2158
|
+
raise LoweringError, "cannot use method #{binding.name} with receiver #{receiver_type}"
|
|
2159
|
+
end
|
|
2160
|
+
|
|
2161
|
+
declared_receiver_type.definition.type_params.zip(receiver_type.arguments).to_h
|
|
2162
|
+
when Types::VariantInstance
|
|
2163
|
+
return {} unless declared_receiver_type.definition.is_a?(Types::GenericVariantDefinition)
|
|
2164
|
+
|
|
2165
|
+
unless receiver_type.is_a?(Types::VariantInstance) && receiver_type.definition == declared_receiver_type.definition
|
|
2166
|
+
raise LoweringError, "cannot use method #{binding.name} with receiver #{receiver_type}"
|
|
2167
|
+
end
|
|
2168
|
+
|
|
2169
|
+
declared_receiver_type.definition.type_params.zip(receiver_type.arguments).to_h
|
|
2170
|
+
when Types::GenericInstance
|
|
2171
|
+
unless receiver_type.is_a?(Types::GenericInstance) && receiver_type.name == declared_receiver_type.name && receiver_type.arguments.length == declared_receiver_type.arguments.length
|
|
2172
|
+
raise LoweringError, "cannot use method #{binding.name} with receiver #{receiver_type}"
|
|
2173
|
+
end
|
|
2174
|
+
|
|
2175
|
+
declared_receiver_type.arguments.zip(receiver_type.arguments).each_with_object({}) do |(declared_argument, actual_argument), substitutions|
|
|
2176
|
+
if declared_argument.is_a?(Types::TypeVar)
|
|
2177
|
+
substitutions[declared_argument.name] = actual_argument
|
|
2178
|
+
elsif declared_argument != actual_argument
|
|
2179
|
+
raise LoweringError, "cannot use method #{binding.name} with receiver #{receiver_type}"
|
|
2180
|
+
end
|
|
2181
|
+
end
|
|
2182
|
+
else
|
|
2183
|
+
{}
|
|
2184
|
+
end
|
|
2185
|
+
end
|
|
2186
|
+
|
|
2187
|
+
def collect_type_substitutions(pattern_type, actual_type, substitutions, function_name)
|
|
2188
|
+
case pattern_type
|
|
2189
|
+
when Types::TypeVar
|
|
2190
|
+
existing = substitutions[pattern_type.name]
|
|
2191
|
+
if existing && existing != actual_type
|
|
2192
|
+
raise LoweringError, "conflicting type argument #{pattern_type.name} for function #{function_name}: got #{existing} and #{actual_type}"
|
|
2193
|
+
end
|
|
2194
|
+
|
|
2195
|
+
substitutions[pattern_type.name] ||= actual_type
|
|
2196
|
+
when Types::Nullable
|
|
2197
|
+
candidate = actual_type.is_a?(Types::Nullable) ? actual_type.base : actual_type
|
|
2198
|
+
collect_type_substitutions(pattern_type.base, candidate, substitutions, function_name)
|
|
2199
|
+
when Types::GenericInstance
|
|
2200
|
+
if ref_type?(pattern_type) && !ref_type?(actual_type)
|
|
2201
|
+
collect_type_substitutions(referenced_type(pattern_type), actual_type, substitutions, function_name)
|
|
2202
|
+
return
|
|
2203
|
+
end
|
|
2204
|
+
|
|
2205
|
+
if own_type?(actual_type) && (mutable_pointer_type?(pattern_type) || const_pointer_type?(pattern_type))
|
|
2206
|
+
collect_type_substitutions(pointee_type(pattern_type), owned_referent_type(actual_type), substitutions, function_name)
|
|
2207
|
+
return
|
|
2208
|
+
end
|
|
2209
|
+
|
|
2210
|
+
return unless actual_type.is_a?(Types::GenericInstance)
|
|
2211
|
+
return unless actual_type.name == pattern_type.name && actual_type.arguments.length == pattern_type.arguments.length
|
|
2212
|
+
|
|
2213
|
+
pattern_type.arguments.zip(actual_type.arguments).each do |expected_argument, actual_argument|
|
|
2214
|
+
next if expected_argument.is_a?(Types::LiteralTypeArg)
|
|
2215
|
+
|
|
2216
|
+
collect_type_substitutions(expected_argument, actual_argument, substitutions, function_name)
|
|
2217
|
+
end
|
|
2218
|
+
when Types::Span
|
|
2219
|
+
return unless actual_type.is_a?(Types::Span)
|
|
2220
|
+
|
|
2221
|
+
collect_type_substitutions(pattern_type.element_type, actual_type.element_type, substitutions, function_name)
|
|
2222
|
+
when Types::Task
|
|
2223
|
+
return unless actual_type.is_a?(Types::Task)
|
|
2224
|
+
|
|
2225
|
+
collect_type_substitutions(pattern_type.result_type, actual_type.result_type, substitutions, function_name)
|
|
2226
|
+
when Types::Proc
|
|
2227
|
+
if task_root_proc_type?(pattern_type) && actual_type.is_a?(Types::Task)
|
|
2228
|
+
collect_type_substitutions(pattern_type.return_type, actual_type, substitutions, function_name)
|
|
2229
|
+
return
|
|
2230
|
+
end
|
|
2231
|
+
|
|
2232
|
+
actual_params = case actual_type
|
|
2233
|
+
when Types::Proc
|
|
2234
|
+
return unless actual_type.params.length == pattern_type.params.length
|
|
2235
|
+
|
|
2236
|
+
actual_type.params
|
|
2237
|
+
when Types::Function
|
|
2238
|
+
return if actual_type.receiver_type || actual_type.variadic
|
|
2239
|
+
return unless actual_type.params.length == pattern_type.params.length
|
|
2240
|
+
return unless actual_type.params.zip(pattern_type.params).all? { |actual_param, expected_param| actual_param.mutable == expected_param.mutable }
|
|
2241
|
+
|
|
2242
|
+
actual_type.params
|
|
2243
|
+
else
|
|
2244
|
+
return
|
|
2245
|
+
end
|
|
2246
|
+
|
|
2247
|
+
pattern_type.params.zip(actual_params).each do |expected_param, actual_param|
|
|
2248
|
+
collect_type_substitutions(expected_param.type, actual_param.type, substitutions, function_name)
|
|
2249
|
+
end
|
|
2250
|
+
collect_type_substitutions(pattern_type.return_type, actual_type.return_type, substitutions, function_name)
|
|
2251
|
+
when Types::StructInstance
|
|
2252
|
+
return unless actual_type.is_a?(Types::StructInstance)
|
|
2253
|
+
return unless actual_type.definition == pattern_type.definition && actual_type.arguments.length == pattern_type.arguments.length
|
|
2254
|
+
|
|
2255
|
+
pattern_type.arguments.zip(actual_type.arguments).each do |expected_argument, actual_argument|
|
|
2256
|
+
collect_type_substitutions(expected_argument, actual_argument, substitutions, function_name)
|
|
2257
|
+
end
|
|
2258
|
+
when Types::VariantInstance
|
|
2259
|
+
return unless actual_type.is_a?(Types::VariantInstance)
|
|
2260
|
+
return unless actual_type.definition == pattern_type.definition && actual_type.arguments.length == pattern_type.arguments.length
|
|
2261
|
+
|
|
2262
|
+
pattern_type.arguments.zip(actual_type.arguments).each do |expected_argument, actual_argument|
|
|
2263
|
+
collect_type_substitutions(expected_argument, actual_argument, substitutions, function_name)
|
|
2264
|
+
end
|
|
2265
|
+
when Types::Function
|
|
2266
|
+
return unless actual_type.is_a?(Types::Function)
|
|
2267
|
+
return unless actual_type.params.length == pattern_type.params.length
|
|
2268
|
+
|
|
2269
|
+
pattern_type.params.zip(actual_type.params).each do |expected_param, actual_param|
|
|
2270
|
+
collect_type_substitutions(expected_param.type, actual_param.type, substitutions, function_name)
|
|
2271
|
+
end
|
|
2272
|
+
collect_type_substitutions(pattern_type.return_type, actual_type.return_type, substitutions, function_name)
|
|
2273
|
+
end
|
|
2274
|
+
end
|
|
2275
|
+
|
|
2276
|
+
def substitute_value_binding(binding, substitutions)
|
|
2277
|
+
ValueBinding.new(
|
|
2278
|
+
id: binding.id,
|
|
2279
|
+
name: binding.name,
|
|
2280
|
+
storage_type: substitute_type(binding.storage_type, substitutions),
|
|
2281
|
+
flow_type: binding.flow_type ? substitute_type(binding.flow_type, substitutions) : nil,
|
|
2282
|
+
mutable: binding.mutable,
|
|
2283
|
+
kind: binding.kind,
|
|
2284
|
+
const_value: binding.const_value,
|
|
2285
|
+
)
|
|
2286
|
+
end
|
|
2287
|
+
|
|
2288
|
+
def substitute_type(type, substitutions)
|
|
2289
|
+
SubstituteTypeVisitor.new(substitutions).apply(type)
|
|
2290
|
+
end
|
|
2291
|
+
|
|
2292
|
+
def analysis_for_module(module_name)
|
|
2293
|
+
@program.analyses_by_module_name.fetch(module_name)
|
|
2294
|
+
end
|
|
2295
|
+
|
|
2296
|
+
def each_raw_module_analysis(&block)
|
|
2297
|
+
return @program.analyses_by_module_name.each_value.select { |a| a.module_kind == :raw_module }.each unless block
|
|
2298
|
+
@program.analyses_by_module_name.each_value { |a| block.call(a) if a.module_kind == :raw_module }
|
|
2299
|
+
end
|
|
2300
|
+
|
|
2301
|
+
def each_non_raw_module_analysis(&block)
|
|
2302
|
+
return @program.analyses_by_module_name.each_value.reject { |a| a.module_kind == :raw_module }.each unless block
|
|
2303
|
+
@program.analyses_by_module_name.each_value { |a| block.call(a) unless a.module_kind == :raw_module }
|
|
2304
|
+
end
|
|
2305
|
+
|
|
2306
|
+
def types_for_module(module_name)
|
|
2307
|
+
@program.analyses_by_module_name.fetch(module_name).types
|
|
2308
|
+
end
|
|
2309
|
+
|
|
2310
|
+
def imports_for_module(module_name)
|
|
2311
|
+
@program.analyses_by_module_name.fetch(module_name).imports
|
|
2312
|
+
end
|
|
2313
|
+
|
|
2314
|
+
def const_declaration_for_module(module_name, name)
|
|
2315
|
+
analysis = @program.analyses_by_module_name.fetch(module_name)
|
|
2316
|
+
declaration = analysis.ast.declarations.find { |decl| decl.is_a?(AST::ConstDecl) && decl.name == name }
|
|
2317
|
+
raise LoweringError, "unknown constant #{analysis.module_name}.#{name}" unless declaration
|
|
2318
|
+
|
|
2319
|
+
declaration
|
|
2320
|
+
end
|
|
2321
|
+
|
|
2322
|
+
def resolve_type_ref_for_analysis(type_ref, analysis, type_params: current_type_params)
|
|
2323
|
+
saved = @ctx.save
|
|
2324
|
+
@ctx.install(analysis)
|
|
2325
|
+
@ctx.module_prefix = module_c_prefix(@ctx.module_name)
|
|
2326
|
+
resolve_type_ref(type_ref, type_params:)
|
|
2327
|
+
ensure
|
|
2328
|
+
@ctx.restore(saved)
|
|
2329
|
+
end
|
|
2330
|
+
|
|
2331
|
+
def current_type_params
|
|
2332
|
+
@ctx.current_type_substitutions || {}
|
|
2333
|
+
end
|
|
2334
|
+
|
|
2335
|
+
def resolve_type_ref(type_ref, type_params: current_type_params)
|
|
2336
|
+
if type_ref.is_a?(AST::FunctionType)
|
|
2337
|
+
params = type_ref.params.map do |param|
|
|
2338
|
+
Types::Registry.parameter(param.name, resolve_type_ref(param.type, type_params:))
|
|
2339
|
+
end
|
|
2340
|
+
return Types::Registry.function(nil, params:, return_type: resolve_type_ref(type_ref.return_type, type_params:))
|
|
2341
|
+
end
|
|
2342
|
+
|
|
2343
|
+
if type_ref.is_a?(AST::ProcType)
|
|
2344
|
+
params = type_ref.params.map do |param|
|
|
2345
|
+
Types::Registry.parameter(param.name, resolve_type_ref(param.type, type_params:))
|
|
2346
|
+
end
|
|
2347
|
+
return Types::Registry.proc(params:, return_type: resolve_type_ref(type_ref.return_type, type_params:))
|
|
2348
|
+
end
|
|
2349
|
+
|
|
2350
|
+
if type_ref.is_a?(AST::DynType)
|
|
2351
|
+
interface = resolve_interface_ref(type_ref.interface)
|
|
2352
|
+
raise LoweringError, "generic interface requires type arguments" if interface.respond_to?(:instantiate)
|
|
2353
|
+
type_arguments = interface.respond_to?(:type_arguments) ? (interface.type_arguments || []) : []
|
|
2354
|
+
return Types::Dyn.new(interface, type_arguments)
|
|
2355
|
+
end
|
|
2356
|
+
|
|
2357
|
+
if type_ref.is_a?(AST::TupleType)
|
|
2358
|
+
names = []
|
|
2359
|
+
element_types = []
|
|
2360
|
+
type_ref.element_types.each do |et|
|
|
2361
|
+
if et.is_a?(AST::Argument)
|
|
2362
|
+
names << et.name
|
|
2363
|
+
element_types << resolve_type_ref(et.value, type_params:)
|
|
2364
|
+
else
|
|
2365
|
+
names << nil
|
|
2366
|
+
element_types << resolve_type_ref(et, type_params:)
|
|
2367
|
+
end
|
|
2368
|
+
end
|
|
2369
|
+
has_named = names.any?
|
|
2370
|
+
return Types::Registry.tuple(element_types, field_names: has_named ? names : nil)
|
|
2371
|
+
end
|
|
2372
|
+
|
|
2373
|
+
parts = type_ref.name.parts
|
|
2374
|
+
base = if type_ref.arguments.any?
|
|
2375
|
+
name = parts.join(".")
|
|
2376
|
+
args = type_ref.arguments.map { |argument| resolve_type_argument(argument.value, type_params:) }
|
|
2377
|
+
if name != "ref" && args.any? { |argument| contains_ref_type?(argument) && !stored_ref_supported_type?(argument) }
|
|
2378
|
+
raise LoweringError, "ref types cannot be nested inside #{name}"
|
|
2379
|
+
end
|
|
2380
|
+
if name == "Task"
|
|
2381
|
+
validate_generic_type!(name, args)
|
|
2382
|
+
Types::Registry.task(args.fetch(0))
|
|
2383
|
+
elsif (generic_type = resolve_named_generic_type(parts))
|
|
2384
|
+
generic_type.instantiate(args)
|
|
2385
|
+
elsif name == "span"
|
|
2386
|
+
Types::Registry.span(args.fetch(0))
|
|
2387
|
+
elsif name == "SoA"
|
|
2388
|
+
validate_generic_type!(name, args)
|
|
2389
|
+
Types::Registry.soa(args.fetch(0), count: args.fetch(1).value)
|
|
2390
|
+
else
|
|
2391
|
+
validate_generic_type!(name, args)
|
|
2392
|
+
args = [type_ref.lifetime] + args if name == "ref" && type_ref.lifetime
|
|
2393
|
+
Types::Registry.generic_instance(name, args)
|
|
2394
|
+
end
|
|
2395
|
+
elsif parts.length == 1 && type_params.key?(parts.first)
|
|
2396
|
+
type_params.fetch(parts.first)
|
|
2397
|
+
elsif parts.length == 1
|
|
2398
|
+
type = @ctx.types[parts.first]
|
|
2399
|
+
raise LoweringError, "unknown type #{parts.first}" unless type
|
|
2400
|
+
raise LoweringError, "generic type #{parts.first} requires type arguments" if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
|
|
2401
|
+
|
|
2402
|
+
type
|
|
2403
|
+
elsif parts.length >= 2
|
|
2404
|
+
type = resolve_nested_type_ref(parts)
|
|
2405
|
+
|
|
2406
|
+
unless type
|
|
2407
|
+
if @ctx.imports.key?(parts.first)
|
|
2408
|
+
imported_module = @ctx.imports.fetch(parts.first)
|
|
2409
|
+
if imported_module.private_type?(parts.last)
|
|
2410
|
+
raise LoweringError, "#{parts.first}.#{parts.last} is private to module #{imported_module.name}"
|
|
2411
|
+
end
|
|
2412
|
+
|
|
2413
|
+
type = imported_module.types[parts.last]
|
|
2414
|
+
raise LoweringError, "unknown type #{type_ref.name}" unless type
|
|
2415
|
+
raise LoweringError, "generic type #{type_ref.name} requires type arguments" if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
|
|
2416
|
+
elsif @type_resolution_env && (field_type = resolve_field_handle_type_ref(parts))
|
|
2417
|
+
type = field_type
|
|
2418
|
+
else
|
|
2419
|
+
raise LoweringError, "unknown type #{type_ref.name}"
|
|
2420
|
+
end
|
|
2421
|
+
end
|
|
2422
|
+
|
|
2423
|
+
type
|
|
2424
|
+
else
|
|
2425
|
+
raise LoweringError, "unknown type #{type_ref.name}"
|
|
2426
|
+
end
|
|
2427
|
+
|
|
2428
|
+
raise LoweringError, "ref types are non-null and cannot be nullable" if type_ref.nullable && ref_type?(base)
|
|
2429
|
+
|
|
2430
|
+
type_ref.nullable ? Types::Registry.nullable(base) : base
|
|
2431
|
+
end
|
|
2432
|
+
|
|
2433
|
+
def resolve_nested_type_ref(parts)
|
|
2434
|
+
current = @ctx.types[parts.first]
|
|
2435
|
+
return nil unless current.is_a?(Types::Struct) || current.is_a?(Types::GenericStructDefinition)
|
|
2436
|
+
|
|
2437
|
+
parts[1..].each do |part|
|
|
2438
|
+
nested = current.respond_to?(:nested_types) ? current.nested_types[part] : nil
|
|
2439
|
+
return nil unless nested
|
|
2440
|
+
current = nested
|
|
2441
|
+
end
|
|
2442
|
+
current
|
|
2443
|
+
end
|
|
2444
|
+
|
|
2445
|
+
def resolve_named_generic_type(parts)
|
|
2446
|
+
if parts.length == 1
|
|
2447
|
+
type = @ctx.types[parts.first]
|
|
2448
|
+
return type if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
|
|
2449
|
+
elsif parts.length >= 2
|
|
2450
|
+
type = resolve_nested_type_ref(parts)
|
|
2451
|
+
return type if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
|
|
2452
|
+
if @ctx.imports.key?(parts.first)
|
|
2453
|
+
type = @ctx.imports.fetch(parts.first).types[parts.last]
|
|
2454
|
+
return type if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
|
|
2455
|
+
end
|
|
2456
|
+
end
|
|
2457
|
+
|
|
2458
|
+
nil
|
|
2459
|
+
end
|
|
2460
|
+
|
|
2461
|
+
# Resolves a bare dotted reflection type ref `field.type` (where `field` is
|
|
2462
|
+
# a compile-time `field_handle` bound in the active inline-for env) to the
|
|
2463
|
+
# field's concrete type. Mirrors the sema-side `resolve_compile_time_type_ref`.
|
|
2464
|
+
def resolve_field_handle_type_ref(parts)
|
|
2465
|
+
return nil unless parts.length == 2 && parts.last == "type"
|
|
2466
|
+
|
|
2467
|
+
binding = lookup_value(parts.first, @type_resolution_env)
|
|
2468
|
+
handle = binding && binding[:const_value]
|
|
2469
|
+
return nil unless handle.is_a?(Types::FieldHandle)
|
|
2470
|
+
|
|
2471
|
+
# Use the struct's already-resolved field type (module-independent) rather
|
|
2472
|
+
# than re-resolving the field's declared TypeRef, which would look up a
|
|
2473
|
+
# user struct name in this (std) module's scope and fail.
|
|
2474
|
+
handle.struct_handle.struct_type.field(handle.field_name)
|
|
2475
|
+
end
|
|
2476
|
+
|
|
2477
|
+
def infer_field_handle_member_type(expression)
|
|
2478
|
+
case expression.member
|
|
2479
|
+
when "name" then @ctx.types["str"]
|
|
2480
|
+
when "type"
|
|
2481
|
+
handle = compile_time_const_value(expression.receiver, env: nil)
|
|
2482
|
+
return @error_type unless handle.is_a?(Types::FieldHandle)
|
|
2483
|
+
|
|
2484
|
+
resolve_type_ref(handle.field_declaration.type)
|
|
2485
|
+
else
|
|
2486
|
+
@error_type
|
|
2487
|
+
end
|
|
2488
|
+
end
|
|
2489
|
+
|
|
2490
|
+
def infer_member_handle_member_type(expression)
|
|
2491
|
+
case expression.member
|
|
2492
|
+
when "name" then @ctx.types["str"]
|
|
2493
|
+
when "value" then @ctx.types["int"]
|
|
2494
|
+
else @error_type
|
|
2495
|
+
end
|
|
2496
|
+
end
|
|
2497
|
+
|
|
2498
|
+
def resolve_interface_ref(interface_ref)
|
|
2499
|
+
parts = interface_ref.parts
|
|
2500
|
+
interface = if parts.length == 1
|
|
2501
|
+
@ctx.interfaces[parts.first]
|
|
2502
|
+
elsif parts.length == 2 && @ctx.imports.key?(parts.first)
|
|
2503
|
+
@ctx.imports.fetch(parts.first).interfaces[parts.last]
|
|
2504
|
+
end
|
|
2505
|
+
raise LoweringError, "unknown interface #{interface_ref}" unless interface
|
|
2506
|
+
|
|
2507
|
+
if interface_ref.type_arguments.any?
|
|
2508
|
+
raise LoweringError, "interface #{interface.name} is not generic" unless interface.respond_to?(:instantiate)
|
|
2509
|
+
type_args = interface_ref.type_arguments.map { |arg| resolve_type_ref(arg) }
|
|
2510
|
+
interface.instantiate(type_args)
|
|
2511
|
+
else
|
|
2512
|
+
interface
|
|
2513
|
+
end
|
|
2514
|
+
end
|
|
2515
|
+
end
|
|
2516
|
+
end
|