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,1735 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MilkTea
|
|
4
|
+
class SemanticAnalyzer
|
|
5
|
+
class Checker
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def infer_lvalue(expression, scopes:)
|
|
9
|
+
case expression
|
|
10
|
+
when AST::Identifier
|
|
11
|
+
binding = lookup_value(expression.name, scopes)
|
|
12
|
+
unless binding
|
|
13
|
+
scoped_names = scopes.flat_map { |s| s.is_a?(Hash) ? s.keys : [] }.map(&:to_s)
|
|
14
|
+
suggestion = suggest_name(expression.name, scoped_names)
|
|
15
|
+
raise_sema_error("unknown name #{expression.name}", expression, suggestion: suggestion ? "did you mean '#{suggestion}'?" : nil)
|
|
16
|
+
end
|
|
17
|
+
record_identifier_binding(expression, binding)
|
|
18
|
+
raise_sema_error("cannot assign to immutable #{expression.name}") unless binding.mutable
|
|
19
|
+
|
|
20
|
+
binding.storage_type
|
|
21
|
+
when AST::MemberAccess
|
|
22
|
+
receiver_type = infer_lvalue_receiver(expression.receiver, scopes:, allow_ref_identifier: true, allow_pointer_identifier: true, allow_span_param_identifier: true)
|
|
23
|
+
receiver_type = project_field_receiver_type(receiver_type, require_mutable_pointer: true)
|
|
24
|
+
unless aggregate_type?(receiver_type)
|
|
25
|
+
raise_sema_error("cannot assign to member #{expression.member} of #{receiver_type}")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
field_type = receiver_type.field(expression.member)
|
|
29
|
+
raise_sema_error("unknown field #{receiver_type}.#{expression.member}") unless field_type
|
|
30
|
+
|
|
31
|
+
field_type
|
|
32
|
+
when AST::IndexAccess
|
|
33
|
+
receiver_type = infer_lvalue_receiver(
|
|
34
|
+
expression.receiver,
|
|
35
|
+
scopes:,
|
|
36
|
+
allow_pointer_identifier: true,
|
|
37
|
+
require_mutable_pointer: true,
|
|
38
|
+
allow_span_param_identifier: true,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
index_type = infer_expression(expression.index, scopes:)
|
|
42
|
+
infer_index_result_type(receiver_type, index_type)
|
|
43
|
+
when AST::Call
|
|
44
|
+
if read_call?(expression)
|
|
45
|
+
validate_read_call_arguments!(expression.arguments)
|
|
46
|
+
return infer_reference_value_type(expression.arguments.first.value, scopes:)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
raise_sema_error("invalid assignment target")
|
|
50
|
+
when AST::BinaryOp
|
|
51
|
+
raise_sema_error("invalid assignment target")
|
|
52
|
+
else
|
|
53
|
+
raise_sema_error("invalid assignment target")
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def infer_lvalue_receiver(expression, scopes:, allow_ref_identifier: false, allow_pointer_identifier: false, require_mutable_pointer: false, allow_span_param_identifier: false)
|
|
58
|
+
case expression
|
|
59
|
+
when AST::Identifier
|
|
60
|
+
binding = lookup_value(expression.name, scopes)
|
|
61
|
+
raise_sema_error("unknown name #{expression.name}") unless binding
|
|
62
|
+
record_identifier_binding(expression, binding)
|
|
63
|
+
|
|
64
|
+
return referenced_type(binding.type) if allow_ref_identifier && ref_type?(binding.type)
|
|
65
|
+
if allow_pointer_identifier && pointer_type?(binding.type)
|
|
66
|
+
require_unsafe!("raw pointer dereference requires unsafe") unless own_type?(binding.type)
|
|
67
|
+
raise_sema_error("cannot assign through read-only raw pointer #{binding.type}") if require_mutable_pointer && const_pointer_type?(binding.type)
|
|
68
|
+
|
|
69
|
+
return binding.type
|
|
70
|
+
end
|
|
71
|
+
if allow_span_param_identifier && binding.kind == :param && span_type?(binding.type)
|
|
72
|
+
return binding.type
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
raise_sema_error("cannot assign through immutable #{expression.name}") unless binding.mutable
|
|
76
|
+
|
|
77
|
+
binding.type
|
|
78
|
+
when AST::MemberAccess
|
|
79
|
+
receiver_type = infer_lvalue_receiver(
|
|
80
|
+
expression.receiver,
|
|
81
|
+
scopes:,
|
|
82
|
+
allow_ref_identifier:,
|
|
83
|
+
allow_pointer_identifier:,
|
|
84
|
+
require_mutable_pointer:,
|
|
85
|
+
allow_span_param_identifier:,
|
|
86
|
+
)
|
|
87
|
+
receiver_type = project_field_receiver_type(receiver_type, require_mutable_pointer:)
|
|
88
|
+
unless aggregate_type?(receiver_type)
|
|
89
|
+
raise_sema_error("cannot access member #{expression.member} of #{receiver_type}")
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
field_type = receiver_type.field(expression.member)
|
|
93
|
+
raise_sema_error("unknown field #{receiver_type}.#{expression.member}") unless field_type
|
|
94
|
+
|
|
95
|
+
field_type
|
|
96
|
+
when AST::IndexAccess
|
|
97
|
+
receiver_type = infer_lvalue_receiver(
|
|
98
|
+
expression.receiver,
|
|
99
|
+
scopes:,
|
|
100
|
+
allow_ref_identifier:,
|
|
101
|
+
allow_pointer_identifier:,
|
|
102
|
+
require_mutable_pointer:,
|
|
103
|
+
allow_span_param_identifier:,
|
|
104
|
+
)
|
|
105
|
+
index_type = infer_expression(expression.index, scopes:)
|
|
106
|
+
infer_index_result_type(receiver_type, index_type)
|
|
107
|
+
when AST::Call
|
|
108
|
+
if read_call?(expression)
|
|
109
|
+
validate_read_call_arguments!(expression.arguments)
|
|
110
|
+
return infer_reference_value_type(expression.arguments.first.value, scopes:)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
raise_sema_error("invalid assignment target")
|
|
114
|
+
when AST::BinaryOp
|
|
115
|
+
require_unsafe!("raw pointer arithmetic as lvalue receiver requires unsafe")
|
|
116
|
+
type = infer_expression(expression, scopes:)
|
|
117
|
+
raise_sema_error("binary op lvalue receiver must be a pointer") unless pointer_type?(type)
|
|
118
|
+
raise_sema_error("cannot assign through read-only raw pointer #{type}") if require_mutable_pointer && const_pointer_type?(type)
|
|
119
|
+
|
|
120
|
+
type
|
|
121
|
+
else
|
|
122
|
+
raise_sema_error("invalid assignment target")
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def external_numeric_assignment_target?(expression, scopes:)
|
|
127
|
+
case expression
|
|
128
|
+
when AST::MemberAccess
|
|
129
|
+
receiver_type = infer_field_receiver_type(expression.receiver, scopes:, require_mutable_pointer: true)
|
|
130
|
+
receiver_type.respond_to?(:external) && receiver_type.external
|
|
131
|
+
else
|
|
132
|
+
false
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def infer_expression(expression, scopes:, expected_type: nil)
|
|
137
|
+
with_error_node(expression) do
|
|
138
|
+
type = case expression
|
|
139
|
+
when AST::ErrorExpr
|
|
140
|
+
expected_type || @error_type
|
|
141
|
+
when AST::IntegerLiteral
|
|
142
|
+
infer_integer_literal(expression, expected_type)
|
|
143
|
+
when AST::FloatLiteral
|
|
144
|
+
infer_float_literal(expression, expected_type)
|
|
145
|
+
when AST::CharLiteral
|
|
146
|
+
@ctx.types.fetch("ubyte")
|
|
147
|
+
when AST::SizeofExpr
|
|
148
|
+
unless check_layout_type_via_ct(expression.type, context: "size_of", scopes:)
|
|
149
|
+
infer_layout_query_type(expression.type, context: "size_of")
|
|
150
|
+
end
|
|
151
|
+
@ctx.types.fetch("ptr_uint")
|
|
152
|
+
when AST::AlignofExpr
|
|
153
|
+
unless check_layout_type_via_ct(expression.type, context: "align_of", scopes:)
|
|
154
|
+
infer_layout_query_type(expression.type, context: "align_of")
|
|
155
|
+
end
|
|
156
|
+
@ctx.types.fetch("ptr_uint")
|
|
157
|
+
when AST::OffsetofExpr
|
|
158
|
+
infer_offsetof_type(expression.type, expression.field, scopes:)
|
|
159
|
+
resolve_and_store_offset(expression, scopes:)
|
|
160
|
+
@ctx.types.fetch("ptr_uint")
|
|
161
|
+
when AST::StringLiteral
|
|
162
|
+
@ctx.types.fetch(expression.cstring ? "cstr" : "str")
|
|
163
|
+
when AST::FormatString
|
|
164
|
+
check_format_string_literal(expression, scopes:)
|
|
165
|
+
@ctx.types.fetch("str")
|
|
166
|
+
when AST::BooleanLiteral
|
|
167
|
+
@ctx.types.fetch("bool")
|
|
168
|
+
when AST::NullLiteral
|
|
169
|
+
infer_null_literal(expression)
|
|
170
|
+
when AST::Identifier
|
|
171
|
+
infer_identifier(expression, scopes:, expected_type:)
|
|
172
|
+
when AST::MemberAccess
|
|
173
|
+
infer_member_access(expression, scopes:, expected_type:)
|
|
174
|
+
when AST::IndexAccess
|
|
175
|
+
infer_index_access(expression, scopes:)
|
|
176
|
+
when AST::UnaryOp
|
|
177
|
+
infer_unary(expression, scopes:, expected_type:)
|
|
178
|
+
when AST::BinaryOp
|
|
179
|
+
infer_binary(expression, scopes:, expected_type:)
|
|
180
|
+
when AST::IfExpr
|
|
181
|
+
infer_if_expression(expression, scopes:, expected_type:)
|
|
182
|
+
when AST::MatchExpr
|
|
183
|
+
infer_match_expression(expression, scopes:, expected_type:)
|
|
184
|
+
when AST::UnsafeExpr
|
|
185
|
+
infer_unsafe_expression(expression, scopes:, expected_type:)
|
|
186
|
+
when AST::ProcExpr
|
|
187
|
+
infer_proc_expression(expression, scopes:, expected_type:)
|
|
188
|
+
when AST::AwaitExpr
|
|
189
|
+
infer_await_expression(expression, scopes:)
|
|
190
|
+
when AST::DetachExpr
|
|
191
|
+
@uses_parallel_for = true
|
|
192
|
+
validate_detach_expression!(expression.body.first&.expression || expression.body, scopes:)
|
|
193
|
+
check_block(expression.body, scopes:, return_type: @ctx.types.fetch("void"), allow_return: false)
|
|
194
|
+
Types::Handle.new
|
|
195
|
+
when AST::Call
|
|
196
|
+
infer_call(expression, scopes:, expected_type:)
|
|
197
|
+
when AST::PrefixCast
|
|
198
|
+
target_type = resolve_type_ref(expression.target_type)
|
|
199
|
+
check_cast_call(target_type, [AST::Argument.new(name: nil, value: expression.expression)], scopes:)
|
|
200
|
+
target_type
|
|
201
|
+
when AST::Specialization
|
|
202
|
+
if expression.callee.is_a?(AST::Identifier)
|
|
203
|
+
if expression.callee.name == "zero"
|
|
204
|
+
callable_kind, callable, = resolve_callable(expression, scopes:)
|
|
205
|
+
return check_zero_call(callable, [], expected_type:) if callable_kind == :zero
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
if expression.callee.name == "default"
|
|
209
|
+
resolution = resolve_default_specialization(expression)
|
|
210
|
+
return resolution.target_type
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
if (callable_resolution = resolve_specialized_callable_binding(expression, scopes:))
|
|
215
|
+
callable_kind, function_binding, = callable_resolution
|
|
216
|
+
raise_sema_error("specialized method #{describe_expression(expression)} must be called") if callable_kind == :method
|
|
217
|
+
|
|
218
|
+
return function_binding.type
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
raise_sema_error("specialized name #{describe_expression(expression)} must be called")
|
|
222
|
+
when AST::RangeExpr
|
|
223
|
+
raise_sema_error("range expression can only be used as a for-loop iterable or range index target")
|
|
224
|
+
when AST::ExpressionList
|
|
225
|
+
if expected_type && expected_type.is_a?(Types::GenericInstance) && expected_type.name == "array"
|
|
226
|
+
element_type = expected_type.arguments.first
|
|
227
|
+
expression.elements.each do |element|
|
|
228
|
+
value = element.is_a?(AST::Argument) ? element.value : element
|
|
229
|
+
actual = infer_expression(value, scopes:, expected_type: element_type)
|
|
230
|
+
ensure_assignable!(actual, element_type, "array element type mismatch: expected #{element_type}, got #{actual}", expression: value)
|
|
231
|
+
end
|
|
232
|
+
expected_type
|
|
233
|
+
else
|
|
234
|
+
names = []
|
|
235
|
+
element_types = []
|
|
236
|
+
expression.elements.each do |element|
|
|
237
|
+
if element.is_a?(AST::Argument)
|
|
238
|
+
names << element.name
|
|
239
|
+
element_types << infer_expression(element.value, scopes:)
|
|
240
|
+
else
|
|
241
|
+
names << nil
|
|
242
|
+
element_types << infer_expression(element, scopes:)
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
has_named = names.any?
|
|
246
|
+
Types::Registry.tuple(element_types, field_names: has_named ? names : nil)
|
|
247
|
+
end
|
|
248
|
+
else
|
|
249
|
+
raise_sema_error("unsupported expression #{expression.class.name}")
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
@resolved_expr_types[@ctx.ast.node_ids[expression.object_id]] = type
|
|
253
|
+
type
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def infer_unsafe_expression(expression, scopes:, expected_type: nil)
|
|
258
|
+
@unsafe_statement_lines << expression.line
|
|
259
|
+
begin
|
|
260
|
+
with_unsafe do
|
|
261
|
+
infer_expression(expression.expression, scopes:, expected_type:)
|
|
262
|
+
end
|
|
263
|
+
ensure
|
|
264
|
+
@unsafe_statement_lines.pop
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
def infer_integer_literal(expression, expected_type)
|
|
269
|
+
# Integer type suffixes: 42u8, 0xFFub, 100uz, etc.
|
|
270
|
+
suffix_type = integer_suffix_type(expression.lexeme)
|
|
271
|
+
return @ctx.types.fetch(suffix_type) if suffix_type
|
|
272
|
+
|
|
273
|
+
if expected_type.is_a?(Types::Primitive) && expected_type.integer? &&
|
|
274
|
+
value_fits_integer_type?(expression.value, expected_type)
|
|
275
|
+
expected_type
|
|
276
|
+
else
|
|
277
|
+
@ctx.types.fetch("int")
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
INTEGER_SUFFIX_TYPES = {
|
|
282
|
+
"ub" => "ubyte",
|
|
283
|
+
"b" => "byte",
|
|
284
|
+
"us" => "ushort",
|
|
285
|
+
"s" => "short",
|
|
286
|
+
"u" => "uint",
|
|
287
|
+
"i" => "int",
|
|
288
|
+
"ul" => "ulong",
|
|
289
|
+
"l" => "long",
|
|
290
|
+
"z" => "ptr_uint",
|
|
291
|
+
"iz" => "ptr_int",
|
|
292
|
+
}.freeze
|
|
293
|
+
|
|
294
|
+
def integer_suffix_type(lexeme)
|
|
295
|
+
INTEGER_SUFFIX_TYPES.sort_by { |k, _| -k.length }.find { |suffix, _| lexeme.end_with?(suffix) }&.last
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def infer_float_literal(expression, expected_type)
|
|
299
|
+
if expression.lexeme.end_with?("f")
|
|
300
|
+
@ctx.types.fetch("float")
|
|
301
|
+
elsif expression.lexeme.end_with?("d")
|
|
302
|
+
@ctx.types.fetch("double")
|
|
303
|
+
elsif expected_type.is_a?(Types::Primitive) && expected_type.float?
|
|
304
|
+
expected_type
|
|
305
|
+
else
|
|
306
|
+
@ctx.types.fetch("float")
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def infer_identifier(expression, scopes:, expected_type: nil)
|
|
311
|
+
binding = lookup_value(expression.name, scopes)
|
|
312
|
+
if binding
|
|
313
|
+
record_identifier_binding(expression, binding)
|
|
314
|
+
return binding.type
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
if @ctx.top_level_functions.key?(expression.name)
|
|
318
|
+
raise_sema_error("generic function #{expression.name} must be called") if @ctx.top_level_functions.fetch(expression.name).type_params.any?
|
|
319
|
+
|
|
320
|
+
function_type = function_type_for_name(expression.name)
|
|
321
|
+
if expected_type
|
|
322
|
+
record_callable_value_identifier_site(expression)
|
|
323
|
+
return function_type
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
raise_sema_error("function #{expression.name} must be called")
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
raise_sema_error("module #{expression.name} cannot be used as a value") if @ctx.imports.key?(expression.name)
|
|
330
|
+
if @ctx.types.key?(expression.name)
|
|
331
|
+
return Types::BUILTIN_TYPE_META_TYPE if expected_type.is_a?(Types::TypeType)
|
|
332
|
+
return @ctx.types.fetch(expression.name)
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
if @ctx.top_level_functions && @ctx.types && scopes
|
|
336
|
+
func_names = @ctx.top_level_functions.keys.map(&:to_s)
|
|
337
|
+
type_names = @ctx.types.keys.map(&:to_s)
|
|
338
|
+
scoped_names = scopes.flat_map { |s| s.is_a?(Hash) ? s.keys : [] }.map(&:to_s)
|
|
339
|
+
suggestion = suggest_name(expression.name, func_names + type_names + scoped_names)
|
|
340
|
+
end
|
|
341
|
+
raise_sema_error("unknown name #{expression.name}", expression, suggestion: suggestion ? "did you mean '#{suggestion}'?" : nil)
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
def infer_member_access(expression, scopes:, expected_type: nil)
|
|
345
|
+
type = resolve_type_expression(expression.receiver)
|
|
346
|
+
if type
|
|
347
|
+
return @error_type if error_type?(type)
|
|
348
|
+
|
|
349
|
+
member_type = resolve_type_member(type, expression.member)
|
|
350
|
+
return member_type if member_type
|
|
351
|
+
|
|
352
|
+
if type.is_a?(Types::Variant) && type.arm_names.include?(expression.member)
|
|
353
|
+
raise_sema_error("variant arm #{type}.#{expression.member} has payload; construct it with #{type}.#{expression.member}(field: value, ...)")
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
if (method = lookup_method(type, expression.member))
|
|
357
|
+
raise_sema_error("associated function #{type}.#{expression.member} must be called") unless method.type.receiver_type.nil?
|
|
358
|
+
raise_sema_error("method #{type}.#{expression.member} must be called")
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
raise_sema_error("unknown member #{type}.#{expression.member}")
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
if expression.receiver.is_a?(AST::Identifier) && @ctx.imports.key?(expression.receiver.name)
|
|
365
|
+
imported_module = @ctx.imports.fetch(expression.receiver.name)
|
|
366
|
+
value = imported_module.values[expression.member]
|
|
367
|
+
return value.type if value
|
|
368
|
+
|
|
369
|
+
if imported_module.functions.key?(expression.member)
|
|
370
|
+
function = imported_module.functions.fetch(expression.member)
|
|
371
|
+
raise_sema_error("generic function #{expression.receiver.name}.#{expression.member} must be called") if function.type_params.any?
|
|
372
|
+
if expected_type
|
|
373
|
+
record_callable_value_member_access_site(expression)
|
|
374
|
+
return function.type
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
raise_sema_error("function #{expression.receiver.name}.#{expression.member} must be called")
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
if imported_module.types.key?(expression.member)
|
|
381
|
+
raise_sema_error("type #{expression.receiver.name}.#{expression.member} cannot be used as a value")
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
if imported_module.private_value?(expression.member) || imported_module.private_function?(expression.member) || imported_module.private_type?(expression.member)
|
|
385
|
+
raise_sema_error("#{expression.receiver.name}.#{expression.member} is private to module #{imported_module.name}")
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
raise_sema_error("unknown member #{expression.receiver.name}.#{expression.member}")
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
field_receiver_type = infer_field_receiver_type(expression.receiver, scopes:)
|
|
392
|
+
method_receiver_type = infer_method_receiver_type(expression.receiver, scopes:, member_name: expression.member)
|
|
393
|
+
return @error_type if error_type?(field_receiver_type) || error_type?(method_receiver_type)
|
|
394
|
+
|
|
395
|
+
if array_type?(field_receiver_type) && expression.member == "as_span"
|
|
396
|
+
element_type = array_element_type(field_receiver_type)
|
|
397
|
+
return Types::Registry.span(element_type)
|
|
398
|
+
end
|
|
399
|
+
if char_array_removed_text_method?(method_receiver_type, expression.member)
|
|
400
|
+
raise_sema_error("#{method_receiver_type}.#{expression.member} is not available; array[char, N] is raw storage, use str_buffer[N] or an explicit helper")
|
|
401
|
+
end
|
|
402
|
+
if str_buffer_type?(method_receiver_type) && str_buffer_method_kind(method_receiver_type, expression.member)
|
|
403
|
+
raise_sema_error("method #{method_receiver_type}.#{expression.member} must be called")
|
|
404
|
+
end
|
|
405
|
+
if event_type?(method_receiver_type) && event_method_kind(method_receiver_type, expression.member)
|
|
406
|
+
raise_sema_error("method #{method_receiver_type}.#{expression.member} must be called")
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
unless aggregate_type?(field_receiver_type)
|
|
410
|
+
if field_receiver_type == builtin_field_handle_type
|
|
411
|
+
return infer_field_handle_member(expression, scopes:)
|
|
412
|
+
end
|
|
413
|
+
if field_receiver_type == builtin_member_handle_type
|
|
414
|
+
return infer_member_handle_member(expression)
|
|
415
|
+
end
|
|
416
|
+
raise_sema_error("cannot access member #{expression.member} of #{field_receiver_type}")
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
field_type = field_receiver_type.field(expression.member)
|
|
420
|
+
return field_type if field_type
|
|
421
|
+
|
|
422
|
+
if (event_type = event_member_type(field_receiver_type, expression.member))
|
|
423
|
+
unless event_visible_from_current_module?(event_type)
|
|
424
|
+
raise_sema_error("event #{field_receiver_type}.#{expression.member} is private to module #{event_type.module_name}")
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
return event_type
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
if lookup_method(method_receiver_type, expression.member)
|
|
431
|
+
raise_sema_error("method #{method_receiver_type.name}.#{expression.member} must be called")
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
if (imported_module = imported_module_with_private_method(method_receiver_type, expression.member))
|
|
435
|
+
raise_sema_error("#{method_receiver_type}.#{expression.member} is private to module #{imported_module.name}")
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
raise_sema_error("unknown field #{field_receiver_type}.#{expression.member}")
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
def infer_index_access(expression, scopes:)
|
|
442
|
+
receiver_type = infer_expression(expression.receiver, scopes:)
|
|
443
|
+
index_type = infer_expression(expression.index, scopes:)
|
|
444
|
+
|
|
445
|
+
if soa_type?(receiver_type)
|
|
446
|
+
return receiver_type.element_type
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
if array_type?(receiver_type) && !unsafe_context? && !addressable_storage_expression?(expression.receiver, scopes:)
|
|
450
|
+
raise_sema_error("safe array indexing requires an addressable array value; bind it to a local first")
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
infer_index_result_type(receiver_type, index_type)
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
def infer_unary(expression, scopes:, expected_type: nil)
|
|
457
|
+
return infer_propagate_expression(expression.operand, scopes:) if expression.operator == "?"
|
|
458
|
+
|
|
459
|
+
operand_type = infer_expression(expression.operand, scopes:, expected_type:)
|
|
460
|
+
|
|
461
|
+
case expression.operator
|
|
462
|
+
when "not"
|
|
463
|
+
ensure_assignable!(operand_type, @ctx.types.fetch("bool"), "operator not requires bool, got #{operand_type}")
|
|
464
|
+
@ctx.types.fetch("bool")
|
|
465
|
+
when "+", "-"
|
|
466
|
+
raise_sema_error("operator #{expression.operator} requires a numeric operand, got #{operand_type}") unless operand_type.numeric?
|
|
467
|
+
|
|
468
|
+
if expression.operator == "-" && operand_type.integer?
|
|
469
|
+
ct_value = evaluate_compile_time_const_value(expression, scopes:)
|
|
470
|
+
if ct_value.is_a?(Integer) && !value_fits_integer_type?(ct_value, operand_type)
|
|
471
|
+
raise_sema_error("negated value #{ct_value} does not fit in type #{operand_type}", expression)
|
|
472
|
+
end
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
operand_type
|
|
476
|
+
when "~"
|
|
477
|
+
raise_sema_error("operator ~ requires an integer or flags operand, got #{operand_type}") unless bitwise_type?(operand_type)
|
|
478
|
+
|
|
479
|
+
operand_type
|
|
480
|
+
when "out", "in", "inout"
|
|
481
|
+
raise_sema_error("#{expression.operator} is only allowed for foreign call arguments")
|
|
482
|
+
else
|
|
483
|
+
raise_sema_error("unsupported unary operator #{expression.operator}")
|
|
484
|
+
end
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
def infer_propagate_expression(operand, scopes:, allow_void_success: false)
|
|
488
|
+
source_type = infer_expression(operand, scopes:)
|
|
489
|
+
if result_let_else_type?(source_type)
|
|
490
|
+
infer_result_propagation(source_type, allow_void_success:)
|
|
491
|
+
elsif option_let_else_type?(source_type)
|
|
492
|
+
infer_option_propagation(source_type, allow_void_success:)
|
|
493
|
+
else
|
|
494
|
+
raise_sema_error("propagation expects Result[T, E] or Option[T], got #{source_type}")
|
|
495
|
+
end
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
def infer_result_propagation(source_type, allow_void_success:)
|
|
499
|
+
success_type = let_else_success_type(source_type)
|
|
500
|
+
error_type = let_else_error_type(source_type)
|
|
501
|
+
raise_sema_error("propagation requires a non-void Result success type") if success_type == @ctx.types.fetch("void") && !allow_void_success
|
|
502
|
+
|
|
503
|
+
context = current_return_context
|
|
504
|
+
raise_sema_error("propagation is only allowed inside function and proc bodies") unless context
|
|
505
|
+
raise_sema_error("propagation is not allowed inside defer blocks") unless context[:allow_return]
|
|
506
|
+
|
|
507
|
+
return_type = context[:return_type]
|
|
508
|
+
unless result_let_else_type?(return_type)
|
|
509
|
+
raise_sema_error("propagation requires enclosing function/proc to return Result[_, #{error_type}], got #{return_type}")
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
return_error_type = let_else_error_type(return_type)
|
|
513
|
+
unless return_error_type == error_type
|
|
514
|
+
raise_sema_error("propagation error type #{error_type} must match enclosing Result error type #{return_error_type}")
|
|
515
|
+
end
|
|
516
|
+
|
|
517
|
+
success_type
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
def infer_option_propagation(source_type, allow_void_success:)
|
|
521
|
+
success_type = let_else_success_type(source_type)
|
|
522
|
+
raise_sema_error("propagation requires a non-void Option success type") if success_type == @ctx.types.fetch("void") && !allow_void_success
|
|
523
|
+
|
|
524
|
+
context = current_return_context
|
|
525
|
+
raise_sema_error("propagation is only allowed inside function and proc bodies") unless context
|
|
526
|
+
raise_sema_error("propagation is not allowed inside defer blocks") unless context[:allow_return]
|
|
527
|
+
|
|
528
|
+
return_type = context[:return_type]
|
|
529
|
+
unless option_let_else_type?(return_type)
|
|
530
|
+
raise_sema_error("propagation requires enclosing function/proc to return Option[_], got #{return_type}")
|
|
531
|
+
end
|
|
532
|
+
|
|
533
|
+
success_type
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
def infer_binary(expression, scopes:, expected_type: nil)
|
|
538
|
+
propagated_type = propagating_expected_type(expression.operator, expected_type)
|
|
539
|
+
left_type = infer_expression(expression.left, scopes:, expected_type: propagated_type)
|
|
540
|
+
|
|
541
|
+
right_scopes = case expression.operator
|
|
542
|
+
when "and"
|
|
543
|
+
scopes_with_refinements(scopes, flow_refinements(expression.left, truthy: true, scopes:))
|
|
544
|
+
when "or"
|
|
545
|
+
scopes_with_refinements(scopes, flow_refinements(expression.left, truthy: false, scopes:))
|
|
546
|
+
else
|
|
547
|
+
scopes
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
right_expected_type = case expression.operator
|
|
551
|
+
when "<<", ">>"
|
|
552
|
+
propagated_type || left_type
|
|
553
|
+
when "+", "-", "*", "/", "%"
|
|
554
|
+
propagated_type || left_type
|
|
555
|
+
when "|", "&", "^"
|
|
556
|
+
left_type
|
|
557
|
+
else
|
|
558
|
+
left_type
|
|
559
|
+
end
|
|
560
|
+
|
|
561
|
+
right_type = infer_expression(expression.right, scopes: right_scopes, expected_type: right_expected_type)
|
|
562
|
+
left_type, right_type = harmonize_binary_float_literal_types(
|
|
563
|
+
expression.left,
|
|
564
|
+
expression.right,
|
|
565
|
+
left_type,
|
|
566
|
+
right_type,
|
|
567
|
+
scopes: right_scopes,
|
|
568
|
+
)
|
|
569
|
+
|
|
570
|
+
left_type, right_type = harmonize_binary_integer_literal_types(
|
|
571
|
+
expression.left,
|
|
572
|
+
expression.right,
|
|
573
|
+
left_type,
|
|
574
|
+
right_type,
|
|
575
|
+
scopes: right_scopes,
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
case expression.operator
|
|
579
|
+
when "and", "or"
|
|
580
|
+
ensure_assignable!(left_type, @ctx.types.fetch("bool"), "operator #{expression.operator} requires bool operands")
|
|
581
|
+
ensure_assignable!(right_type, @ctx.types.fetch("bool"), "operator #{expression.operator} requires bool operands")
|
|
582
|
+
@ctx.types.fetch("bool")
|
|
583
|
+
when "|", "&", "^"
|
|
584
|
+
# For Flags/Enum types, the operands must match and be bitwise-capable.
|
|
585
|
+
unless left_type == right_type && (bitwise_type?(left_type) || left_type.is_a?(Types::Flags))
|
|
586
|
+
raise_sema_error("operator #{expression.operator} requires matching integer or flags types, got #{left_type} and #{right_type}")
|
|
587
|
+
end
|
|
588
|
+
|
|
589
|
+
left_type
|
|
590
|
+
when "+", "-", "*", "/"
|
|
591
|
+
if expression.operator == "+" && (string_like_type?(left_type) || string_like_type?(right_type))
|
|
592
|
+
raise_sema_error("operator + does not support str/cstr concatenation; use continued string literals for static text or string.String/str_buffer for dynamic text")
|
|
593
|
+
end
|
|
594
|
+
|
|
595
|
+
pointer_result = pointer_arithmetic_result(expression.operator, left_type, right_type)
|
|
596
|
+
return pointer_result if pointer_result
|
|
597
|
+
|
|
598
|
+
vector_result = vector_arithmetic_result(expression.operator, left_type, right_type)
|
|
599
|
+
return vector_result if vector_result
|
|
600
|
+
|
|
601
|
+
result_type = common_numeric_type(left_type, right_type)
|
|
602
|
+
unless result_type
|
|
603
|
+
if left_type.respond_to?(:signed_integer?) && right_type.respond_to?(:signed_integer?) &&
|
|
604
|
+
left_type.integer? && right_type.integer? &&
|
|
605
|
+
left_type.signed_integer? != right_type.signed_integer?
|
|
606
|
+
raise_sema_error("operator #{expression.operator} requires compatible numeric types, got #{left_type} and #{right_type} (use an explicit cast to resolve signed/unsigned mismatch)")
|
|
607
|
+
else
|
|
608
|
+
raise_sema_error("operator #{expression.operator} requires compatible numeric types, got #{left_type} and #{right_type}")
|
|
609
|
+
end
|
|
610
|
+
end
|
|
611
|
+
|
|
612
|
+
result_type
|
|
613
|
+
when "%"
|
|
614
|
+
result_type = common_integer_type(left_type, right_type)
|
|
615
|
+
unless result_type
|
|
616
|
+
raise_sema_error("operator % requires compatible integer types, got #{left_type} and #{right_type}")
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
result_type
|
|
620
|
+
when "<<", ">>"
|
|
621
|
+
unless left_type.is_a?(Types::Primitive) && left_type.integer? && right_type.is_a?(Types::Primitive) && right_type.integer?
|
|
622
|
+
raise_sema_error("operator #{expression.operator} requires integer operands, got #{left_type} and #{right_type}")
|
|
623
|
+
end
|
|
624
|
+
|
|
625
|
+
left_type
|
|
626
|
+
when "<", "<=", ">", ">="
|
|
627
|
+
unless common_numeric_type(left_type, right_type)
|
|
628
|
+
raise_sema_error("operator #{expression.operator} requires compatible numeric types, got #{left_type} and #{right_type}")
|
|
629
|
+
end
|
|
630
|
+
|
|
631
|
+
@ctx.types.fetch("bool")
|
|
632
|
+
when "==", "!="
|
|
633
|
+
unless c_natively_equality_comparable_type?(left_type) && c_natively_equality_comparable_type?(right_type)
|
|
634
|
+
bad_type = c_natively_equality_comparable_type?(right_type) ? left_type : right_type
|
|
635
|
+
if struct_instance_type?(bad_type)
|
|
636
|
+
raise_sema_error("operator #{expression.operator} is not supported for struct type #{bad_type}; use equal[#{bad_type}](...) instead")
|
|
637
|
+
else
|
|
638
|
+
raise_sema_error("operator #{expression.operator} is not supported for type #{bad_type}")
|
|
639
|
+
end
|
|
640
|
+
end
|
|
641
|
+
unless common_numeric_type(left_type, right_type) || types_compatible?(left_type, right_type) || types_compatible?(right_type, left_type)
|
|
642
|
+
raise_sema_error("operator #{expression.operator} requires comparable types, got #{left_type} and #{right_type}")
|
|
643
|
+
end
|
|
644
|
+
|
|
645
|
+
@ctx.types.fetch("bool")
|
|
646
|
+
else
|
|
647
|
+
raise_sema_error("unsupported binary operator #{expression.operator}")
|
|
648
|
+
end
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
def infer_if_expression(expression, scopes:, expected_type: nil)
|
|
652
|
+
condition_type = infer_expression(expression.condition, scopes:, expected_type: @ctx.types.fetch("bool"))
|
|
653
|
+
ensure_assignable!(condition_type, @ctx.types.fetch("bool"), "if expression condition must be bool, got #{condition_type}")
|
|
654
|
+
|
|
655
|
+
then_scopes = scopes_with_refinements(scopes, flow_refinements(expression.condition, truthy: true, scopes:))
|
|
656
|
+
else_scopes = scopes_with_refinements(scopes, flow_refinements(expression.condition, truthy: false, scopes:))
|
|
657
|
+
then_type = infer_expression(expression.then_expression, scopes: then_scopes, expected_type:)
|
|
658
|
+
else_type = infer_expression(expression.else_expression, scopes: else_scopes, expected_type:)
|
|
659
|
+
|
|
660
|
+
return expected_type if expected_type &&
|
|
661
|
+
types_compatible?(then_type, expected_type, expression: expression.then_expression) &&
|
|
662
|
+
types_compatible?(else_type, expected_type, expression: expression.else_expression)
|
|
663
|
+
|
|
664
|
+
common_type = conditional_common_type(
|
|
665
|
+
then_type,
|
|
666
|
+
else_type,
|
|
667
|
+
then_expression: expression.then_expression,
|
|
668
|
+
else_expression: expression.else_expression,
|
|
669
|
+
)
|
|
670
|
+
return common_type if common_type
|
|
671
|
+
|
|
672
|
+
raise_sema_error("if expression branches require compatible types, got #{then_type} and #{else_type}")
|
|
673
|
+
end
|
|
674
|
+
|
|
675
|
+
def validate_detach_expression!(expression, scopes:)
|
|
676
|
+
case expression
|
|
677
|
+
when AST::Call, AST::Specialization
|
|
678
|
+
expression.arguments.each do |arg|
|
|
679
|
+
validate_detach_argument!(arg.value, scopes:)
|
|
680
|
+
end
|
|
681
|
+
else
|
|
682
|
+
raise_sema_error("detach currently only supports global function calls")
|
|
683
|
+
end
|
|
684
|
+
end
|
|
685
|
+
|
|
686
|
+
def validate_detach_argument!(expression, scopes:)
|
|
687
|
+
return true if expression.is_a?(AST::IntegerLiteral) || expression.is_a?(AST::FloatLiteral) ||
|
|
688
|
+
expression.is_a?(AST::StringLiteral) || expression.is_a?(AST::BooleanLiteral) ||
|
|
689
|
+
expression.is_a?(AST::NullLiteral) || expression.is_a?(AST::CharLiteral) ||
|
|
690
|
+
expression.is_a?(AST::FormatString)
|
|
691
|
+
|
|
692
|
+
if expression.is_a?(AST::Identifier)
|
|
693
|
+
binding = lookup_value(expression.name, scopes)
|
|
694
|
+
return true unless binding && %i[let var param].include?(binding.kind)
|
|
695
|
+
|
|
696
|
+
raise_sema_error("detach argument cannot capture local variable #{expression.name}")
|
|
697
|
+
end
|
|
698
|
+
|
|
699
|
+
true
|
|
700
|
+
end
|
|
701
|
+
|
|
702
|
+
def infer_match_expression(expression, scopes:, expected_type: nil)
|
|
703
|
+
validate_consuming_foreign_expression!(expression.expression, scopes:, root_allowed: false)
|
|
704
|
+
validate_hoistable_foreign_expression!(expression.expression, scopes:, root_hoistable: false)
|
|
705
|
+
scrutinee_type = infer_expression(expression.expression, scopes:)
|
|
706
|
+
|
|
707
|
+
if error_type?(scrutinee_type)
|
|
708
|
+
infer_recovered_match_expression(expression, scopes:, expected_type:)
|
|
709
|
+
elsif scrutinee_type.is_a?(Types::Enum)
|
|
710
|
+
infer_enum_match_expression(expression, scrutinee_type, scopes:, expected_type:)
|
|
711
|
+
elsif scrutinee_type.is_a?(Types::Variant)
|
|
712
|
+
infer_variant_match_expression(expression, scrutinee_type, scopes:, expected_type:)
|
|
713
|
+
elsif integer_type?(scrutinee_type)
|
|
714
|
+
infer_integer_match_expression(expression, scrutinee_type, scopes:, expected_type:)
|
|
715
|
+
elsif scrutinee_type.is_a?(Types::StringView)
|
|
716
|
+
infer_string_match_expression(expression, scrutinee_type, scopes:, expected_type:)
|
|
717
|
+
elsif scrutinee_type.is_a?(Types::Tuple)
|
|
718
|
+
infer_tuple_match_expression(expression, scrutinee_type, scopes:, expected_type:)
|
|
719
|
+
else
|
|
720
|
+
raise_sema_error("match requires an enum, variant, or integer scrutinee, got #{scrutinee_type}")
|
|
721
|
+
end
|
|
722
|
+
end
|
|
723
|
+
|
|
724
|
+
def infer_recovered_match_expression(expression, scopes:, expected_type:)
|
|
725
|
+
arm_entries = expression.arms.map do |arm|
|
|
726
|
+
arm_scopes = scopes
|
|
727
|
+
if arm.binding_name
|
|
728
|
+
ensure_non_reserved_primitive_name!(arm.binding_name, kind_label: "match binding", line: arm.binding_line, column: arm.binding_column)
|
|
729
|
+
binding = value_binding(
|
|
730
|
+
name: arm.binding_name,
|
|
731
|
+
type: @error_type,
|
|
732
|
+
mutable: false,
|
|
733
|
+
kind: :local,
|
|
734
|
+
id: @preassigned_local_binding_ids.fetch(arm.object_id),
|
|
735
|
+
)
|
|
736
|
+
arm_scopes = scopes + [{ arm.binding_name => binding }]
|
|
737
|
+
record_declaration_binding(arm, binding)
|
|
738
|
+
end
|
|
739
|
+
[infer_match_expression_arm_value(arm, scopes: arm_scopes, expected_type:), arm.value]
|
|
740
|
+
end
|
|
741
|
+
|
|
742
|
+
match_expression_common_type(arm_entries, expected_type)
|
|
743
|
+
end
|
|
744
|
+
|
|
745
|
+
def infer_enum_match_expression(expression, scrutinee_type, scopes:, expected_type:)
|
|
746
|
+
arm_entries = []
|
|
747
|
+
each_enum_match_arm(expression, scrutinee_type, scopes:) do |arm, arm_scopes|
|
|
748
|
+
arm_entries << [infer_match_expression_arm_value(arm, scopes: arm_scopes, expected_type:), arm.value]
|
|
749
|
+
end
|
|
750
|
+
match_expression_common_type(arm_entries, expected_type)
|
|
751
|
+
end
|
|
752
|
+
|
|
753
|
+
def infer_integer_match_expression(expression, scrutinee_type, scopes:, expected_type:)
|
|
754
|
+
has_wildcard = expression.arms.any? { |arm| wildcard_pattern?(arm.pattern) }
|
|
755
|
+
raise_sema_error("match on integer type #{scrutinee_type} requires a wildcard arm (_:)") unless has_wildcard
|
|
756
|
+
|
|
757
|
+
covered_values = {}
|
|
758
|
+
wildcard_seen = false
|
|
759
|
+
arm_entries = []
|
|
760
|
+
|
|
761
|
+
expression.arms.each do |arm|
|
|
762
|
+
if arm.pattern.is_a?(AST::ErrorExpr)
|
|
763
|
+
arm_entries << [infer_match_expression_arm_value(arm, scopes:, expected_type:), arm.value]
|
|
764
|
+
next
|
|
765
|
+
end
|
|
766
|
+
|
|
767
|
+
if wildcard_pattern?(arm.pattern)
|
|
768
|
+
raise_sema_error("duplicate wildcard arm in match") if wildcard_seen
|
|
769
|
+
|
|
770
|
+
wildcard_seen = true
|
|
771
|
+
arm_entries << [infer_match_expression_arm_value(arm, scopes:, expected_type:), arm.value]
|
|
772
|
+
next
|
|
773
|
+
end
|
|
774
|
+
|
|
775
|
+
unless arm.pattern.is_a?(AST::IntegerLiteral) || arm.pattern.is_a?(AST::CharLiteral)
|
|
776
|
+
raise_sema_error("match arm for integer scrutinee must be an integer literal, char literal, or _, got #{arm.pattern.class.name}")
|
|
777
|
+
end
|
|
778
|
+
|
|
779
|
+
value = arm.pattern.value
|
|
780
|
+
raise_sema_error("duplicate match arm value #{value}") if covered_values.key?(value)
|
|
781
|
+
|
|
782
|
+
covered_values[value] = true
|
|
783
|
+
arm_entries << [infer_match_expression_arm_value(arm, scopes:, expected_type:), arm.value]
|
|
784
|
+
end
|
|
785
|
+
|
|
786
|
+
match_expression_common_type(arm_entries, expected_type)
|
|
787
|
+
end
|
|
788
|
+
|
|
789
|
+
def infer_string_match_expression(expression, scrutinee_type, scopes:, expected_type:)
|
|
790
|
+
has_wildcard = expression.arms.any? { |arm| wildcard_pattern?(arm.pattern) }
|
|
791
|
+
raise_sema_error("match on str requires a wildcard arm (_:)") unless has_wildcard
|
|
792
|
+
|
|
793
|
+
covered_values = {}
|
|
794
|
+
wildcard_seen = false
|
|
795
|
+
arm_entries = []
|
|
796
|
+
|
|
797
|
+
expression.arms.each do |arm|
|
|
798
|
+
if arm.pattern.is_a?(AST::ErrorExpr)
|
|
799
|
+
arm_entries << [infer_match_expression_arm_value(arm, scopes:, expected_type:), arm.value]
|
|
800
|
+
next
|
|
801
|
+
end
|
|
802
|
+
|
|
803
|
+
if wildcard_pattern?(arm.pattern)
|
|
804
|
+
raise_sema_error("duplicate wildcard arm in match") if wildcard_seen
|
|
805
|
+
wildcard_seen = true
|
|
806
|
+
arm_entries << [infer_match_expression_arm_value(arm, scopes:, expected_type:), arm.value]
|
|
807
|
+
next
|
|
808
|
+
end
|
|
809
|
+
|
|
810
|
+
unless arm.pattern.is_a?(AST::StringLiteral)
|
|
811
|
+
raise_sema_error("match arm for str scrutinee must be a string literal or _, got #{arm.pattern.class.name}")
|
|
812
|
+
end
|
|
813
|
+
|
|
814
|
+
value = arm.pattern.value
|
|
815
|
+
raise_sema_error("duplicate match arm value \"#{value}\"") if covered_values.key?(value)
|
|
816
|
+
|
|
817
|
+
covered_values[value] = true
|
|
818
|
+
arm_entries << [infer_match_expression_arm_value(arm, scopes:, expected_type:), arm.value]
|
|
819
|
+
end
|
|
820
|
+
|
|
821
|
+
match_expression_common_type(arm_entries, expected_type)
|
|
822
|
+
end
|
|
823
|
+
|
|
824
|
+
def infer_tuple_match_expression(expression, scrutinee_type, scopes:, expected_type:)
|
|
825
|
+
has_wildcard = expression.arms.any? { |arm| wildcard_pattern?(arm.pattern) }
|
|
826
|
+
raise_sema_error("match on tuple type #{scrutinee_type} requires a wildcard arm (_:)") unless has_wildcard
|
|
827
|
+
|
|
828
|
+
arity = scrutinee_type.element_types.length
|
|
829
|
+
covered_values = {}
|
|
830
|
+
wildcard_seen = false
|
|
831
|
+
arm_entries = []
|
|
832
|
+
|
|
833
|
+
expression.arms.each do |arm|
|
|
834
|
+
if arm.pattern.is_a?(AST::ErrorExpr)
|
|
835
|
+
arm_entries << [infer_match_expression_arm_value(arm, scopes:, expected_type:), arm.value]
|
|
836
|
+
next
|
|
837
|
+
end
|
|
838
|
+
|
|
839
|
+
if wildcard_pattern?(arm.pattern)
|
|
840
|
+
raise_sema_error("duplicate wildcard arm in match") if wildcard_seen
|
|
841
|
+
wildcard_seen = true
|
|
842
|
+
arm_entries << [infer_match_expression_arm_value(arm, scopes:, expected_type:), arm.value]
|
|
843
|
+
next
|
|
844
|
+
end
|
|
845
|
+
|
|
846
|
+
unless arm.pattern.is_a?(AST::ExpressionList)
|
|
847
|
+
raise_sema_error("match arm for tuple scrutinee must be a tuple literal or _, got #{arm.pattern.class.name}")
|
|
848
|
+
end
|
|
849
|
+
|
|
850
|
+
elements = arm.pattern.elements
|
|
851
|
+
raise_sema_error("tuple match arm has #{elements.length} elements but scrutinee has #{arity}") unless elements.length == arity
|
|
852
|
+
|
|
853
|
+
values = elements.map do |elem|
|
|
854
|
+
if elem.is_a?(AST::Identifier) && elem.name == "_"
|
|
855
|
+
:wildcard
|
|
856
|
+
elsif elem.is_a?(AST::IntegerLiteral) || elem.is_a?(AST::CharLiteral) ||
|
|
857
|
+
elem.is_a?(AST::StringLiteral) || elem.is_a?(AST::BooleanLiteral)
|
|
858
|
+
elem.value
|
|
859
|
+
else
|
|
860
|
+
raise_sema_error("tuple match arm element must be a literal or _, got #{elem.class.name}")
|
|
861
|
+
end
|
|
862
|
+
end
|
|
863
|
+
|
|
864
|
+
all_literal = values.all? { |v| v != :wildcard }
|
|
865
|
+
if all_literal
|
|
866
|
+
raise_sema_error("duplicate tuple match arm #{arm.pattern.elements.map { |e| e.respond_to?(:value) ? e.value.inspect : '_' }.join(', ')}") if covered_values.key?(values)
|
|
867
|
+
covered_values[values] = true
|
|
868
|
+
end
|
|
869
|
+
|
|
870
|
+
arm_entries << [infer_match_expression_arm_value(arm, scopes:, expected_type:), arm.value]
|
|
871
|
+
end
|
|
872
|
+
|
|
873
|
+
match_expression_common_type(arm_entries, expected_type)
|
|
874
|
+
end
|
|
875
|
+
|
|
876
|
+
def infer_variant_match_expression(expression, scrutinee_type, scopes:, expected_type:)
|
|
877
|
+
arm_entries = []
|
|
878
|
+
each_variant_match_arm(expression, scrutinee_type, scopes:) do |arm, arm_scopes|
|
|
879
|
+
arm_entries << [infer_match_expression_arm_value(arm, scopes: arm_scopes, expected_type:), arm.value]
|
|
880
|
+
end
|
|
881
|
+
match_expression_common_type(arm_entries, expected_type)
|
|
882
|
+
end
|
|
883
|
+
|
|
884
|
+
def infer_match_expression_arm_value(arm, scopes:, expected_type:)
|
|
885
|
+
validate_consuming_foreign_expression!(arm.value, scopes:, root_allowed: false)
|
|
886
|
+
validate_hoistable_foreign_expression!(arm.value, scopes:, root_hoistable: false)
|
|
887
|
+
infer_expression(arm.value, scopes:, expected_type:)
|
|
888
|
+
end
|
|
889
|
+
|
|
890
|
+
def match_expression_common_type(arm_entries, expected_type)
|
|
891
|
+
return expected_type || @error_type if arm_entries.empty?
|
|
892
|
+
|
|
893
|
+
if expected_type && arm_entries.all? { |type, expr| types_compatible?(type, expected_type, expression: expr) }
|
|
894
|
+
return expected_type
|
|
895
|
+
end
|
|
896
|
+
|
|
897
|
+
common_type, common_expression = arm_entries.first
|
|
898
|
+
arm_entries.drop(1).each do |type, expr|
|
|
899
|
+
next if type == common_type
|
|
900
|
+
|
|
901
|
+
merged_type = conditional_common_type(
|
|
902
|
+
common_type,
|
|
903
|
+
type,
|
|
904
|
+
then_expression: common_expression,
|
|
905
|
+
else_expression: expr,
|
|
906
|
+
)
|
|
907
|
+
raise_sema_error("match expression arms require compatible types, got #{common_type} and #{type}") unless merged_type
|
|
908
|
+
|
|
909
|
+
common_type = merged_type
|
|
910
|
+
common_expression = expr
|
|
911
|
+
end
|
|
912
|
+
|
|
913
|
+
common_type
|
|
914
|
+
end
|
|
915
|
+
|
|
916
|
+
def infer_proc_expression(expression, scopes:, expected_type: nil)
|
|
917
|
+
proc_type = resolve_type_ref(AST::ProcType.new(params: expression.params, return_type: expression.return_type))
|
|
918
|
+
if expected_type && !proc_type_compatible?(proc_type, expected_type)
|
|
919
|
+
raise_sema_error("proc expression expects #{proc_type}, got #{expected_type}")
|
|
920
|
+
end
|
|
921
|
+
|
|
922
|
+
proc_scopes = scopes.map { |scope| freeze_scope_bindings(scope) }
|
|
923
|
+
proc_scope = {}
|
|
924
|
+
expression.params.each do |param|
|
|
925
|
+
ensure_non_reserved_primitive_name!(param.name, kind_label: "parameter", line: param.respond_to?(:line) ? param.line : nil, column: param.respond_to?(:column) ? param.column : nil)
|
|
926
|
+
param_type = resolve_type_ref(param.type)
|
|
927
|
+
validate_parameter_ref_type!(param_type, function_name: "proc", parameter_name: param.name, external: false)
|
|
928
|
+
validate_parameter_proc_type!(param_type, function_name: "proc", parameter_name: param.name, external: false, foreign: false)
|
|
929
|
+
proc_scope[param.name] = value_binding(name: param.name, type: param_type, mutable: false, kind: :param)
|
|
930
|
+
end
|
|
931
|
+
|
|
932
|
+
check_block(expression.body, scopes: proc_scopes + [proc_scope], return_type: proc_type.return_type, allow_return: true)
|
|
933
|
+
proc_type
|
|
934
|
+
end
|
|
935
|
+
|
|
936
|
+
def infer_await_expression(expression, scopes:)
|
|
937
|
+
raise_sema_error("await is only allowed inside async functions") unless inside_async_function?
|
|
938
|
+
|
|
939
|
+
task_type = infer_expression(expression.expression, scopes:)
|
|
940
|
+
raise_sema_error("await expects Task[T], got #{task_type}") unless task_type.is_a?(Types::Task)
|
|
941
|
+
|
|
942
|
+
task_type.result_type
|
|
943
|
+
end
|
|
944
|
+
|
|
945
|
+
def harmonize_binary_float_literal_types(left_expression, right_expression, left_type, right_type, scopes:)
|
|
946
|
+
if float_literal_expression?(left_expression) && right_type.is_a?(Types::Primitive) && right_type.float?
|
|
947
|
+
left_type = infer_expression(left_expression, scopes:, expected_type: right_type)
|
|
948
|
+
end
|
|
949
|
+
|
|
950
|
+
if float_literal_expression?(right_expression) && left_type.is_a?(Types::Primitive) && left_type.float?
|
|
951
|
+
right_type = infer_expression(right_expression, scopes:, expected_type: left_type)
|
|
952
|
+
end
|
|
953
|
+
|
|
954
|
+
[left_type, right_type]
|
|
955
|
+
end
|
|
956
|
+
|
|
957
|
+
def float_literal_expression?(expression)
|
|
958
|
+
expression.is_a?(AST::FloatLiteral) ||
|
|
959
|
+
(expression.is_a?(AST::UnaryOp) && ["+", "-"].include?(expression.operator) && float_literal_expression?(expression.operand))
|
|
960
|
+
end
|
|
961
|
+
|
|
962
|
+
def harmonize_binary_integer_literal_types(left_expression, right_expression, left_type, right_type, scopes:)
|
|
963
|
+
if integer_literal_expression?(left_expression) && right_type.is_a?(Types::Primitive) && right_type.integer?
|
|
964
|
+
if exact_compile_time_numeric_compatibility?(left_type, left_expression, right_type, scopes:)
|
|
965
|
+
left_type = infer_expression(left_expression, scopes:, expected_type: right_type)
|
|
966
|
+
end
|
|
967
|
+
end
|
|
968
|
+
|
|
969
|
+
if integer_literal_expression?(right_expression) && left_type.is_a?(Types::Primitive) && left_type.integer?
|
|
970
|
+
if exact_compile_time_numeric_compatibility?(right_type, right_expression, left_type, scopes:)
|
|
971
|
+
right_type = infer_expression(right_expression, scopes:, expected_type: left_type)
|
|
972
|
+
end
|
|
973
|
+
end
|
|
974
|
+
|
|
975
|
+
[left_type, right_type]
|
|
976
|
+
end
|
|
977
|
+
|
|
978
|
+
def integer_literal_expression?(expression)
|
|
979
|
+
expression.is_a?(AST::IntegerLiteral)
|
|
980
|
+
end
|
|
981
|
+
|
|
982
|
+
def propagating_expected_type(operator, expected_type)
|
|
983
|
+
case operator
|
|
984
|
+
when "+", "-", "*", "/", "%", "<<", ">>"
|
|
985
|
+
return expected_type if expected_type.is_a?(Types::Primitive) && expected_type.numeric?
|
|
986
|
+
when "|", "&", "^"
|
|
987
|
+
return expected_type if expected_type.is_a?(Types::Primitive) && expected_type.integer?
|
|
988
|
+
return expected_type if expected_type.is_a?(Types::Flags)
|
|
989
|
+
end
|
|
990
|
+
|
|
991
|
+
nil
|
|
992
|
+
end
|
|
993
|
+
|
|
994
|
+
def infer_call(expression, scopes:, expected_type: nil)
|
|
995
|
+
callable_kind, callable, receiver = resolve_callable(expression.callee, scopes:)
|
|
996
|
+
@resolved_call_kinds[@ctx.ast.node_ids[expression.callee.object_id]] = callable_kind
|
|
997
|
+
|
|
998
|
+
case callable_kind
|
|
999
|
+
when :function
|
|
1000
|
+
callable = specialize_function_binding(
|
|
1001
|
+
callable,
|
|
1002
|
+
expression.arguments,
|
|
1003
|
+
scopes:,
|
|
1004
|
+
receiver_type: callable_receiver_type_for_specialization(expression.callee, scopes:),
|
|
1005
|
+
)
|
|
1006
|
+
|
|
1007
|
+
check_function_call(callable, expression.arguments, scopes:)
|
|
1008
|
+
callable.owner.send(:check_function, callable) unless callable.type_arguments.empty?
|
|
1009
|
+
callable.type.return_type
|
|
1010
|
+
when :method
|
|
1011
|
+
callable = specialize_function_binding(
|
|
1012
|
+
callable,
|
|
1013
|
+
expression.arguments,
|
|
1014
|
+
scopes:,
|
|
1015
|
+
receiver_type: infer_method_receiver_type(receiver, scopes:, member_name: expression.callee.member),
|
|
1016
|
+
) if callable.type_params.any?
|
|
1017
|
+
record_editable_receiver_expression(receiver) if callable.type.receiver_editable
|
|
1018
|
+
raise_sema_error("cannot call editable method #{callable.name} on an immutable receiver") if callable.type.receiver_editable && !assignable_receiver?(receiver, scopes)
|
|
1019
|
+
|
|
1020
|
+
check_function_call(callable, expression.arguments, scopes:)
|
|
1021
|
+
callable.owner.send(:check_function, callable) unless callable.type_arguments.empty?
|
|
1022
|
+
callable.type.return_type
|
|
1023
|
+
when :callable_value
|
|
1024
|
+
check_callable_value_call(callable, expression.arguments, scopes:, callee_expression: expression.callee)
|
|
1025
|
+
callable.return_type
|
|
1026
|
+
when :str_buffer_clear, :str_buffer_assign, :str_buffer_append, :str_buffer_assign_format, :str_buffer_append_format,
|
|
1027
|
+
:str_buffer_len, :str_buffer_capacity, :str_buffer_as_str, :str_buffer_as_cstr
|
|
1028
|
+
check_str_buffer_method_call(callable_kind, receiver, expression.arguments, scopes:)
|
|
1029
|
+
when :array_as_span
|
|
1030
|
+
raise_sema_error("as_span does not support named arguments") if expression.arguments.any?(&:name)
|
|
1031
|
+
raise_sema_error("as_span expects 0 arguments, got #{expression.arguments.length}") unless expression.arguments.empty?
|
|
1032
|
+
Types::Registry.span(array_element_type(callable))
|
|
1033
|
+
when :event_subscribe, :event_subscribe_once, :event_unsubscribe, :event_emit, :event_wait
|
|
1034
|
+
check_event_method_call(callable_kind, receiver, expression.arguments, scopes:)
|
|
1035
|
+
when :atomic_load, :atomic_store, :atomic_add, :atomic_sub, :atomic_exchange, :atomic_compare_exchange
|
|
1036
|
+
check_atomic_method_call(callable_kind, callable, receiver, expression.arguments, scopes:)
|
|
1037
|
+
when :struct
|
|
1038
|
+
check_aggregate_construction(callable, expression.arguments, scopes:)
|
|
1039
|
+
when :struct_with
|
|
1040
|
+
check_struct_with_call(callable, receiver, expression.arguments, scopes:)
|
|
1041
|
+
when :variant_arm_ctor
|
|
1042
|
+
check_variant_arm_construction(callable, expression.arguments, scopes:)
|
|
1043
|
+
when :array
|
|
1044
|
+
check_array_construction(callable, expression.arguments, scopes:)
|
|
1045
|
+
when :reinterpret
|
|
1046
|
+
check_reinterpret_call(callable, expression.arguments, scopes:)
|
|
1047
|
+
when :hash
|
|
1048
|
+
check_hash_call(callable, expression.arguments, scopes:)
|
|
1049
|
+
when :equal
|
|
1050
|
+
check_equal_call(callable, expression.arguments, scopes:)
|
|
1051
|
+
when :order
|
|
1052
|
+
check_order_call(callable, expression.arguments, scopes:)
|
|
1053
|
+
when :fatal
|
|
1054
|
+
check_fatal_call(expression.arguments, scopes:)
|
|
1055
|
+
when :ref_of
|
|
1056
|
+
check_ref_of_call(expression.arguments, scopes:)
|
|
1057
|
+
when :const_ptr_of
|
|
1058
|
+
check_const_ptr_of_call(expression.arguments, scopes:)
|
|
1059
|
+
when :read
|
|
1060
|
+
check_read_call(expression.arguments, scopes:)
|
|
1061
|
+
when :ptr_of
|
|
1062
|
+
check_ptr_of_call(expression.arguments, scopes:)
|
|
1063
|
+
when :field_of
|
|
1064
|
+
check_field_of_call(expression.arguments, scopes:)
|
|
1065
|
+
when :callable_of
|
|
1066
|
+
check_callable_of_call(expression.arguments, scopes:)
|
|
1067
|
+
when :attribute_of
|
|
1068
|
+
check_attribute_of_call(expression.arguments, scopes:)
|
|
1069
|
+
when :has_attribute
|
|
1070
|
+
check_has_attribute_call(expression.arguments, scopes:)
|
|
1071
|
+
when :get
|
|
1072
|
+
check_get_call(expression.arguments, scopes:)
|
|
1073
|
+
when :attribute_arg
|
|
1074
|
+
check_attribute_arg_call(callable, expression.arguments, scopes:)
|
|
1075
|
+
when :dyn_method
|
|
1076
|
+
check_dyn_method_call(callable, receiver, expression.arguments, scopes:)
|
|
1077
|
+
callable.return_type
|
|
1078
|
+
when :adapt
|
|
1079
|
+
check_adapt_call(callable, expression.arguments, scopes:)
|
|
1080
|
+
else
|
|
1081
|
+
raise_sema_error("#{describe_expression(expression.callee)} is not callable")
|
|
1082
|
+
end
|
|
1083
|
+
end
|
|
1084
|
+
|
|
1085
|
+
def validate_consuming_foreign_expression!(expression, scopes:, root_allowed: false)
|
|
1086
|
+
return unless expression
|
|
1087
|
+
return if expression.is_a?(AST::ErrorExpr)
|
|
1088
|
+
|
|
1089
|
+
if (foreign_call = resolve_foreign_call_expression(expression, scopes:)) && foreign_call_consumes_binding?(foreign_call[:binding])
|
|
1090
|
+
raise_sema_error("consuming foreign calls must be top-level expression statements") unless root_allowed
|
|
1091
|
+
end
|
|
1092
|
+
|
|
1093
|
+
case expression
|
|
1094
|
+
when AST::Call, AST::Specialization
|
|
1095
|
+
validate_consuming_foreign_expression!(expression.callee, scopes:, root_allowed: false)
|
|
1096
|
+
expression.arguments.each do |argument|
|
|
1097
|
+
validate_consuming_foreign_expression!(argument.value, scopes:, root_allowed: false)
|
|
1098
|
+
end
|
|
1099
|
+
when AST::UnaryOp
|
|
1100
|
+
validate_consuming_foreign_expression!(expression.operand, scopes:, root_allowed: false)
|
|
1101
|
+
when AST::BinaryOp
|
|
1102
|
+
validate_consuming_foreign_expression!(expression.left, scopes:, root_allowed: false)
|
|
1103
|
+
validate_consuming_foreign_expression!(expression.right, scopes:, root_allowed: false)
|
|
1104
|
+
when AST::IfExpr
|
|
1105
|
+
validate_consuming_foreign_expression!(expression.condition, scopes:, root_allowed: false)
|
|
1106
|
+
validate_consuming_foreign_expression!(expression.then_expression, scopes:, root_allowed: false)
|
|
1107
|
+
validate_consuming_foreign_expression!(expression.else_expression, scopes:, root_allowed: false)
|
|
1108
|
+
when AST::MatchExpr
|
|
1109
|
+
validate_consuming_foreign_expression!(expression.expression, scopes:, root_allowed: false)
|
|
1110
|
+
expression.arms.each do |arm|
|
|
1111
|
+
validate_consuming_foreign_expression!(arm.pattern, scopes:, root_allowed: false)
|
|
1112
|
+
arm_scopes = arm.binding_name ? scopes + [{ arm.binding_name => value_binding(name: arm.binding_name, type: @error_type, mutable: false, kind: :local, id: @preassigned_local_binding_ids.fetch(arm.object_id)) }] : scopes
|
|
1113
|
+
validate_consuming_foreign_expression!(arm.value, scopes: arm_scopes, root_allowed: false)
|
|
1114
|
+
end
|
|
1115
|
+
when AST::UnsafeExpr
|
|
1116
|
+
validate_consuming_foreign_expression!(expression.expression, scopes:, root_allowed: false)
|
|
1117
|
+
when AST::FormatString
|
|
1118
|
+
expression.parts.each do |part|
|
|
1119
|
+
next unless part.is_a?(AST::FormatExprPart)
|
|
1120
|
+
|
|
1121
|
+
validate_consuming_foreign_expression!(part.expression, scopes:, root_allowed: false)
|
|
1122
|
+
end
|
|
1123
|
+
when AST::MemberAccess
|
|
1124
|
+
validate_consuming_foreign_expression!(expression.receiver, scopes:, root_allowed: false)
|
|
1125
|
+
when AST::IndexAccess
|
|
1126
|
+
validate_consuming_foreign_expression!(expression.receiver, scopes:, root_allowed: false)
|
|
1127
|
+
validate_consuming_foreign_expression!(expression.index, scopes:, root_allowed: false)
|
|
1128
|
+
when AST::RangeExpr
|
|
1129
|
+
validate_consuming_foreign_expression!(expression.start_expr, scopes:, root_allowed: false)
|
|
1130
|
+
validate_consuming_foreign_expression!(expression.end_expr, scopes:, root_allowed: false)
|
|
1131
|
+
when AST::PrefixCast
|
|
1132
|
+
validate_consuming_foreign_expression!(expression.expression, scopes:, root_allowed: false)
|
|
1133
|
+
end
|
|
1134
|
+
end
|
|
1135
|
+
|
|
1136
|
+
def validate_hoistable_foreign_expression!(expression, scopes:, root_hoistable: false)
|
|
1137
|
+
return unless expression
|
|
1138
|
+
return if expression.is_a?(AST::ErrorExpr)
|
|
1139
|
+
|
|
1140
|
+
if (foreign_call = resolve_foreign_call_expression(expression, scopes:)) && (message = inline_foreign_call_requires_hoisting_message(foreign_call, scopes:))
|
|
1141
|
+
raise_sema_error(message) unless root_hoistable
|
|
1142
|
+
end
|
|
1143
|
+
|
|
1144
|
+
case expression
|
|
1145
|
+
when AST::Call, AST::Specialization
|
|
1146
|
+
validate_hoistable_foreign_expression!(expression.callee, scopes:, root_hoistable: false)
|
|
1147
|
+
expression.arguments.each do |argument|
|
|
1148
|
+
validate_hoistable_foreign_expression!(argument.value, scopes:, root_hoistable: false)
|
|
1149
|
+
end
|
|
1150
|
+
when AST::UnaryOp
|
|
1151
|
+
validate_hoistable_foreign_expression!(expression.operand, scopes:, root_hoistable: false)
|
|
1152
|
+
when AST::BinaryOp
|
|
1153
|
+
validate_hoistable_foreign_expression!(expression.left, scopes:, root_hoistable: false)
|
|
1154
|
+
validate_hoistable_foreign_expression!(expression.right, scopes:, root_hoistable: false)
|
|
1155
|
+
when AST::IfExpr
|
|
1156
|
+
validate_hoistable_foreign_expression!(expression.condition, scopes:, root_hoistable: false)
|
|
1157
|
+
validate_hoistable_foreign_expression!(expression.then_expression, scopes:, root_hoistable: false)
|
|
1158
|
+
validate_hoistable_foreign_expression!(expression.else_expression, scopes:, root_hoistable: false)
|
|
1159
|
+
when AST::MatchExpr
|
|
1160
|
+
validate_hoistable_foreign_expression!(expression.expression, scopes:, root_hoistable: false)
|
|
1161
|
+
expression.arms.each do |arm|
|
|
1162
|
+
validate_hoistable_foreign_expression!(arm.pattern, scopes:, root_hoistable: false)
|
|
1163
|
+
arm_scopes = arm.binding_name ? scopes + [{ arm.binding_name => value_binding(name: arm.binding_name, type: @error_type, mutable: false, kind: :local, id: @preassigned_local_binding_ids.fetch(arm.object_id)) }] : scopes
|
|
1164
|
+
validate_hoistable_foreign_expression!(arm.value, scopes: arm_scopes, root_hoistable: false)
|
|
1165
|
+
end
|
|
1166
|
+
when AST::UnsafeExpr
|
|
1167
|
+
validate_hoistable_foreign_expression!(expression.expression, scopes:, root_hoistable: false)
|
|
1168
|
+
when AST::FormatString
|
|
1169
|
+
expression.parts.each do |part|
|
|
1170
|
+
next unless part.is_a?(AST::FormatExprPart)
|
|
1171
|
+
|
|
1172
|
+
validate_hoistable_foreign_expression!(part.expression, scopes:, root_hoistable: false)
|
|
1173
|
+
end
|
|
1174
|
+
when AST::MemberAccess
|
|
1175
|
+
validate_hoistable_foreign_expression!(expression.receiver, scopes:, root_hoistable: false)
|
|
1176
|
+
when AST::IndexAccess
|
|
1177
|
+
validate_hoistable_foreign_expression!(expression.receiver, scopes:, root_hoistable: false)
|
|
1178
|
+
validate_hoistable_foreign_expression!(expression.index, scopes:, root_hoistable: false)
|
|
1179
|
+
when AST::RangeExpr
|
|
1180
|
+
validate_hoistable_foreign_expression!(expression.start_expr, scopes:, root_hoistable: false)
|
|
1181
|
+
validate_hoistable_foreign_expression!(expression.end_expr, scopes:, root_hoistable: false)
|
|
1182
|
+
when AST::PrefixCast
|
|
1183
|
+
validate_hoistable_foreign_expression!(expression.expression, scopes:, root_hoistable: false)
|
|
1184
|
+
end
|
|
1185
|
+
end
|
|
1186
|
+
|
|
1187
|
+
def inline_foreign_call_requires_hoisting_message(foreign_call, scopes:)
|
|
1188
|
+
binding = foreign_call[:binding]
|
|
1189
|
+
call = foreign_call[:call]
|
|
1190
|
+
reference_counts = foreign_mapping_reference_counts(foreign_mapping_expression(binding.ast))
|
|
1191
|
+
|
|
1192
|
+
binding.ast.params.each_with_index do |param_ast, index|
|
|
1193
|
+
public_alias = param_ast.boundary_type ? foreign_mapping_public_alias_name(param_ast.name) : nil
|
|
1194
|
+
total_references = reference_counts.fetch(param_ast.name, 0)
|
|
1195
|
+
total_references += reference_counts.fetch(public_alias, 0) if public_alias
|
|
1196
|
+
next if total_references <= 1 || simple_foreign_argument_expression?(call.arguments.fetch(index).value)
|
|
1197
|
+
|
|
1198
|
+
return inline_foreign_hoisting_message(binding.name, param_ast.name, reason: "is referenced multiple times in its mapping")
|
|
1199
|
+
end
|
|
1200
|
+
|
|
1201
|
+
binding.ast.params.each_with_index do |param_ast, index|
|
|
1202
|
+
parameter = binding.type.params.fetch(index)
|
|
1203
|
+
argument_expression = call.arguments.fetch(index).value
|
|
1204
|
+
next unless automatic_foreign_cstr_temp_needed?(parameter, argument_expression, scopes:) || automatic_foreign_cstr_list_temp_needed?(parameter)
|
|
1205
|
+
|
|
1206
|
+
return inline_foreign_hoisting_message(binding.name, param_ast.name, reason: "needs temporary foreign text storage")
|
|
1207
|
+
end
|
|
1208
|
+
|
|
1209
|
+
nil
|
|
1210
|
+
end
|
|
1211
|
+
|
|
1212
|
+
def inline_foreign_hoisting_message(binding_name, parameter_name, reason:)
|
|
1213
|
+
"foreign call #{binding_name} cannot be used inline because #{parameter_name} #{reason}; use it as a statement, local initializer, assignment, or return expression"
|
|
1214
|
+
end
|
|
1215
|
+
|
|
1216
|
+
def resolve_foreign_call_expression(expression, scopes:)
|
|
1217
|
+
call = expression
|
|
1218
|
+
return unless call.is_a?(AST::Call)
|
|
1219
|
+
|
|
1220
|
+
callable_kind, callable, _receiver = resolve_callable(call.callee, scopes:)
|
|
1221
|
+
return unless callable_kind == :function
|
|
1222
|
+
|
|
1223
|
+
callable = specialize_function_binding(
|
|
1224
|
+
callable,
|
|
1225
|
+
call.arguments,
|
|
1226
|
+
scopes:,
|
|
1227
|
+
receiver_type: callable_receiver_type_for_specialization(call.callee, scopes:),
|
|
1228
|
+
) if callable.type_params.any?
|
|
1229
|
+
return unless foreign_function_binding?(callable)
|
|
1230
|
+
|
|
1231
|
+
{ call:, binding: callable }
|
|
1232
|
+
rescue SemanticError
|
|
1233
|
+
nil
|
|
1234
|
+
end
|
|
1235
|
+
|
|
1236
|
+
def foreign_call_consumes_binding?(binding)
|
|
1237
|
+
binding.type.params.any? { |parameter| parameter.passing_mode == :consuming }
|
|
1238
|
+
end
|
|
1239
|
+
|
|
1240
|
+
def foreign_mapping_reference_counts(expression, counts = Hash.new(0))
|
|
1241
|
+
case expression
|
|
1242
|
+
when AST::Identifier
|
|
1243
|
+
counts[expression.name] += 1
|
|
1244
|
+
when AST::MemberAccess
|
|
1245
|
+
foreign_mapping_reference_counts(expression.receiver, counts)
|
|
1246
|
+
when AST::IndexAccess
|
|
1247
|
+
foreign_mapping_reference_counts(expression.receiver, counts)
|
|
1248
|
+
foreign_mapping_reference_counts(expression.index, counts)
|
|
1249
|
+
when AST::Specialization, AST::Call
|
|
1250
|
+
foreign_mapping_reference_counts(expression.callee, counts)
|
|
1251
|
+
expression.arguments.each { |argument| foreign_mapping_reference_counts(argument.value, counts) }
|
|
1252
|
+
when AST::UnaryOp
|
|
1253
|
+
foreign_mapping_reference_counts(expression.operand, counts)
|
|
1254
|
+
when AST::BinaryOp
|
|
1255
|
+
foreign_mapping_reference_counts(expression.left, counts)
|
|
1256
|
+
foreign_mapping_reference_counts(expression.right, counts)
|
|
1257
|
+
when AST::IfExpr
|
|
1258
|
+
foreign_mapping_reference_counts(expression.condition, counts)
|
|
1259
|
+
foreign_mapping_reference_counts(expression.then_expression, counts)
|
|
1260
|
+
foreign_mapping_reference_counts(expression.else_expression, counts)
|
|
1261
|
+
when AST::UnsafeExpr
|
|
1262
|
+
foreign_mapping_reference_counts(expression.expression, counts)
|
|
1263
|
+
when AST::PrefixCast
|
|
1264
|
+
foreign_mapping_reference_counts(expression.expression, counts)
|
|
1265
|
+
end
|
|
1266
|
+
|
|
1267
|
+
counts
|
|
1268
|
+
end
|
|
1269
|
+
|
|
1270
|
+
def simple_foreign_argument_expression?(expression)
|
|
1271
|
+
case expression
|
|
1272
|
+
when AST::Identifier, AST::IntegerLiteral, AST::FloatLiteral, AST::StringLiteral, AST::BooleanLiteral, AST::NullLiteral
|
|
1273
|
+
true
|
|
1274
|
+
when AST::MemberAccess
|
|
1275
|
+
simple_foreign_argument_expression?(expression.receiver)
|
|
1276
|
+
else
|
|
1277
|
+
false
|
|
1278
|
+
end
|
|
1279
|
+
end
|
|
1280
|
+
|
|
1281
|
+
def automatic_foreign_cstr_list_temp_needed?(parameter)
|
|
1282
|
+
return false unless parameter.type.is_a?(Types::Span) && parameter.type.element_type == @ctx.types.fetch("str")
|
|
1283
|
+
return false unless parameter.boundary_type.is_a?(Types::Span)
|
|
1284
|
+
|
|
1285
|
+
boundary_element_type = parameter.boundary_type.element_type
|
|
1286
|
+
boundary_element_type == @ctx.types.fetch("cstr") || char_pointer_type?(boundary_element_type)
|
|
1287
|
+
end
|
|
1288
|
+
|
|
1289
|
+
def automatic_foreign_cstr_temp_needed?(parameter, expression, scopes:)
|
|
1290
|
+
return false unless parameter.boundary_type == @ctx.types.fetch("cstr") && parameter.type == @ctx.types.fetch("str")
|
|
1291
|
+
return false if expression.is_a?(AST::StringLiteral) && !expression.cstring
|
|
1292
|
+
|
|
1293
|
+
infer_expression(expression, scopes:) != @ctx.types.fetch("cstr")
|
|
1294
|
+
end
|
|
1295
|
+
|
|
1296
|
+
def consuming_foreign_call_refinements(expression, scopes:)
|
|
1297
|
+
foreign_call = resolve_foreign_call_expression(expression, scopes:)
|
|
1298
|
+
return {} unless foreign_call
|
|
1299
|
+
|
|
1300
|
+
binding = foreign_call[:binding]
|
|
1301
|
+
return {} unless foreign_call_consumes_binding?(binding)
|
|
1302
|
+
|
|
1303
|
+
binding.type.params.each_with_index.each_with_object({}) do |(parameter, index), refinements|
|
|
1304
|
+
next unless parameter.passing_mode == :consuming
|
|
1305
|
+
|
|
1306
|
+
argument = foreign_call[:call].arguments.fetch(index)
|
|
1307
|
+
argument_binding = foreign_consuming_argument_binding(parameter, argument, scopes:, function_name: binding.name)
|
|
1308
|
+
refinements[argument.value.name] = @null_type if argument_binding.storage_type.is_a?(Types::Nullable)
|
|
1309
|
+
end
|
|
1310
|
+
end
|
|
1311
|
+
|
|
1312
|
+
def resolve_callable(callee, scopes:)
|
|
1313
|
+
case callee
|
|
1314
|
+
when AST::Identifier
|
|
1315
|
+
if (binding = lookup_value(callee.name, scopes))
|
|
1316
|
+
return [:callable_value, binding.type, nil] if callable_type?(binding.type)
|
|
1317
|
+
|
|
1318
|
+
raise_sema_error("#{callee.name} is not callable")
|
|
1319
|
+
end
|
|
1320
|
+
|
|
1321
|
+
return [:function, @ctx.top_level_functions.fetch(callee.name), nil] if @ctx.top_level_functions.key?(callee.name)
|
|
1322
|
+
return [:fatal, nil, nil] if callee.name == "fatal"
|
|
1323
|
+
return [:ref_of, nil, nil] if callee.name == "ref_of"
|
|
1324
|
+
return [:const_ptr_of, nil, nil] if callee.name == "const_ptr_of"
|
|
1325
|
+
return [:read, nil, nil] if callee.name == "read"
|
|
1326
|
+
return [:ptr_of, nil, nil] if callee.name == "ptr_of"
|
|
1327
|
+
return [:field_of, nil, nil] if callee.name == "field_of"
|
|
1328
|
+
return [:callable_of, nil, nil] if callee.name == "callable_of"
|
|
1329
|
+
return [:attribute_of, nil, nil] if callee.name == "attribute_of"
|
|
1330
|
+
return [:has_attribute, nil, nil] if callee.name == "has_attribute"
|
|
1331
|
+
return [:get, nil, nil] if callee.name == "get"
|
|
1332
|
+
|
|
1333
|
+
type = @ctx.types[callee.name]
|
|
1334
|
+
return [:struct, type, nil] if type.is_a?(Types::Struct) || type.is_a?(Types::StringView) || task_type?(type) || type.is_a?(Types::Vector) || type.is_a?(Types::Matrix) || type.is_a?(Types::Quaternion)
|
|
1335
|
+
if type.is_a?(Types::GenericStructDefinition) || type.is_a?(Types::GenericVariantDefinition)
|
|
1336
|
+
raise_sema_error("generic type #{callee.name} requires type arguments")
|
|
1337
|
+
end
|
|
1338
|
+
|
|
1339
|
+
raise_sema_error("unknown callable #{callee.name}")
|
|
1340
|
+
when AST::MemberAccess
|
|
1341
|
+
if callee.receiver.is_a?(AST::Identifier) && @ctx.imports.key?(callee.receiver.name)
|
|
1342
|
+
imported_module = @ctx.imports.fetch(callee.receiver.name)
|
|
1343
|
+
return [:function, imported_module.functions.fetch(callee.member), nil] if imported_module.functions.key?(callee.member)
|
|
1344
|
+
imported_type = imported_module.types[callee.member]
|
|
1345
|
+
if imported_type.is_a?(Types::Struct) || imported_type.is_a?(Types::GenericStructDefinition) || 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)
|
|
1346
|
+
return [:struct, imported_module.types.fetch(callee.member), nil]
|
|
1347
|
+
end
|
|
1348
|
+
|
|
1349
|
+
if imported_type.is_a?(Types::Variant)
|
|
1350
|
+
arm_name = callee.member
|
|
1351
|
+
unless imported_type.arm_names.include?(arm_name)
|
|
1352
|
+
raise_sema_error("unknown arm #{arm_name} for variant #{imported_type}")
|
|
1353
|
+
end
|
|
1354
|
+
|
|
1355
|
+
return [:variant_arm_ctor, [imported_type, arm_name], nil]
|
|
1356
|
+
end
|
|
1357
|
+
|
|
1358
|
+
if imported_module.private_function?(callee.member) || imported_module.private_type?(callee.member) || imported_module.private_value?(callee.member)
|
|
1359
|
+
raise_sema_error("#{callee.receiver.name}.#{callee.member} is private to module #{imported_module.name}")
|
|
1360
|
+
end
|
|
1361
|
+
|
|
1362
|
+
raise_sema_error("unknown callable #{callee.receiver.name}.#{callee.member}") unless @ctx.types.key?(callee.receiver.name)
|
|
1363
|
+
end
|
|
1364
|
+
|
|
1365
|
+
if (type_expr = resolve_type_expression(callee.receiver))
|
|
1366
|
+
if type_expr.is_a?(Types::Variant)
|
|
1367
|
+
arm_name = callee.member
|
|
1368
|
+
unless type_expr.arm_names.include?(arm_name)
|
|
1369
|
+
raise_sema_error("unknown arm #{arm_name} for variant #{type_expr}")
|
|
1370
|
+
end
|
|
1371
|
+
|
|
1372
|
+
return [:variant_arm_ctor, [type_expr, arm_name], nil]
|
|
1373
|
+
end
|
|
1374
|
+
|
|
1375
|
+
if type_expr.respond_to?(:nested_types) && type_expr.nested_types.key?(callee.member)
|
|
1376
|
+
return [:struct, type_expr.nested_types[callee.member], nil]
|
|
1377
|
+
end
|
|
1378
|
+
|
|
1379
|
+
method = lookup_method(type_expr, callee.member)
|
|
1380
|
+
method ||= lookup_static_method(type_expr, callee.member)
|
|
1381
|
+
return [:function, method, nil] if method && method.type.receiver_type.nil?
|
|
1382
|
+
|
|
1383
|
+
raise_sema_error("unknown associated function #{type_expr}.#{callee.member}")
|
|
1384
|
+
end
|
|
1385
|
+
|
|
1386
|
+
method_receiver_type = infer_method_receiver_type(callee.receiver, scopes:, member_name: callee.member)
|
|
1387
|
+
|
|
1388
|
+
if dyn_type?(method_receiver_type)
|
|
1389
|
+
interface = method_receiver_type.interface_binding
|
|
1390
|
+
method_binding = interface.methods[callee.member]
|
|
1391
|
+
raise_sema_error("no method '#{callee.member}' on interface #{interface.name}") unless method_binding
|
|
1392
|
+
raise_sema_error("cannot call static method '#{callee.member}' on dyn value") if method_binding.kind == :static
|
|
1393
|
+
return [:dyn_method, method_binding, callee.receiver]
|
|
1394
|
+
end
|
|
1395
|
+
|
|
1396
|
+
method = lookup_method(method_receiver_type, callee.member)
|
|
1397
|
+
return [:method, method, callee.receiver] if method
|
|
1398
|
+
|
|
1399
|
+
if callee.member == "with" && struct_with_target_type?(method_receiver_type)
|
|
1400
|
+
return [:struct_with, method_receiver_type, callee.receiver]
|
|
1401
|
+
end
|
|
1402
|
+
|
|
1403
|
+
if char_array_removed_text_method?(method_receiver_type, callee.member)
|
|
1404
|
+
raise_sema_error("#{method_receiver_type}.#{callee.member} is not available; array[char, N] is raw storage, use str_buffer[N] or an explicit helper")
|
|
1405
|
+
end
|
|
1406
|
+
|
|
1407
|
+
if (str_buffer_method = str_buffer_method_kind(method_receiver_type, callee.member))
|
|
1408
|
+
return [str_buffer_method, method_receiver_type, callee.receiver]
|
|
1409
|
+
end
|
|
1410
|
+
|
|
1411
|
+
if (event_method = event_method_kind(method_receiver_type, callee.member))
|
|
1412
|
+
return [event_method, method_receiver_type, callee.receiver]
|
|
1413
|
+
end
|
|
1414
|
+
|
|
1415
|
+
if (atomic_method = atomic_method_kind(method_receiver_type, callee.member))
|
|
1416
|
+
return [atomic_method, method_receiver_type, callee.receiver]
|
|
1417
|
+
end
|
|
1418
|
+
|
|
1419
|
+
field_receiver_type = infer_field_receiver_type(callee.receiver, scopes:)
|
|
1420
|
+
if array_type?(field_receiver_type) && callee.member == "as_span"
|
|
1421
|
+
return [:array_as_span, field_receiver_type, callee.receiver]
|
|
1422
|
+
end
|
|
1423
|
+
|
|
1424
|
+
return [:callable_value, field_receiver_type.field(callee.member), nil] if aggregate_type?(field_receiver_type) && callable_type?(field_receiver_type.field(callee.member))
|
|
1425
|
+
return [:callable_value, field_receiver_type.field(callee.member), nil] if aggregate_type?(field_receiver_type) && callable_type?(field_receiver_type.field(callee.member))
|
|
1426
|
+
|
|
1427
|
+
if (imported_module = imported_module_with_private_method(method_receiver_type, callee.member))
|
|
1428
|
+
raise_sema_error("#{method_receiver_type}.#{callee.member} is private to module #{imported_module.name}")
|
|
1429
|
+
end
|
|
1430
|
+
|
|
1431
|
+
raise_sema_error("unknown method #{method_receiver_type}.#{callee.member}")
|
|
1432
|
+
when AST::Specialization
|
|
1433
|
+
if callee.callee.is_a?(AST::Identifier) && callee.callee.name == "reinterpret"
|
|
1434
|
+
raise_sema_error("reinterpret requires exactly one type argument") unless callee.arguments.length == 1
|
|
1435
|
+
|
|
1436
|
+
type_arg = callee.arguments.first.value
|
|
1437
|
+
raise_sema_error("reinterpret type argument must be a type") unless type_arg.is_a?(AST::TypeRef)
|
|
1438
|
+
|
|
1439
|
+
return [:reinterpret, resolve_type_ref(type_arg), nil]
|
|
1440
|
+
end
|
|
1441
|
+
|
|
1442
|
+
if callee.callee.is_a?(AST::Identifier) && callee.callee.name == "array"
|
|
1443
|
+
raise_sema_error("array requires exactly two type arguments") unless callee.arguments.length == 2
|
|
1444
|
+
|
|
1445
|
+
array_type = resolve_type_ref(AST::TypeRef.new(name: AST::QualifiedName.new(parts: ["array"]), arguments: callee.arguments, nullable: false))
|
|
1446
|
+
raise_sema_error("array specialization must be array[T, N]") unless array_type?(array_type)
|
|
1447
|
+
|
|
1448
|
+
return [:array, array_type, nil]
|
|
1449
|
+
end
|
|
1450
|
+
|
|
1451
|
+
if callee.callee.is_a?(AST::Identifier) && callee.callee.name == "span"
|
|
1452
|
+
raise_sema_error("span requires exactly one type argument") unless callee.arguments.length == 1
|
|
1453
|
+
|
|
1454
|
+
span_type = resolve_type_ref(AST::TypeRef.new(name: AST::QualifiedName.new(parts: ["span"]), arguments: callee.arguments, nullable: false))
|
|
1455
|
+
raise_sema_error("span specialization must be span[T]") unless span_type?(span_type)
|
|
1456
|
+
|
|
1457
|
+
return [:struct, span_type, nil]
|
|
1458
|
+
end
|
|
1459
|
+
|
|
1460
|
+
if callee.callee.is_a?(AST::Identifier) && callee.callee.name == "zero"
|
|
1461
|
+
raise_sema_error("zero requires exactly one type argument") unless callee.arguments.length == 1
|
|
1462
|
+
|
|
1463
|
+
type_arg = callee.arguments.first.value
|
|
1464
|
+
raise_sema_error("zero type argument must be a type") unless type_arg.is_a?(AST::TypeRef)
|
|
1465
|
+
|
|
1466
|
+
return [:zero, resolve_type_ref(type_arg), nil]
|
|
1467
|
+
end
|
|
1468
|
+
|
|
1469
|
+
if callee.callee.is_a?(AST::Identifier) && callee.callee.name == "default"
|
|
1470
|
+
return [:default, resolve_default_specialization(callee), nil]
|
|
1471
|
+
end
|
|
1472
|
+
|
|
1473
|
+
if callee.callee.is_a?(AST::Identifier) && callee.callee.name == "hash"
|
|
1474
|
+
return [:hash, resolve_hash_specialization(callee), nil]
|
|
1475
|
+
end
|
|
1476
|
+
|
|
1477
|
+
if callee.callee.is_a?(AST::Identifier) && callee.callee.name == "equal"
|
|
1478
|
+
return [:equal, resolve_equal_specialization(callee), nil]
|
|
1479
|
+
end
|
|
1480
|
+
|
|
1481
|
+
if callee.callee.is_a?(AST::Identifier) && callee.callee.name == "order"
|
|
1482
|
+
return [:order, resolve_order_specialization(callee), nil]
|
|
1483
|
+
end
|
|
1484
|
+
|
|
1485
|
+
if callee.callee.is_a?(AST::Identifier) && callee.callee.name == "attribute_arg"
|
|
1486
|
+
raise_sema_error("attribute_arg requires exactly one type argument") unless callee.arguments.length == 1
|
|
1487
|
+
|
|
1488
|
+
type_arg = callee.arguments.first.value
|
|
1489
|
+
raise_sema_error("attribute_arg type argument must be a type") unless type_arg.is_a?(AST::TypeRef)
|
|
1490
|
+
|
|
1491
|
+
return [:attribute_arg, resolve_type_ref(type_arg), nil]
|
|
1492
|
+
end
|
|
1493
|
+
|
|
1494
|
+
if callee.callee.is_a?(AST::Identifier) && callee.callee.name == "adapt"
|
|
1495
|
+
raise_sema_error("adapt requires exactly one type argument") unless callee.arguments.length == 1
|
|
1496
|
+
|
|
1497
|
+
type_arg = callee.arguments.first.value
|
|
1498
|
+
raise_sema_error("adapt type argument must be a type") unless type_arg.is_a?(AST::TypeRef)
|
|
1499
|
+
|
|
1500
|
+
interface = resolve_adapt_interface(type_arg)
|
|
1501
|
+
return [:adapt, interface, nil]
|
|
1502
|
+
end
|
|
1503
|
+
|
|
1504
|
+
if (callable_resolution = resolve_specialized_callable_binding(callee, scopes:))
|
|
1505
|
+
return callable_resolution
|
|
1506
|
+
end
|
|
1507
|
+
|
|
1508
|
+
if (type_ref = type_ref_from_specialization(callee))
|
|
1509
|
+
specialized_type = resolve_type_ref(type_ref)
|
|
1510
|
+
return [:struct, specialized_type, nil] 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)
|
|
1511
|
+
end
|
|
1512
|
+
|
|
1513
|
+
raise_sema_error("unsupported callable specialization #{describe_expression(callee)}")
|
|
1514
|
+
else
|
|
1515
|
+
callee_type = infer_expression(callee, scopes:)
|
|
1516
|
+
return [:callable_value, callee_type, nil] if callable_type?(callee_type)
|
|
1517
|
+
|
|
1518
|
+
raise_sema_error("unsupported callee #{describe_expression(callee)}")
|
|
1519
|
+
end
|
|
1520
|
+
end
|
|
1521
|
+
|
|
1522
|
+
|
|
1523
|
+
def record_editable_receiver_expression(receiver)
|
|
1524
|
+
return unless receiver
|
|
1525
|
+
|
|
1526
|
+
@editable_receiver_expression_ids[receiver.object_id] = true
|
|
1527
|
+
end
|
|
1528
|
+
|
|
1529
|
+
def record_mutable_lvalue_argument_identifier(expression)
|
|
1530
|
+
return unless expression.is_a?(AST::Identifier)
|
|
1531
|
+
|
|
1532
|
+
@mutable_lvalue_argument_identifier_ids[expression.object_id] = true
|
|
1533
|
+
end
|
|
1534
|
+
|
|
1535
|
+
def check_format_string_literal(format_string, scopes:)
|
|
1536
|
+
format_string.parts.each do |part|
|
|
1537
|
+
next unless part.is_a?(AST::FormatExprPart)
|
|
1538
|
+
|
|
1539
|
+
value_type = infer_expression(part.expression, scopes:)
|
|
1540
|
+
|
|
1541
|
+
if part.format_spec
|
|
1542
|
+
case part.format_spec[:kind]
|
|
1543
|
+
when :precision
|
|
1544
|
+
unless value_type.is_a?(Types::Primitive) && value_type.float?
|
|
1545
|
+
raise_sema_error("format spec ':.N' is only valid for float and double, got #{value_type}")
|
|
1546
|
+
end
|
|
1547
|
+
when :hex
|
|
1548
|
+
unless format_string_integer_base_spec_supported?(value_type)
|
|
1549
|
+
raise_sema_error("format spec ':x' and ':X' are only valid for integer primitives and integer-backed enums/flags, got #{value_type}")
|
|
1550
|
+
end
|
|
1551
|
+
when :oct
|
|
1552
|
+
unless format_string_integer_base_spec_supported?(value_type)
|
|
1553
|
+
raise_sema_error("format spec ':o' and ':O' are only valid for integer primitives and integer-backed enums/flags, got #{value_type}")
|
|
1554
|
+
end
|
|
1555
|
+
when :bin
|
|
1556
|
+
unless format_string_integer_base_spec_supported?(value_type)
|
|
1557
|
+
raise_sema_error("format spec ':b' and ':B' are only valid for integer primitives and integer-backed enums/flags, got #{value_type}")
|
|
1558
|
+
end
|
|
1559
|
+
else
|
|
1560
|
+
raise_sema_error("unsupported format spec #{part.format_spec.inspect}")
|
|
1561
|
+
end
|
|
1562
|
+
else
|
|
1563
|
+
next if format_string_interpolation_supported?(value_type, context: "formatted string interpolation of #{value_type}")
|
|
1564
|
+
raise_sema_error("formatted string interpolation supports str, cstr, bool, numeric primitives, integer-backed enums/flags, and types implementing format_len()/append_format(output: ref[std.string.String]), got #{value_type}")
|
|
1565
|
+
end
|
|
1566
|
+
end
|
|
1567
|
+
end
|
|
1568
|
+
|
|
1569
|
+
def format_string_integer_base_spec_supported?(type)
|
|
1570
|
+
resolved = type.is_a?(Types::EnumBase) ? type.backing_type : type
|
|
1571
|
+
resolved.is_a?(Types::Primitive) && resolved.integer?
|
|
1572
|
+
end
|
|
1573
|
+
|
|
1574
|
+
def format_string_interpolation_supported?(type, context:)
|
|
1575
|
+
return true if type == @ctx.types.fetch("str")
|
|
1576
|
+
return true if type == @ctx.types.fetch("cstr")
|
|
1577
|
+
return true if type == @ctx.types.fetch("bool")
|
|
1578
|
+
return true if type.is_a?(Types::Primitive) && type.integer?
|
|
1579
|
+
return true if type.is_a?(Types::Primitive) && type.float?
|
|
1580
|
+
return true if type.is_a?(Types::EnumBase) && type.backing_type.is_a?(Types::Primitive) && type.backing_type.integer?
|
|
1581
|
+
return true if resolve_explicit_format_binding(type, context:)
|
|
1582
|
+
|
|
1583
|
+
false
|
|
1584
|
+
end
|
|
1585
|
+
|
|
1586
|
+
|
|
1587
|
+
|
|
1588
|
+
|
|
1589
|
+
|
|
1590
|
+
|
|
1591
|
+
|
|
1592
|
+
|
|
1593
|
+
def evaluate_field_of_call(arguments, scopes:)
|
|
1594
|
+
raise_sema_error("field_of does not support named arguments") if arguments.any?(&:name)
|
|
1595
|
+
raise_sema_error("field_of expects 2 arguments, got #{arguments.length}") unless arguments.length == 2
|
|
1596
|
+
|
|
1597
|
+
struct_handle = resolve_struct_handle_argument(arguments.first.value, scopes:)
|
|
1598
|
+
field_name = reflection_identifier_name(arguments[1].value, context: "field_of")
|
|
1599
|
+
field_handle = CompileTime::Reflection.core_field_handle(struct_handle, field_name)
|
|
1600
|
+
raise_sema_error("unknown field #{struct_handle.struct_type}.#{field_name}") unless field_handle
|
|
1601
|
+
|
|
1602
|
+
field_handle
|
|
1603
|
+
end
|
|
1604
|
+
|
|
1605
|
+
|
|
1606
|
+
def evaluate_callable_of_call(arguments, scopes:)
|
|
1607
|
+
raise_sema_error("callable_of does not support named arguments") if arguments.any?(&:name)
|
|
1608
|
+
raise_sema_error("callable_of expects 1 argument, got #{arguments.length}") unless arguments.length == 1
|
|
1609
|
+
|
|
1610
|
+
resolve_callable_handle_argument(arguments.first.value, scopes:)
|
|
1611
|
+
end
|
|
1612
|
+
|
|
1613
|
+
|
|
1614
|
+
|
|
1615
|
+
|
|
1616
|
+
def resolve_struct_handle_argument(expression, scopes:)
|
|
1617
|
+
if (type_expr = resolve_type_expression(expression))
|
|
1618
|
+
handle = struct_handle_for_type(type_expr)
|
|
1619
|
+
return handle if handle
|
|
1620
|
+
end
|
|
1621
|
+
|
|
1622
|
+
raise_sema_error("field_of expects a struct type expression")
|
|
1623
|
+
end
|
|
1624
|
+
|
|
1625
|
+
def resolve_reflection_target_argument(expression, scopes:)
|
|
1626
|
+
if (type_expr = resolve_type_expression(expression))
|
|
1627
|
+
handle = struct_handle_for_type(type_expr)
|
|
1628
|
+
return handle if handle
|
|
1629
|
+
end
|
|
1630
|
+
|
|
1631
|
+
handle = evaluate_compile_time_const_value(expression, scopes:)
|
|
1632
|
+
return handle if handle.is_a?(Types::FieldHandle) || handle.is_a?(Types::CallableHandle)
|
|
1633
|
+
|
|
1634
|
+
raise_sema_error("attribute reflection expects a struct type, field handle, or callable handle")
|
|
1635
|
+
end
|
|
1636
|
+
|
|
1637
|
+
def resolve_callable_handle_argument(expression, scopes:)
|
|
1638
|
+
callable_kind, callable, _receiver = resolve_callable(expression, scopes:)
|
|
1639
|
+
raise_sema_error("callable_of expects a callable declaration name") unless callable_kind == :function
|
|
1640
|
+
|
|
1641
|
+
Types::CallableHandle.new(describe_expression(expression), callable.ast)
|
|
1642
|
+
end
|
|
1643
|
+
|
|
1644
|
+
def resolve_attribute_name_argument(expression)
|
|
1645
|
+
case expression
|
|
1646
|
+
when AST::Identifier
|
|
1647
|
+
resolve_attribute_binding(AST::QualifiedName.new(parts: [expression.name]))
|
|
1648
|
+
when AST::MemberAccess
|
|
1649
|
+
raise_sema_error("attribute name must use a module qualifier") unless expression.receiver.is_a?(AST::Identifier)
|
|
1650
|
+
|
|
1651
|
+
resolve_attribute_binding(AST::QualifiedName.new(parts: [expression.receiver.name, expression.member]))
|
|
1652
|
+
else
|
|
1653
|
+
raise_sema_error("attribute name must be an identifier or module-qualified attribute name")
|
|
1654
|
+
end
|
|
1655
|
+
end
|
|
1656
|
+
|
|
1657
|
+
def reflection_identifier_name(expression, context:)
|
|
1658
|
+
raise_sema_error("#{context} expects an identifier argument") unless expression.is_a?(AST::Identifier)
|
|
1659
|
+
|
|
1660
|
+
expression.name
|
|
1661
|
+
end
|
|
1662
|
+
|
|
1663
|
+
def struct_handle_for_type(type)
|
|
1664
|
+
base_type = type.is_a?(Types::StructInstance) ? type.definition : type
|
|
1665
|
+
return nil unless base_type.is_a?(Types::Struct) || base_type.is_a?(Types::GenericStructDefinition)
|
|
1666
|
+
|
|
1667
|
+
declaration = struct_declaration_for_type(base_type)
|
|
1668
|
+
return nil unless declaration
|
|
1669
|
+
|
|
1670
|
+
Types::StructHandle.new(base_type, declaration)
|
|
1671
|
+
end
|
|
1672
|
+
|
|
1673
|
+
def struct_declaration_for_type(type)
|
|
1674
|
+
return type.ast_declaration if type.respond_to?(:ast_declaration) && type.ast_declaration
|
|
1675
|
+
|
|
1676
|
+
return nil unless type.respond_to?(:module_name)
|
|
1677
|
+
if type.module_name == @ctx.module_name
|
|
1678
|
+
return @ctx.ast.declarations.find do |decl|
|
|
1679
|
+
decl.is_a?(AST::StructDecl) && decl.name == type.name
|
|
1680
|
+
end
|
|
1681
|
+
end
|
|
1682
|
+
|
|
1683
|
+
imported_module = imported_module_binding_for_name(type.module_name)
|
|
1684
|
+
return nil unless imported_module
|
|
1685
|
+
|
|
1686
|
+
declaration = imported_module.type_declarations[type.name]
|
|
1687
|
+
declaration if declaration.is_a?(AST::StructDecl)
|
|
1688
|
+
end
|
|
1689
|
+
|
|
1690
|
+
def imported_module_binding_for_name(module_name)
|
|
1691
|
+
@ctx.imports.each_value.find { |binding| binding.name == module_name }
|
|
1692
|
+
end
|
|
1693
|
+
|
|
1694
|
+
def validate_attribute_target_compatibility!(target, binding)
|
|
1695
|
+
target_kind = attribute_target_kind(target)
|
|
1696
|
+
raise_sema_error("attribute #{qualified_attribute_name(binding)} cannot target #{target_kind}") unless binding.targets.include?(target_kind)
|
|
1697
|
+
end
|
|
1698
|
+
|
|
1699
|
+
def attribute_target_kind(target)
|
|
1700
|
+
case target
|
|
1701
|
+
when Types::StructHandle then :struct
|
|
1702
|
+
when Types::FieldHandle then :field
|
|
1703
|
+
when Types::CallableHandle then :callable
|
|
1704
|
+
else
|
|
1705
|
+
raise_sema_error("unsupported attribute reflection target #{target}")
|
|
1706
|
+
end
|
|
1707
|
+
end
|
|
1708
|
+
|
|
1709
|
+
def infer_field_handle_member(expression, scopes:)
|
|
1710
|
+
case expression.member
|
|
1711
|
+
when "name"
|
|
1712
|
+
@ctx.types.fetch("str")
|
|
1713
|
+
when "type"
|
|
1714
|
+
handle = evaluate_compile_time_const_value(expression.receiver, scopes:)
|
|
1715
|
+
return @error_type unless handle.is_a?(Types::FieldHandle)
|
|
1716
|
+
|
|
1717
|
+
resolve_type_ref(handle.field_declaration.type)
|
|
1718
|
+
else
|
|
1719
|
+
raise_sema_error("unknown member #{expression.member} of field_handle")
|
|
1720
|
+
end
|
|
1721
|
+
end
|
|
1722
|
+
|
|
1723
|
+
def infer_member_handle_member(expression)
|
|
1724
|
+
case expression.member
|
|
1725
|
+
when "name"
|
|
1726
|
+
@ctx.types.fetch("str")
|
|
1727
|
+
when "value"
|
|
1728
|
+
@ctx.types.fetch("int")
|
|
1729
|
+
else
|
|
1730
|
+
raise_sema_error("unknown member #{expression.member} of member_handle")
|
|
1731
|
+
end
|
|
1732
|
+
end
|
|
1733
|
+
end
|
|
1734
|
+
end
|
|
1735
|
+
end
|