rigortype 0.2.7 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/data/core_overlay/csv.rbs +28 -0
- data/data/core_overlay/psych.rbs +22 -0
- data/docs/handbook/01-getting-started.md +9 -1
- data/docs/handbook/02-everyday-types.md +4 -1
- data/docs/handbook/08-understanding-errors.md +3 -3
- data/docs/manual/01-installation.md +1 -0
- data/docs/manual/02-cli-reference.md +16 -7
- data/docs/manual/04-diagnostics.md +7 -4
- data/docs/manual/06-baseline.md +5 -2
- data/docs/manual/07-plugins.md +1 -1
- data/docs/manual/14-rails-quickstart.md +4 -2
- data/docs/manual/15-type-protection-coverage.md +27 -4
- data/docs/manual/plugins/rigor-actionpack.md +1 -1
- data/docs/manual/plugins/rigor-activerecord.md +12 -5
- data/docs/manual/plugins/rigor-rails-routes.md +11 -0
- data/lib/rigor/analysis/baseline.rb +56 -96
- data/lib/rigor/analysis/buffer_binding.rb +13 -20
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +29 -48
- data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +35 -54
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +23 -37
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +16 -23
- data/lib/rigor/analysis/check_rules/rule_walk.rb +48 -71
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +19 -28
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +48 -67
- data/lib/rigor/analysis/check_rules.rb +174 -274
- data/lib/rigor/analysis/dependency_recorder.rb +26 -38
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +13 -25
- data/lib/rigor/analysis/dependency_source_inference/builder.rb +17 -30
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +15 -26
- data/lib/rigor/analysis/dependency_source_inference/index.rb +45 -76
- data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +23 -40
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +50 -83
- data/lib/rigor/analysis/dependency_source_inference.rb +6 -10
- data/lib/rigor/analysis/diagnostic.rb +48 -75
- data/lib/rigor/analysis/erb_template_detector.rb +13 -18
- data/lib/rigor/analysis/fact_store.rb +12 -22
- data/lib/rigor/analysis/incremental.rb +47 -63
- data/lib/rigor/analysis/incremental_session.rb +74 -100
- data/lib/rigor/analysis/project_scan.rb +12 -23
- data/lib/rigor/analysis/result.rb +3 -5
- data/lib/rigor/analysis/rule_catalog.rb +67 -95
- data/lib/rigor/analysis/run_stats.rb +38 -61
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +101 -160
- data/lib/rigor/analysis/runner/pool_coordinator.rb +121 -188
- data/lib/rigor/analysis/runner/project_pre_passes.rb +62 -96
- data/lib/rigor/analysis/runner/run_snapshots.rb +12 -18
- data/lib/rigor/analysis/runner.rb +220 -333
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +30 -43
- data/lib/rigor/analysis/worker_session.rb +64 -102
- data/lib/rigor/ast/type_node.rb +6 -8
- data/lib/rigor/ast.rb +6 -10
- data/lib/rigor/bleeding_edge.rb +27 -35
- data/lib/rigor/builtins/hkt_builtins.rb +7 -14
- data/lib/rigor/builtins/imported_refinements.rb +106 -149
- data/lib/rigor/builtins/predefined_constant_refinements.rb +51 -65
- data/lib/rigor/builtins/regex_refinement.rb +32 -43
- data/lib/rigor/builtins/static_return_refinements.rb +57 -81
- data/lib/rigor/cache/descriptor.rb +58 -94
- data/lib/rigor/cache/incremental_snapshot.rb +32 -48
- data/lib/rigor/cache/rbs_cache_producer.rb +10 -15
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +10 -16
- data/lib/rigor/cache/rbs_class_type_param_names.rb +10 -16
- data/lib/rigor/cache/rbs_constant_table.rb +8 -13
- data/lib/rigor/cache/rbs_descriptor.rb +8 -13
- data/lib/rigor/cache/rbs_environment.rb +11 -19
- data/lib/rigor/cache/rbs_environment_marshal_patch.rb +11 -19
- data/lib/rigor/cache/rbs_known_class_names.rb +8 -12
- data/lib/rigor/cache/store.rb +248 -186
- data/lib/rigor/cli/annotate_command.rb +51 -88
- data/lib/rigor/cli/baseline_command.rb +10 -17
- data/lib/rigor/cli/check_command.rb +121 -199
- data/lib/rigor/cli/check_runner_factory.rb +8 -14
- data/lib/rigor/cli/ci_detector.rb +9 -14
- data/lib/rigor/cli/command.rb +8 -14
- data/lib/rigor/cli/coverage_command.rb +62 -48
- data/lib/rigor/cli/coverage_mutation.rb +14 -19
- data/lib/rigor/cli/coverage_report.rb +0 -2
- data/lib/rigor/cli/coverage_scan.rb +7 -11
- data/lib/rigor/cli/diagnostic_formats.rb +46 -62
- data/lib/rigor/cli/diff_command.rb +10 -20
- data/lib/rigor/cli/docs_command.rb +26 -40
- data/lib/rigor/cli/doctor_command.rb +8 -9
- data/lib/rigor/cli/explain_command.rb +4 -7
- data/lib/rigor/cli/fused_protection_renderer.rb +4 -5
- data/lib/rigor/cli/fused_protection_report.rb +6 -8
- data/lib/rigor/cli/lsp_command.rb +11 -19
- data/lib/rigor/cli/mcp_command.rb +4 -6
- data/lib/rigor/cli/mutation_protection_renderer.rb +3 -4
- data/lib/rigor/cli/mutation_protection_report.rb +6 -9
- data/lib/rigor/cli/options.rb +11 -19
- data/lib/rigor/cli/plugin_command.rb +18 -30
- data/lib/rigor/cli/plugins_command.rb +29 -51
- data/lib/rigor/cli/plugins_renderer.rb +12 -20
- data/lib/rigor/cli/prism_colorizer.rb +13 -19
- data/lib/rigor/cli/protection_fork_scan.rb +55 -0
- data/lib/rigor/cli/protection_renderer.rb +5 -7
- data/lib/rigor/cli/protection_report.rb +34 -18
- data/lib/rigor/cli/renderable.rb +4 -6
- data/lib/rigor/cli/show_bleedingedge_command.rb +5 -8
- data/lib/rigor/cli/sig_gen_command.rb +14 -26
- data/lib/rigor/cli/skill_command.rb +30 -47
- data/lib/rigor/cli/skill_describe.rb +40 -64
- data/lib/rigor/cli/trace_command.rb +9 -16
- data/lib/rigor/cli/trace_renderer.rb +35 -51
- data/lib/rigor/cli/triage_command.rb +6 -10
- data/lib/rigor/cli/triage_renderer.rb +1 -2
- data/lib/rigor/cli/type_of_command.rb +14 -23
- data/lib/rigor/cli/type_of_renderer.rb +3 -5
- data/lib/rigor/cli/type_scan_command.rb +6 -10
- data/lib/rigor/cli/type_scan_renderer.rb +3 -5
- data/lib/rigor/cli/type_scan_report.rb +2 -3
- data/lib/rigor/cli/upgrade_command.rb +2 -3
- data/lib/rigor/cli.rb +16 -28
- data/lib/rigor/config_audit.rb +35 -44
- data/lib/rigor/configuration/dependencies.rb +41 -70
- data/lib/rigor/configuration/severity_profile.rb +28 -42
- data/lib/rigor/configuration.rb +150 -241
- data/lib/rigor/environment/bundle_sig_discovery.rb +74 -118
- data/lib/rigor/environment/class_registry.rb +19 -26
- data/lib/rigor/environment/constant_type_cache_holder.rb +14 -21
- data/lib/rigor/environment/hkt_registry_holder.rb +6 -12
- data/lib/rigor/environment/lockfile_resolver.rb +31 -47
- data/lib/rigor/environment/missing_gem_constant_index.rb +128 -0
- data/lib/rigor/environment/rbs_collection_discovery.rb +39 -63
- data/lib/rigor/environment/rbs_coverage_report.rb +24 -42
- data/lib/rigor/environment/rbs_loader.rb +420 -518
- data/lib/rigor/environment/reflection.rb +28 -53
- data/lib/rigor/environment/reporters.rb +13 -24
- data/lib/rigor/environment.rb +225 -304
- data/lib/rigor/flow_contribution/conflict.rb +16 -27
- data/lib/rigor/flow_contribution/element.rb +7 -12
- data/lib/rigor/flow_contribution/fact.rb +33 -57
- data/lib/rigor/flow_contribution/merge_result.rb +6 -9
- data/lib/rigor/flow_contribution/merger.rb +32 -47
- data/lib/rigor/flow_contribution.rb +37 -55
- data/lib/rigor/inference/acceptance.rb +133 -219
- data/lib/rigor/inference/block_parameter_binder.rb +52 -82
- data/lib/rigor/inference/body_fixpoint.rb +22 -30
- data/lib/rigor/inference/budget_trace.rb +43 -63
- data/lib/rigor/inference/builtins/array_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/comparable_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/complex_catalog.rb +13 -19
- data/lib/rigor/inference/builtins/date_catalog.rb +38 -67
- data/lib/rigor/inference/builtins/encoding_catalog.rb +22 -36
- data/lib/rigor/inference/builtins/enumerable_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/exception_catalog.rb +38 -57
- data/lib/rigor/inference/builtins/hash_catalog.rb +9 -14
- data/lib/rigor/inference/builtins/method_catalog.rb +29 -48
- data/lib/rigor/inference/builtins/numeric_catalog.rb +13 -18
- data/lib/rigor/inference/builtins/pathname_catalog.rb +8 -13
- data/lib/rigor/inference/builtins/proc_catalog.rb +38 -62
- data/lib/rigor/inference/builtins/random_catalog.rb +21 -32
- data/lib/rigor/inference/builtins/range_catalog.rb +12 -21
- data/lib/rigor/inference/builtins/rational_catalog.rb +9 -15
- data/lib/rigor/inference/builtins/re_catalog.rb +29 -48
- data/lib/rigor/inference/builtins/set_catalog.rb +18 -27
- data/lib/rigor/inference/builtins/string_catalog.rb +12 -19
- data/lib/rigor/inference/builtins/struct_catalog.rb +18 -30
- data/lib/rigor/inference/builtins/time_catalog.rb +28 -44
- data/lib/rigor/inference/closure_escape_analyzer.rb +44 -67
- data/lib/rigor/inference/coverage_scanner.rb +13 -18
- data/lib/rigor/inference/def_return_typer.rb +8 -14
- data/lib/rigor/inference/dynamic_origin.rb +23 -20
- data/lib/rigor/inference/expression_typer.rb +794 -1154
- data/lib/rigor/inference/fallback.rb +8 -12
- data/lib/rigor/inference/fallback_tracer.rb +4 -10
- data/lib/rigor/inference/flow_tracer.rb +25 -36
- data/lib/rigor/inference/fork_map.rb +87 -0
- data/lib/rigor/inference/hkt_body.rb +45 -68
- data/lib/rigor/inference/hkt_body_parser.rb +33 -52
- data/lib/rigor/inference/hkt_reducer.rb +38 -59
- data/lib/rigor/inference/hkt_registry.rb +50 -76
- data/lib/rigor/inference/indexed_narrowing.rb +55 -81
- data/lib/rigor/inference/macro_block_self_type.rb +21 -34
- data/lib/rigor/inference/method_dispatcher/array_to_h_folding.rb +11 -18
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +49 -83
- data/lib/rigor/inference/method_dispatcher/call_context.rb +16 -23
- data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +13 -22
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +307 -454
- data/lib/rigor/inference/method_dispatcher/data_folding.rb +24 -34
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +22 -37
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +52 -81
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +51 -78
- data/lib/rigor/inference/method_dispatcher/literal_string_folding.rb +60 -97
- data/lib/rigor/inference/method_dispatcher/math_folding.rb +23 -34
- data/lib/rigor/inference/method_dispatcher/member_shape_projection.rb +18 -26
- data/lib/rigor/inference/method_dispatcher/method_folding.rb +37 -71
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +114 -182
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +122 -193
- data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +15 -24
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +64 -93
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +31 -45
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +6 -9
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +356 -511
- data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +22 -32
- data/lib/rigor/inference/method_dispatcher/singleton_folding.rb +15 -21
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +66 -82
- data/lib/rigor/inference/method_dispatcher/time_folding.rb +10 -15
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +9 -13
- data/lib/rigor/inference/method_dispatcher.rb +378 -524
- data/lib/rigor/inference/method_parameter_binder.rb +81 -114
- data/lib/rigor/inference/multi_target_binder.rb +51 -68
- data/lib/rigor/inference/mutation_widening.rb +115 -158
- data/lib/rigor/inference/narrowing.rb +627 -727
- data/lib/rigor/inference/origin_lookup.rb +38 -0
- data/lib/rigor/inference/parameter_inference_collector.rb +154 -109
- data/lib/rigor/inference/precision_scanner.rb +26 -35
- data/lib/rigor/inference/project_patched_methods.rb +20 -32
- data/lib/rigor/inference/project_patched_scanner.rb +23 -37
- data/lib/rigor/inference/protection_scanner.rb +16 -18
- data/lib/rigor/inference/rbs_type_translator.rb +49 -66
- data/lib/rigor/inference/scope_indexer.rb +473 -821
- data/lib/rigor/inference/statement_evaluator.rb +754 -1114
- data/lib/rigor/inference/struct_fold_safety.rb +34 -48
- data/lib/rigor/inference/synthetic_method.rb +9 -16
- data/lib/rigor/inference/synthetic_method_index.rb +20 -35
- data/lib/rigor/inference/synthetic_method_scanner.rb +63 -103
- data/lib/rigor/language_server/buffer_resolution.rb +6 -9
- data/lib/rigor/language_server/buffer_table.rb +11 -18
- data/lib/rigor/language_server/completion_provider.rb +69 -116
- data/lib/rigor/language_server/debouncer.rb +16 -25
- data/lib/rigor/language_server/diagnostic_publisher.rb +26 -40
- data/lib/rigor/language_server/document_symbol_provider.rb +14 -19
- data/lib/rigor/language_server/folding_range_provider.rb +11 -19
- data/lib/rigor/language_server/hover_provider.rb +8 -11
- data/lib/rigor/language_server/hover_renderer.rb +56 -93
- data/lib/rigor/language_server/loop.rb +14 -19
- data/lib/rigor/language_server/project_context.rb +46 -74
- data/lib/rigor/language_server/selection_range_provider.rb +9 -12
- data/lib/rigor/language_server/server.rb +55 -83
- data/lib/rigor/language_server/signature_help_provider.rb +29 -46
- data/lib/rigor/language_server/synchronized_writer.rb +4 -7
- data/lib/rigor/language_server/uri.rb +8 -13
- data/lib/rigor/language_server.rb +4 -6
- data/lib/rigor/mcp/loop.rb +2 -3
- data/lib/rigor/mcp/server.rb +4 -7
- data/lib/rigor/mcp.rb +3 -6
- data/lib/rigor/plugin/access_denied_error.rb +5 -8
- data/lib/rigor/plugin/additional_initializer.rb +21 -31
- data/lib/rigor/plugin/base.rb +335 -518
- data/lib/rigor/plugin/blueprint.rb +14 -23
- data/lib/rigor/plugin/box.rb +18 -29
- data/lib/rigor/plugin/fact_store.rb +16 -26
- data/lib/rigor/plugin/inflector.rb +37 -53
- data/lib/rigor/plugin/io_boundary.rb +33 -56
- data/lib/rigor/plugin/isolation.rb +42 -55
- data/lib/rigor/plugin/load_error.rb +10 -15
- data/lib/rigor/plugin/loader.rb +30 -49
- data/lib/rigor/plugin/macro/block_as_method.rb +20 -32
- data/lib/rigor/plugin/macro/heredoc_template.rb +35 -58
- data/lib/rigor/plugin/macro/nested_class_template.rb +22 -36
- data/lib/rigor/plugin/macro/trait_registry.rb +34 -51
- data/lib/rigor/plugin/macro.rb +10 -15
- data/lib/rigor/plugin/manifest.rb +85 -144
- data/lib/rigor/plugin/node_context.rb +14 -22
- data/lib/rigor/plugin/node_rule_walk.rb +49 -74
- data/lib/rigor/plugin/protocol_contract.rb +25 -39
- data/lib/rigor/plugin/registry.rb +132 -205
- data/lib/rigor/plugin/services.rb +21 -33
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +11 -19
- data/lib/rigor/plugin/trust_policy.rb +24 -38
- data/lib/rigor/plugin/type_node_resolver.rb +15 -24
- data/lib/rigor/protection/diagnostic_oracle.rb +11 -13
- data/lib/rigor/protection/mutation_scanner.rb +27 -35
- data/lib/rigor/protection/mutator.rb +50 -70
- data/lib/rigor/protection/test_suite_oracle.rb +20 -27
- data/lib/rigor/rbs_extended/conformance_checker.rb +48 -68
- data/lib/rigor/rbs_extended/hkt_directives.rb +28 -54
- data/lib/rigor/rbs_extended/reporter.rb +24 -40
- data/lib/rigor/rbs_extended.rb +107 -197
- data/lib/rigor/reflection.rb +68 -86
- data/lib/rigor/scope/discovery_index.rb +14 -19
- data/lib/rigor/scope.rb +255 -310
- data/lib/rigor/sig_gen/classification.rb +6 -10
- data/lib/rigor/sig_gen/generator.rb +197 -323
- data/lib/rigor/sig_gen/layout_index.rb +12 -20
- data/lib/rigor/sig_gen/method_candidate.rb +12 -17
- data/lib/rigor/sig_gen/observation_collector.rb +38 -70
- data/lib/rigor/sig_gen/observed_call.rb +13 -23
- data/lib/rigor/sig_gen/path_mapper.rb +17 -29
- data/lib/rigor/sig_gen/renderer.rb +7 -13
- data/lib/rigor/sig_gen/type_elaborator.rb +15 -28
- data/lib/rigor/sig_gen/write_result.rb +8 -16
- data/lib/rigor/sig_gen/writer.rb +95 -174
- data/lib/rigor/sig_gen.rb +3 -6
- data/lib/rigor/signature_path_audit.rb +24 -30
- data/lib/rigor/source/constant_path.rb +10 -14
- data/lib/rigor/source/literals.rb +31 -45
- data/lib/rigor/source/node_locator.rb +9 -11
- data/lib/rigor/source/node_walker.rb +9 -13
- data/lib/rigor/source.rb +3 -4
- data/lib/rigor/testing.rb +16 -20
- data/lib/rigor/triage/catalogue.rb +38 -62
- data/lib/rigor/triage.rb +31 -52
- data/lib/rigor/trinary.rb +9 -13
- data/lib/rigor/type/acceptance_router.rb +4 -6
- data/lib/rigor/type/accepts_result.rb +10 -14
- data/lib/rigor/type/app.rb +19 -27
- data/lib/rigor/type/bot.rb +4 -6
- data/lib/rigor/type/bound_method.rb +10 -15
- data/lib/rigor/type/combinator.rb +165 -257
- data/lib/rigor/type/constant.rb +23 -34
- data/lib/rigor/type/data_class.rb +10 -15
- data/lib/rigor/type/data_instance.rb +14 -20
- data/lib/rigor/type/difference.rb +21 -32
- data/lib/rigor/type/dynamic.rb +3 -5
- data/lib/rigor/type/hash_shape.rb +32 -18
- data/lib/rigor/type/integer_range.rb +11 -16
- data/lib/rigor/type/intersection.rb +27 -42
- data/lib/rigor/type/nominal.rb +10 -15
- data/lib/rigor/type/plain_lattice.rb +9 -13
- data/lib/rigor/type/refined.rb +67 -114
- data/lib/rigor/type/singleton.rb +4 -6
- data/lib/rigor/type/struct_class.rb +11 -16
- data/lib/rigor/type/struct_instance.rb +15 -21
- data/lib/rigor/type/tuple.rb +14 -19
- data/lib/rigor/type/union.rb +30 -42
- data/lib/rigor/type_node/generic.rb +14 -26
- data/lib/rigor/type_node/identifier.rb +12 -19
- data/lib/rigor/type_node.rb +3 -12
- data/lib/rigor/value_semantics.rb +16 -21
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +18 -30
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +16 -29
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +12 -23
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +22 -39
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +26 -46
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +51 -87
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +10 -17
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +26 -39
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +141 -184
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +30 -51
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +57 -92
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +92 -108
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +13 -22
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +15 -25
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +8 -13
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +16 -24
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +40 -48
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +140 -129
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +56 -59
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +27 -41
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +16 -24
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +172 -0
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +168 -241
- data/plugins/rigor-activerecord/lib/rigor-activerecord.rb +3 -5
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +8 -14
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +9 -15
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +4 -7
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +23 -41
- data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +3 -5
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +6 -10
- data/plugins/rigor-activesupport-core-ext/lib/rigor-activesupport-core-ext.rb +8 -11
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +32 -0
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +30 -45
- data/plugins/rigor-devise/lib/rigor-devise.rb +3 -5
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +43 -69
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +26 -35
- data/plugins/rigor-dry-schema/lib/rigor-dry-schema.rb +3 -5
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +30 -47
- data/plugins/rigor-dry-struct/lib/rigor-dry-struct.rb +3 -5
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +67 -113
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +29 -46
- data/plugins/rigor-dry-types/lib/rigor-dry-types.rb +3 -5
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -20
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +14 -23
- data/plugins/rigor-dry-validation/lib/rigor-dry-validation.rb +2 -3
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +22 -37
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +28 -46
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +13 -17
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +30 -47
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +52 -80
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +21 -31
- data/plugins/rigor-graphql/lib/rigor-graphql.rb +3 -5
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +11 -17
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +20 -34
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +45 -75
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +22 -36
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +22 -41
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +17 -32
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +6 -12
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +4 -8
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +17 -32
- data/plugins/rigor-rails/lib/rigor-rails.rb +11 -18
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +58 -92
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +20 -34
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +20 -31
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +49 -82
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +55 -92
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +51 -90
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +17 -30
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/grape_api_discoverer.rb +189 -0
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +38 -70
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +61 -75
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +319 -505
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +91 -96
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +32 -54
- data/plugins/rigor-rbs-inline/lib/rigor-rbs-inline.rb +8 -13
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +9 -16
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +24 -39
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +13 -22
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +34 -56
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/scope_walker.rb +22 -42
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +43 -75
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +27 -39
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/http_status_codes.rb +14 -19
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +20 -34
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +28 -47
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +21 -37
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +13 -22
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +18 -31
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +6 -10
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +14 -29
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +23 -41
- data/plugins/rigor-sinatra/lib/rigor-sinatra.rb +3 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +23 -38
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +57 -96
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +22 -35
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +41 -69
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/method_signature.rb +6 -10
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +24 -41
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +29 -50
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +55 -88
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +159 -262
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +21 -29
- data/plugins/rigor-statesman/lib/rigor-statesman.rb +3 -5
- data/plugins/rigor-typescript-utility-types/lib/rigor/plugin/typescript_utility_types.rb +23 -37
- data/plugins/rigor-typescript-utility-types/lib/rigor-typescript-utility-types.rb +4 -6
- data/sig/rigor/environment.rbs +1 -0
- data/sig/rigor/scope.rbs +6 -0
- metadata +9 -1
data/lib/rigor/environment.rb
CHANGED
|
@@ -8,6 +8,7 @@ require_relative "environment/reflection"
|
|
|
8
8
|
require_relative "environment/reporters"
|
|
9
9
|
require_relative "environment/hkt_registry_holder"
|
|
10
10
|
require_relative "environment/constant_type_cache_holder"
|
|
11
|
+
require_relative "environment/missing_gem_constant_index"
|
|
11
12
|
require_relative "environment/bundle_sig_discovery"
|
|
12
13
|
require_relative "environment/lockfile_resolver"
|
|
13
14
|
require_relative "environment/rbs_collection_discovery"
|
|
@@ -21,36 +22,28 @@ require_relative "type_node/name_scope"
|
|
|
21
22
|
require_relative "type_node/resolver_chain"
|
|
22
23
|
|
|
23
24
|
module Rigor
|
|
24
|
-
# The engine's view of the type universe outside the current scope.
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
# constant-folding tiers cannot answer.
|
|
25
|
+
# The engine's view of the type universe outside the current scope. Slice 1 exposed only the class
|
|
26
|
+
# registry; Slice 4 added the RBS loader, which threads through ExpressionTyper and MethodDispatcher to
|
|
27
|
+
# type constant references and method calls that the literal-typer and constant-folding tiers cannot
|
|
28
|
+
# answer.
|
|
29
29
|
#
|
|
30
30
|
# See docs/internal-spec/inference-engine.md for the binding contract.
|
|
31
31
|
class Environment # rubocop:disable Metrics/ClassLength
|
|
32
32
|
DEFAULT_PROJECT_SIG_DIR = "sig"
|
|
33
33
|
private_constant :DEFAULT_PROJECT_SIG_DIR
|
|
34
34
|
|
|
35
|
-
# Slice A stdlib expansion. Stdlib libraries that
|
|
36
|
-
# `
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
# `
|
|
40
|
-
#
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
# (`pathname`, `optparse`, `json`, `yaml`, `fileutils`,
|
|
44
|
-
# `tempfile`, `uri`, `logger`, `date`) plus the analyzer-
|
|
45
|
-
# adjacent gems shipping their own RBS in this bundle
|
|
46
|
-
# (`prism`, `rbs`). On hosts where one of these libraries is
|
|
47
|
-
# not installed, the loader silently drops it.
|
|
35
|
+
# Slice A stdlib expansion. Stdlib libraries that `Environment.for_project` loads on top of RBS core
|
|
36
|
+
# unless the caller passes an explicit `libraries:` array. Each entry MUST be a stdlib library name
|
|
37
|
+
# accepted by `RBS::EnvironmentLoader#has_library?`; unknown libraries MUST fail-soft
|
|
38
|
+
# (`RbsLoader#build_env` already filters through `has_library?`). The default set covers the common
|
|
39
|
+
# stdlib surface a Ruby program is likely to import (`pathname`, `optparse`, `json`, `yaml`, `fileutils`,
|
|
40
|
+
# `tempfile`, `uri`, `logger`, `date`) plus the analyzer-adjacent gems shipping their own RBS in this
|
|
41
|
+
# bundle (`prism`, `rbs`). On hosts where one of these libraries is not installed, the loader silently
|
|
42
|
+
# drops it.
|
|
48
43
|
#
|
|
49
|
-
# Callers MAY add to the default by passing
|
|
50
|
-
# `
|
|
51
|
-
# `
|
|
52
|
-
# a strictly RBS-core view MUST construct an `RbsLoader`
|
|
53
|
-
# directly instead of going through `for_project`.
|
|
44
|
+
# Callers MAY add to the default by passing `libraries: %w[csv ...]`; the explicit list is appended to
|
|
45
|
+
# `DEFAULT_LIBRARIES` and de-duplicated. Callers that need a strictly RBS-core view MUST construct an
|
|
46
|
+
# `RbsLoader` directly instead of going through `for_project`.
|
|
54
47
|
DEFAULT_LIBRARIES = %w[
|
|
55
48
|
pathname optparse json yaml fileutils tempfile tmpdir
|
|
56
49
|
stringio forwardable digest securerandom
|
|
@@ -65,11 +58,10 @@ module Rigor
|
|
|
65
58
|
prism rbs
|
|
66
59
|
].freeze
|
|
67
60
|
|
|
68
|
-
# ADR-72 — a Gemfile.lock gem name mapped to the opt-in plugin id
|
|
69
|
-
# that
|
|
70
|
-
#
|
|
71
|
-
#
|
|
72
|
-
# error). Keyed on the gem name `RbsCoverageReport` reports.
|
|
61
|
+
# ADR-72 — a Gemfile.lock gem name mapped to the opt-in plugin id that ships the SAME core-ext RBS. When
|
|
62
|
+
# that plugin is loaded the auto-overlay for the gem stands down, so the two never both declare the
|
|
63
|
+
# methods (which would raise a duplicate-declaration error). Keyed on the gem name `RbsCoverageReport`
|
|
64
|
+
# reports.
|
|
73
65
|
GEM_OVERLAY_PLUGIN_IDS = { "activesupport" => "activesupport-core-ext" }.freeze
|
|
74
66
|
|
|
75
67
|
attr_reader :class_registry, :rbs_loader, :plugin_registry, :dependency_source_index,
|
|
@@ -77,39 +69,30 @@ module Rigor
|
|
|
77
69
|
:synthetic_method_index, :project_patched_methods
|
|
78
70
|
|
|
79
71
|
# @param class_registry [Rigor::Environment::ClassRegistry]
|
|
80
|
-
# @param rbs_loader [Rigor::Environment::RbsLoader, nil] when nil the
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
#
|
|
86
|
-
#
|
|
87
|
-
#
|
|
88
|
-
#
|
|
89
|
-
#
|
|
90
|
-
# default), no
|
|
91
|
-
# participates — useful for tests, the `Environment.default`
|
|
92
|
-
# facade, and analyses that don't load plugins.
|
|
93
|
-
# @param dependency_source_index [Rigor::Analysis::DependencySourceInference::Index, nil]
|
|
94
|
-
# ADR-10 slice 2b-ii. The per-run index of opt-in gem
|
|
95
|
-
# sources the dispatcher consults BELOW RBS dispatch.
|
|
96
|
-
# When nil (the default), no dep-source contribution
|
|
97
|
-
# participates and the dispatcher tier is a no-op.
|
|
72
|
+
# @param rbs_loader [Rigor::Environment::RbsLoader, nil] when nil the environment is "RBS-blind"; useful
|
|
73
|
+
# in tests that want to assert how the engine behaves without RBS data. The default Environment wires
|
|
74
|
+
# the shared core loader, which is itself lazy: requesting an environment instance does NOT load RBS
|
|
75
|
+
# until a method or class query actually consults the loader.
|
|
76
|
+
# @param plugin_registry [Rigor::Plugin::Registry, nil] v0.1.1 Track 2 slice 7. The per-run plugin
|
|
77
|
+
# registry the inference engine consults at call sites for plugin `dynamic_return` rules. When nil
|
|
78
|
+
# (the default), no plugin-level return-type contribution participates — useful for tests, the
|
|
79
|
+
# `Environment.default` facade, and analyses that don't load plugins.
|
|
80
|
+
# @param dependency_source_index [Rigor::Analysis::DependencySourceInference::Index, nil] ADR-10 slice
|
|
81
|
+
# 2b-ii. The per-run index of opt-in gem sources the dispatcher consults BELOW RBS dispatch. When nil
|
|
82
|
+
# (the default), no dep-source contribution participates and the dispatcher tier is a no-op.
|
|
98
83
|
def initialize(class_registry: ClassRegistry.default, rbs_loader: nil, # rubocop:disable Metrics/ParameterLists
|
|
99
84
|
plugin_registry: nil, dependency_source_index: nil,
|
|
100
85
|
rbs_extended_reporter: nil, boundary_cross_reporter: nil,
|
|
101
86
|
source_rbs_synthesis_reporter: nil,
|
|
102
87
|
synthetic_method_index: nil, project_patched_methods: nil,
|
|
103
|
-
hkt_registry: nil)
|
|
88
|
+
hkt_registry: nil, missing_rbs_gems: [], missing_rbs_bundle_path: nil)
|
|
104
89
|
@class_registry = class_registry
|
|
105
90
|
@rbs_loader = rbs_loader
|
|
106
91
|
@plugin_registry = plugin_registry
|
|
107
92
|
@dependency_source_index = dependency_source_index
|
|
108
|
-
# ADR-pending — reporters live in a mutable container so
|
|
109
|
-
#
|
|
110
|
-
#
|
|
111
|
-
# existing `#rbs_extended_reporter` / `#boundary_cross_reporter`
|
|
112
|
-
# accessors below preserve the public lookup shape.
|
|
93
|
+
# ADR-pending — reporters live in a mutable container so long-lived integrations (LSP `ProjectContext`)
|
|
94
|
+
# can swap them per `Runner.run` without rebuilding the env. The existing `#rbs_extended_reporter` /
|
|
95
|
+
# `#boundary_cross_reporter` accessors below preserve the public lookup shape.
|
|
113
96
|
@reporters = Reporters.new(
|
|
114
97
|
rbs_extended: rbs_extended_reporter,
|
|
115
98
|
boundary_cross: boundary_cross_reporter,
|
|
@@ -117,34 +100,30 @@ module Rigor
|
|
|
117
100
|
)
|
|
118
101
|
@synthetic_method_index = synthetic_method_index || Inference::SyntheticMethodIndex::EMPTY
|
|
119
102
|
@project_patched_methods = project_patched_methods || Inference::ProjectPatchedMethods::EMPTY
|
|
120
|
-
# ADR-20 slice 2c + 2e — the per-env HKT registry
|
|
121
|
-
#
|
|
122
|
-
#
|
|
123
|
-
# the
|
|
124
|
-
# with the
|
|
125
|
-
#
|
|
126
|
-
# the RBS
|
|
127
|
-
# (defined below) MEMOIZES the result of merging the
|
|
128
|
-
# base with the RBS scan so the scan is paid at most
|
|
129
|
-
# once per Environment lifetime — and only when first
|
|
130
|
-
# consulted, leaving fast paths like `rigor check
|
|
131
|
-
# --cache-stats --no-stats` from doing the RBS env
|
|
132
|
-
# build at all.
|
|
103
|
+
# ADR-20 slice 2c + 2e — the per-env HKT registry consulted by the reducer when resolving `Type::App`
|
|
104
|
+
# carriers. Defaults to {Inference::HktRegistry::EMPTY}; the {.default} / {.for_project} class methods
|
|
105
|
+
# seed it with the bundled builtins (`json::value`, …) plus any `%a{rigor:v1:hkt_register /
|
|
106
|
+
# hkt_define}` annotations the RBS loader exposes. The hkt_registry getter (defined below) MEMOIZES
|
|
107
|
+
# the result of merging the base with the RBS scan so the scan is paid at most once per Environment
|
|
108
|
+
# lifetime — and only when first consulted, leaving fast paths like `rigor check --cache-stats
|
|
109
|
+
# --no-stats` from doing the RBS env build at all.
|
|
133
110
|
@hkt_registry_base = hkt_registry || Inference::HktRegistry::EMPTY
|
|
134
111
|
@hkt_registry_holder = HktRegistryHolder.new
|
|
135
112
|
@constant_type_cache = ConstantTypeCacheHolder.new
|
|
113
|
+
# ADR-82 WD9 — `[gem_name, version]` pairs for the locked gems with no resolvable RBS. The
|
|
114
|
+
# root-constant ownership index over them is built lazily (first unresolved constant read) so runs
|
|
115
|
+
# whose constants all resolve never pay the entry-file scan.
|
|
116
|
+
@missing_rbs_gems = missing_rbs_gems.freeze
|
|
117
|
+
@missing_rbs_bundle_path = missing_rbs_bundle_path
|
|
118
|
+
@missing_rbs_gem_constants_holder = HktRegistryHolder.new
|
|
136
119
|
@name_scope = build_name_scope
|
|
137
120
|
freeze
|
|
138
121
|
end
|
|
139
122
|
|
|
140
|
-
# ADR-20 slices 2e + 6 — lazy HKT registry getter.
|
|
141
|
-
#
|
|
142
|
-
#
|
|
143
|
-
#
|
|
144
|
-
# plugin entries, which beat the bundled JSON_VALUE.
|
|
145
|
-
# Memoised; single-threaded use only (under the Ractor
|
|
146
|
-
# pool path each worker has its own Environment so
|
|
147
|
-
# cross-worker mutation is impossible; the LSP
|
|
123
|
+
# ADR-20 slices 2e + 6 — lazy HKT registry getter. Merge order on first call: builtins (base) ← plugin
|
|
124
|
+
# manifest aggregation ← RBS env scan. Last-write-wins on URI collisions so user-authored `.rbs` overlays
|
|
125
|
+
# beat plugin entries, which beat the bundled JSON_VALUE. Memoised; single-threaded use only (under the
|
|
126
|
+
# Ractor pool path each worker has its own Environment so cross-worker mutation is impossible; the LSP
|
|
148
127
|
# single-publish-at-a-time invariant serialises here).
|
|
149
128
|
def hkt_registry
|
|
150
129
|
@hkt_registry_holder.fetch do
|
|
@@ -161,10 +140,24 @@ module Rigor
|
|
|
161
140
|
end
|
|
162
141
|
end
|
|
163
142
|
|
|
164
|
-
#
|
|
165
|
-
#
|
|
166
|
-
#
|
|
167
|
-
#
|
|
143
|
+
# ADR-82 WD9 — the gem name owning `root_constant_name`, when that gem is locked in the project's
|
|
144
|
+
# Gemfile.lock, ships no resolvable RBS, and its entry file declares the constant at top level. Nil for
|
|
145
|
+
# everything else — the caller then keeps the generic provenance cause. The index is built once, lazily,
|
|
146
|
+
# from RubyGems metadata + a Prism parse of each gem's entry file; no gem code runs (see
|
|
147
|
+
# {MissingGemConstantIndex}). Under the fork pool a worker that never meets an unresolved constant never
|
|
148
|
+
# builds it.
|
|
149
|
+
def missing_rbs_gem_owner(root_constant_name)
|
|
150
|
+
return nil if @missing_rbs_gems.empty?
|
|
151
|
+
|
|
152
|
+
index = @missing_rbs_gem_constants_holder.fetch do
|
|
153
|
+
MissingGemConstantIndex.build(@missing_rbs_gems, bundle_path: @missing_rbs_bundle_path)
|
|
154
|
+
end
|
|
155
|
+
index[root_constant_name.to_s]
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# Backwards-compatible reporter accessors — every existing consumer (rbs_extended, method_dispatcher)
|
|
159
|
+
# calls these. The frozen `@reporters` container is mutable for slot reassignment via
|
|
160
|
+
# {#attach_reporters!} below.
|
|
168
161
|
def rbs_extended_reporter
|
|
169
162
|
@reporters.rbs_extended
|
|
170
163
|
end
|
|
@@ -173,29 +166,22 @@ module Rigor
|
|
|
173
166
|
@reporters.boundary_cross
|
|
174
167
|
end
|
|
175
168
|
|
|
176
|
-
# ADR-32 WD6 — the per-run accumulator for synthesizer
|
|
177
|
-
#
|
|
178
|
-
# `
|
|
179
|
-
#
|
|
180
|
-
# `source-rbs-synthesis-failed` `:info` diagnostics after
|
|
181
|
-
# analysis completes. Nil when no plugin contributes a
|
|
182
|
-
# synthesizer.
|
|
169
|
+
# ADR-32 WD6 — the per-run accumulator for synthesizer failure events. `Environment.for_project` records
|
|
170
|
+
# `[:error, message]` returns from a plugin's `source_rbs_synthesizer` here so the Runner can emit
|
|
171
|
+
# `source-rbs-synthesis-failed` `:info` diagnostics after analysis completes. Nil when no plugin
|
|
172
|
+
# contributes a synthesizer.
|
|
183
173
|
def source_rbs_synthesis_reporter
|
|
184
174
|
@reporters.source_rbs_synthesis
|
|
185
175
|
end
|
|
186
176
|
|
|
187
|
-
# Replaces the env's per-run reporter slots. Intended for
|
|
188
|
-
#
|
|
189
|
-
#
|
|
190
|
-
#
|
|
191
|
-
# events stay scoped to that call rather than accumulating
|
|
192
|
-
# across publishes.
|
|
177
|
+
# Replaces the env's per-run reporter slots. Intended for long-lived integrations (LSP `ProjectContext`)
|
|
178
|
+
# that share one Environment instance across many `Runner.run` calls: each call attaches its own fresh
|
|
179
|
+
# reporter pair so per-call diagnostic events stay scoped to that call rather than accumulating across
|
|
180
|
+
# publishes.
|
|
193
181
|
#
|
|
194
|
-
# Single-threaded use only. Concurrent publishes against one
|
|
195
|
-
#
|
|
196
|
-
#
|
|
197
|
-
# path. The Ractor pool path builds a per-worker Environment
|
|
198
|
-
# and does not reach this surface.
|
|
182
|
+
# Single-threaded use only. Concurrent publishes against one Environment must serialise — the LSP
|
|
183
|
+
# `Server` debouncer + synchronized writer already enforces this for the editor path. The Ractor pool
|
|
184
|
+
# path builds a per-worker Environment and does not reach this surface.
|
|
199
185
|
def attach_reporters!(rbs_extended_reporter:, boundary_cross_reporter:)
|
|
200
186
|
@reporters.rbs_extended = rbs_extended_reporter
|
|
201
187
|
@reporters.boundary_cross = boundary_cross_reporter
|
|
@@ -210,26 +196,20 @@ module Rigor
|
|
|
210
196
|
).freeze
|
|
211
197
|
end
|
|
212
198
|
|
|
213
|
-
# Builds an Environment that consults the project's local
|
|
214
|
-
#
|
|
199
|
+
# Builds an Environment that consults the project's local signatures and any opt-in stdlib libraries on
|
|
200
|
+
# top of RBS core.
|
|
215
201
|
#
|
|
216
|
-
# @param root [String, Pathname] project root used to auto-detect
|
|
217
|
-
#
|
|
218
|
-
#
|
|
219
|
-
#
|
|
220
|
-
#
|
|
221
|
-
#
|
|
222
|
-
#
|
|
223
|
-
#
|
|
224
|
-
# @param
|
|
225
|
-
#
|
|
226
|
-
# the
|
|
227
|
-
# exists, otherwise no signature path is loaded.
|
|
228
|
-
# @param cache_store [Rigor::Cache::Store, nil] persistent cache
|
|
229
|
-
# threaded into the underlying {Environment::RbsLoader} so
|
|
230
|
-
# constant lookups (and, in later v0.0.9 slices, other
|
|
231
|
-
# reflection artefacts) consult the cache. Pass `nil` (the
|
|
232
|
-
# default) to skip caching for this environment.
|
|
202
|
+
# @param root [String, Pathname] project root used to auto-detect the default signature path. Defaults
|
|
203
|
+
# to the current working directory.
|
|
204
|
+
# @param libraries [Array<String, Symbol>] additional stdlib libraries to load on top of
|
|
205
|
+
# {DEFAULT_LIBRARIES}. The final list is the union of the two, de-duplicated while preserving order.
|
|
206
|
+
# Pass an empty array (the default) to load only the defaults.
|
|
207
|
+
# @param signature_paths [Array<String, Pathname>, nil] explicit list of `sig/`-style directories. When
|
|
208
|
+
# `nil` (the default), the canonical project layout `<root>/sig` is used if it exists, otherwise no
|
|
209
|
+
# signature path is loaded.
|
|
210
|
+
# @param cache_store [Rigor::Cache::Store, nil] persistent cache threaded into the underlying
|
|
211
|
+
# {Environment::RbsLoader} so constant lookups (and, in later v0.0.9 slices, other reflection
|
|
212
|
+
# artefacts) consult the cache. Pass `nil` (the default) to skip caching for this environment.
|
|
233
213
|
# @return [Rigor::Environment]
|
|
234
214
|
# rubocop:disable Metrics/MethodLength, Metrics/ParameterLists
|
|
235
215
|
def for_project(root: Dir.pwd, libraries: [], signature_paths: nil, cache_store: nil,
|
|
@@ -242,21 +222,15 @@ module Rigor
|
|
|
242
222
|
synthetic_method_index: nil, project_patched_methods: nil,
|
|
243
223
|
source_files: [])
|
|
244
224
|
resolved_paths = signature_paths || default_signature_paths(root)
|
|
245
|
-
# O4 MVP — append per-gem `sig/` directories discovered
|
|
246
|
-
#
|
|
247
|
-
#
|
|
248
|
-
#
|
|
249
|
-
# (semantic precedence inside `RbsLoader.build_env_for`);
|
|
250
|
-
# gem-shipped sigs append last so user overrides stay
|
|
251
|
-
# authoritative.
|
|
225
|
+
# O4 MVP — append per-gem `sig/` directories discovered under the target project's bundler install
|
|
226
|
+
# root. Empty array when neither an explicit path nor auto-detection finds a bundle. Order: user
|
|
227
|
+
# `signature_paths:` win first (semantic precedence inside `RbsLoader.build_env_for`); gem-shipped
|
|
228
|
+
# sigs append last so user overrides stay authoritative.
|
|
252
229
|
#
|
|
253
|
-
# O4 Layer 3 — when a Gemfile.lock is available (explicit
|
|
254
|
-
#
|
|
255
|
-
#
|
|
256
|
-
#
|
|
257
|
-
# tree (out-of-band installs, version drift after a
|
|
258
|
-
# `bundle update`) are silently dropped so only gems the
|
|
259
|
-
# project actually declares contribute RBS.
|
|
230
|
+
# O4 Layer 3 — when a Gemfile.lock is available (explicit `bundler_lockfile:` or auto-detected next
|
|
231
|
+
# to the project root), use the locked gem set to filter the discovered `sig/` directories. Stale
|
|
232
|
+
# gems in the bundle install tree (out-of-band installs, version drift after a `bundle update`) are
|
|
233
|
+
# silently dropped so only gems the project actually declares contribute RBS.
|
|
260
234
|
locked = LockfileResolver.locked_gems(
|
|
261
235
|
lockfile_path: bundler_lockfile,
|
|
262
236
|
project_root: root,
|
|
@@ -268,19 +242,19 @@ module Rigor
|
|
|
268
242
|
auto_detect: bundler_auto_detect,
|
|
269
243
|
locked_gems: locked.empty? ? nil : locked
|
|
270
244
|
).map(&:to_s)
|
|
271
|
-
#
|
|
272
|
-
#
|
|
273
|
-
#
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
#
|
|
278
|
-
#
|
|
279
|
-
# `
|
|
280
|
-
#
|
|
281
|
-
# (`
|
|
282
|
-
#
|
|
283
|
-
# double-declare against rigor's bundled RBS (the
|
|
245
|
+
# ADR-82 WD9 — the resolved bundle root, so the missing-gem constant index reads each RBS-less gem's
|
|
246
|
+
# entry file from the TARGET's bundle (not rigor's own — see `MissingGemConstantIndex`). Resolved
|
|
247
|
+
# once here; passed through to the lazy index build.
|
|
248
|
+
bundle_root = BundleSigDiscovery.resolve_bundle_path(
|
|
249
|
+
bundle_path: bundler_bundle_path, project_root: root, auto_detect: bundler_auto_detect
|
|
250
|
+
)&.to_s
|
|
251
|
+
# O4 Layer 3 slice 2 — when `rbs collection install` has been run for the target project, parse the
|
|
252
|
+
# resulting `rbs_collection.lock.yaml` and feed each gem's `<collection_path>/<name>/<version>/`
|
|
253
|
+
# directory into `signature_paths:`. Stdlib-typed entries are skipped (already covered by
|
|
254
|
+
# `DEFAULT_LIBRARIES`), as are gems whose RBS rigor already loads from another source —
|
|
255
|
+
# stdlib-extracted default gems (`cgi`, `logger`, …, shipped by the collection under a `git` source)
|
|
256
|
+
# and the `data/vendored_gem_sigs/` bundle (`redis`, `nokogiri`, `pg`, …). `skip_gem_names:` passes
|
|
257
|
+
# both sets so the collection copy doesn't double-declare against rigor's bundled RBS (the
|
|
284
258
|
# `RBS::DuplicatedDeclarationError` hazard).
|
|
285
259
|
merged_libraries = (DEFAULT_LIBRARIES + libraries.map(&:to_s)).uniq
|
|
286
260
|
skip_gem_names = merged_libraries + RbsLoader.vendored_gem_names
|
|
@@ -290,48 +264,33 @@ module Rigor
|
|
|
290
264
|
auto_detect: rbs_collection_auto_detect,
|
|
291
265
|
skip_gem_names: skip_gem_names
|
|
292
266
|
).map(&:to_s)
|
|
293
|
-
# ADR-25 — RBS signature directories contributed by loaded
|
|
294
|
-
#
|
|
295
|
-
#
|
|
296
|
-
#
|
|
297
|
-
# `signature_paths:` and above the opportunistic bundle /
|
|
298
|
-
# collection discovery. A duplicate-declaration conflict
|
|
299
|
-
# degrades through the same O7 failure-memo path.
|
|
267
|
+
# ADR-25 — RBS signature directories contributed by loaded plugins via their manifest
|
|
268
|
+
# `signature_paths:`. Resolved to absolute dirs by `Plugin::Base#signature_paths`; additive, ranked
|
|
269
|
+
# below the user's explicit `signature_paths:` and above the opportunistic bundle / collection
|
|
270
|
+
# discovery. A duplicate-declaration conflict degrades through the same O7 failure-memo path.
|
|
300
271
|
plugin_sig_paths = plugin_registry ? plugin_registry.signature_paths.map(&:to_s) : []
|
|
301
|
-
# ADR-72 — Gemfile.lock-gated bundled RBS overlays. For each
|
|
302
|
-
#
|
|
303
|
-
# (
|
|
304
|
-
#
|
|
305
|
-
#
|
|
306
|
-
#
|
|
307
|
-
#
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
# the env cache descriptor digests them for free.
|
|
312
|
-
overlay_paths = gem_overlay_paths(
|
|
313
|
-
locked: locked, default_libraries: merged_libraries,
|
|
314
|
-
bundle_sig_paths: gem_sig_paths, rbs_collection_paths: collection_paths,
|
|
315
|
-
plugin_registry: plugin_registry
|
|
272
|
+
# ADR-72 — Gemfile.lock-gated bundled RBS overlays. For each locked gem that ships no RBS through any
|
|
273
|
+
# resolution path (`:missing`) and has a Rigor-bundled overlay, load that overlay so its core-class
|
|
274
|
+
# extensions resolve (e.g. `Integer#minutes` on a Rails project) — turning a systematic false
|
|
275
|
+
# `call.undefined-method` into a no-op while a project WITHOUT the gem still sees the genuine
|
|
276
|
+
# diagnostic. Appended last so any RBS the project already supplies wins, and skipped for a gem whose
|
|
277
|
+
# opt-in plugin twin is loaded (no duplicate declaration). The paths ride in
|
|
278
|
+
# `loader_signature_paths`, so the env cache descriptor digests them for free.
|
|
279
|
+
missing_gems, overlay_paths = missing_gems_and_overlay_paths(
|
|
280
|
+
locked: locked, default_libraries: merged_libraries, bundle_sig_paths: gem_sig_paths,
|
|
281
|
+
rbs_collection_paths: collection_paths, plugin_registry: plugin_registry
|
|
316
282
|
)
|
|
317
283
|
loader_signature_paths = resolved_paths + plugin_sig_paths + gem_sig_paths +
|
|
318
284
|
collection_paths + overlay_paths
|
|
319
|
-
# ADR-32 WD4 + WD5 — invoke each loaded plugin's
|
|
320
|
-
# `
|
|
321
|
-
#
|
|
322
|
-
#
|
|
323
|
-
# `rigor-rbs-inline`) is responsible for its own
|
|
324
|
-
# fail-soft on parse errors per WD6; this loop only
|
|
325
|
-
# filters `nil` returns.
|
|
285
|
+
# ADR-32 WD4 + WD5 — invoke each loaded plugin's `source_rbs_synthesizer` once per project source
|
|
286
|
+
# file and collect non-nil `[filename, rbs_source]` pairs. The synthesizer-emitting plugin (currently
|
|
287
|
+
# only `rigor-rbs-inline`) is responsible for its own fail-soft on parse errors per WD6; this loop
|
|
288
|
+
# only filters `nil` returns.
|
|
326
289
|
#
|
|
327
|
-
# When a `cache_store` is supplied, each synthesizer
|
|
328
|
-
#
|
|
329
|
-
#
|
|
330
|
-
#
|
|
331
|
-
# source skips the rbs-inline parse cost. The empty
|
|
332
|
-
# string is the sentinel for "no contribution" so the
|
|
333
|
-
# Store (which treats `nil` as cache miss) can persist
|
|
334
|
-
# the no-contribution decision too.
|
|
290
|
+
# When a `cache_store` is supplied, each synthesizer invocation is memoised per `(file path + content
|
|
291
|
+
# SHA, plugin id + version + config_hash)` — WD5's cache key — so a second run with unchanged source
|
|
292
|
+
# skips the rbs-inline parse cost. The empty string is the sentinel for "no contribution" so the
|
|
293
|
+
# Store (which treats `nil` as cache miss) can persist the no-contribution decision too.
|
|
335
294
|
virtual_rbs = collect_virtual_rbs(plugin_registry, source_files, cache_store,
|
|
336
295
|
source_rbs_synthesis_reporter)
|
|
337
296
|
loader = RbsLoader.new(
|
|
@@ -340,15 +299,11 @@ module Rigor
|
|
|
340
299
|
cache_store: cache_store,
|
|
341
300
|
virtual_rbs: virtual_rbs
|
|
342
301
|
)
|
|
343
|
-
# ADR-20 slice 2c + 2e — seed hkt_registry with the
|
|
344
|
-
#
|
|
345
|
-
#
|
|
346
|
-
#
|
|
347
|
-
# (
|
|
348
|
-
# pay the eager env-build cost up front. URI
|
|
349
|
-
# collisions let the user-authored overlay win over
|
|
350
|
-
# the bundled builtin (last-write-wins per ADR-20
|
|
351
|
-
# OQ3 tentative).
|
|
302
|
+
# ADR-20 slice 2c + 2e — seed hkt_registry with the bundled builtins. The Environment's
|
|
303
|
+
# `#hkt_registry` getter then LAZILY merges in the RBS env scan on first call so fast paths that
|
|
304
|
+
# don't consult HKT (e.g. `rigor check --cache-stats --no-stats`) don't pay the eager env-build cost
|
|
305
|
+
# up front. URI collisions let the user-authored overlay win over the bundled builtin
|
|
306
|
+
# (last-write-wins per ADR-20 OQ3 tentative).
|
|
352
307
|
new(
|
|
353
308
|
rbs_loader: loader,
|
|
354
309
|
plugin_registry: plugin_registry,
|
|
@@ -358,7 +313,9 @@ module Rigor
|
|
|
358
313
|
source_rbs_synthesis_reporter: source_rbs_synthesis_reporter,
|
|
359
314
|
synthetic_method_index: synthetic_method_index,
|
|
360
315
|
project_patched_methods: project_patched_methods,
|
|
361
|
-
hkt_registry: Builtins::HktBuiltins.registry
|
|
316
|
+
hkt_registry: Builtins::HktBuiltins.registry,
|
|
317
|
+
missing_rbs_gems: missing_gems,
|
|
318
|
+
missing_rbs_bundle_path: bundle_root
|
|
362
319
|
)
|
|
363
320
|
end
|
|
364
321
|
# rubocop:enable Metrics/MethodLength, Metrics/ParameterLists
|
|
@@ -370,51 +327,48 @@ module Rigor
|
|
|
370
327
|
sig.directory? ? [sig] : []
|
|
371
328
|
end
|
|
372
329
|
|
|
373
|
-
#
|
|
374
|
-
#
|
|
375
|
-
#
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
rbs_collection_paths:, plugin_registry:)
|
|
382
|
-
return [] if locked.empty?
|
|
383
|
-
|
|
384
|
-
missing = RbsCoverageReport.classify(
|
|
330
|
+
# The `:missing` classification (locked gems with no RBS through any resolution path), computed once
|
|
331
|
+
# and consumed twice: as `[gem_name, version]` pairs for the ADR-82 WD9 constant-ownership index, and
|
|
332
|
+
# as the eligible-gem set for the ADR-72 overlay resolution. Returns `[pairs, overlay_paths]`.
|
|
333
|
+
def missing_gems_and_overlay_paths(locked:, default_libraries:, bundle_sig_paths:,
|
|
334
|
+
rbs_collection_paths:, plugin_registry:)
|
|
335
|
+
return [[], []] if locked.empty?
|
|
336
|
+
|
|
337
|
+
rows = RbsCoverageReport.classify(
|
|
385
338
|
locked_gems: locked, default_libraries: default_libraries,
|
|
386
339
|
bundle_sig_paths: bundle_sig_paths, rbs_collection_paths: rbs_collection_paths
|
|
387
|
-
).select { |row| row.source == :missing }
|
|
340
|
+
).select { |row| row.source == :missing }
|
|
341
|
+
overlays = gem_overlay_paths(missing_gem_names: rows.map(&:gem_name), plugin_registry: plugin_registry)
|
|
342
|
+
[rows.map { |row| [row.gem_name, row.version] }, overlays]
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
# ADR-72 — resolve the bundled RBS overlay directories to load for this project. A gem is eligible when
|
|
346
|
+
# it is classified `:missing` (see {missing_rbs_gem_rows}) and its conflicting opt-in plugin (if any)
|
|
347
|
+
# is not loaded. Returns `[Pathname]`, deterministically ordered, or `[]` when no eligible gem.
|
|
348
|
+
def gem_overlay_paths(missing_gem_names:, plugin_registry:)
|
|
349
|
+
return [] if missing_gem_names.empty?
|
|
388
350
|
|
|
389
351
|
loaded_ids = plugin_registry ? plugin_registry.ids.to_set : Set.new
|
|
390
|
-
eligible =
|
|
352
|
+
eligible = missing_gem_names.reject do |gem_name|
|
|
391
353
|
plugin_id = GEM_OVERLAY_PLUGIN_IDS[gem_name]
|
|
392
354
|
plugin_id && loaded_ids.include?(plugin_id)
|
|
393
355
|
end.sort
|
|
394
356
|
RbsLoader.gem_overlay_sig_paths(eligible)
|
|
395
357
|
end
|
|
396
358
|
|
|
397
|
-
# ADR-32 WD4 + WD5 — for each project source file, invoke
|
|
398
|
-
#
|
|
399
|
-
#
|
|
400
|
-
# rbs_source], ...]`; the loader threads it through to
|
|
401
|
-
# `RbsLoader.new(virtual_rbs: ...)`.
|
|
359
|
+
# ADR-32 WD4 + WD5 — for each project source file, invoke every plugin-registered synthesizer once and
|
|
360
|
+
# collect non-nil returns. The returned array is `[[virtual_filename, rbs_source], ...]`; the loader
|
|
361
|
+
# threads it through to `RbsLoader.new(virtual_rbs: ...)`.
|
|
402
362
|
#
|
|
403
|
-
# `virtual_filename` is the source file path prefixed with
|
|
404
|
-
# the plugin
|
|
405
|
-
# contributing plugin in their diagnostic location string.
|
|
363
|
+
# `virtual_filename` is the source file path prefixed with the plugin id so RBS parse errors point back
|
|
364
|
+
# to the contributing plugin in their diagnostic location string.
|
|
406
365
|
#
|
|
407
|
-
# When no plugin declares a synthesizer (the common case),
|
|
408
|
-
#
|
|
409
|
-
# this method short-circuits to `[]` without walking the
|
|
410
|
-
# file list.
|
|
366
|
+
# When no plugin declares a synthesizer (the common case), the registry's `source_rbs_synthesizers` is
|
|
367
|
+
# empty and this method short-circuits to `[]` without walking the file list.
|
|
411
368
|
#
|
|
412
|
-
# WD5 — when `cache_store` is supplied, each (file, plugin)
|
|
413
|
-
#
|
|
414
|
-
#
|
|
415
|
-
# plugin's `PluginEntry` (id + version + config_hash) so a
|
|
416
|
-
# config change or content change invalidates the entry
|
|
417
|
-
# automatically.
|
|
369
|
+
# WD5 — when `cache_store` is supplied, each (file, plugin) synthesizer call is memoised through
|
|
370
|
+
# `Cache::Store`. The cache key composes the file's content SHA with the plugin's `PluginEntry` (id +
|
|
371
|
+
# version + config_hash) so a config change or content change invalidates the entry automatically.
|
|
418
372
|
def collect_virtual_rbs(plugin_registry, source_files, cache_store, reporter)
|
|
419
373
|
return [] if plugin_registry.nil?
|
|
420
374
|
|
|
@@ -436,14 +390,10 @@ module Rigor
|
|
|
436
390
|
result
|
|
437
391
|
end
|
|
438
392
|
|
|
439
|
-
# ADR-32 WD5 — cache wrapper around a single (plugin,
|
|
440
|
-
#
|
|
441
|
-
#
|
|
442
|
-
#
|
|
443
|
-
# tuples are stored as the canonical
|
|
444
|
-
# `[:error, message_string]` Array so the same wrapper
|
|
445
|
-
# short-circuits subsequent runs against unchanged broken
|
|
446
|
-
# input.
|
|
393
|
+
# ADR-32 WD5 — cache wrapper around a single (plugin, file) invocation. The cache stores the empty
|
|
394
|
+
# string `""` as the "no contribution" sentinel because `Cache::Store` treats `nil` as a cache miss.
|
|
395
|
+
# Error tuples are stored as the canonical `[:error, message_string]` Array so the same wrapper
|
|
396
|
+
# short-circuits subsequent runs against unchanged broken input.
|
|
447
397
|
def synthesizer_output_for(plugin, callable, path, cache_store)
|
|
448
398
|
return invoke_synthesizer_safely(callable, path) if cache_store.nil?
|
|
449
399
|
return invoke_synthesizer_safely(callable, path) unless File.file?(path)
|
|
@@ -456,17 +406,14 @@ module Rigor
|
|
|
456
406
|
) { invoke_synthesizer_safely(callable, path) || "" }
|
|
457
407
|
end
|
|
458
408
|
|
|
459
|
-
# ADR-32 WD6 — route a synthesizer return value through
|
|
460
|
-
#
|
|
461
|
-
#
|
|
462
|
-
# admits three return shapes:
|
|
409
|
+
# ADR-32 WD6 — route a synthesizer return value through the per-run failure reporter. The
|
|
410
|
+
# synthesizer's contract (declared in
|
|
411
|
+
# `plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb`) admits three return shapes:
|
|
463
412
|
# - `String` (non-empty) → successful RBS source
|
|
464
413
|
# - `nil` / `""` → no contribution
|
|
465
414
|
# - `[:error, message]` → parse failed
|
|
466
|
-
# The error tuple is converted into a reporter entry +
|
|
467
|
-
#
|
|
468
|
-
# continues. Reporter is `nil` for callers that don't care
|
|
469
|
-
# (legacy Environment.new, tests).
|
|
415
|
+
# The error tuple is converted into a reporter entry + treated as "no contribution" so the analysis
|
|
416
|
+
# pipeline continues. Reporter is `nil` for callers that don't care (legacy Environment.new, tests).
|
|
470
417
|
def interpret_synthesizer_outcome(outcome, plugin, path, reporter)
|
|
471
418
|
return outcome unless outcome.is_a?(Array) && outcome[0] == :error
|
|
472
419
|
|
|
@@ -495,8 +442,7 @@ module Rigor
|
|
|
495
442
|
def synthesizer_input_digest(path)
|
|
496
443
|
Digest::SHA256.hexdigest(File.binread(path))
|
|
497
444
|
rescue ::SystemCallError
|
|
498
|
-
# Unreadable file → key on the path alone; the
|
|
499
|
-
# synthesizer's File.file?/File.read will see the same
|
|
445
|
+
# Unreadable file → key on the path alone; the synthesizer's File.file?/File.read will see the same
|
|
500
446
|
# failure and return nil.
|
|
501
447
|
Digest::SHA256.hexdigest(path.to_s)
|
|
502
448
|
end
|
|
@@ -504,23 +450,19 @@ module Rigor
|
|
|
504
450
|
def invoke_synthesizer_safely(callable, path)
|
|
505
451
|
callable.call(path.to_s)
|
|
506
452
|
rescue StandardError
|
|
507
|
-
# WD6 fail-soft — a synthesizer that raises does NOT crash
|
|
508
|
-
#
|
|
509
|
-
# the
|
|
510
|
-
# an unhandled raise is swallowed silently; the
|
|
511
|
-
# unexamined-raise channel is deliberately silent per WD6.
|
|
453
|
+
# WD6 fail-soft — a synthesizer that raises does NOT crash analysis. Unlike the `[:error, msg]`
|
|
454
|
+
# return path (which the runner surfaces as `source-rbs-synthesis-failed`), an unhandled raise is
|
|
455
|
+
# swallowed silently; the unexamined-raise channel is deliberately silent per WD6.
|
|
512
456
|
nil
|
|
513
457
|
end
|
|
514
458
|
end
|
|
515
459
|
|
|
516
|
-
# Resolves a constant name to a Rigor::Type::Nominal (the *instance*
|
|
517
|
-
#
|
|
518
|
-
#
|
|
519
|
-
# the name is unknown to both.
|
|
460
|
+
# Resolves a constant name to a Rigor::Type::Nominal (the *instance* type carrier). Consults the static
|
|
461
|
+
# class registry first (cheap, hardcoded), then falls back to the RBS loader. Returns nil when the name
|
|
462
|
+
# is unknown to both.
|
|
520
463
|
#
|
|
521
|
-
# NOTE: This is the construction helper for "an instance of class
|
|
522
|
-
#
|
|
523
|
-
# constant), use {#singleton_for_name} instead.
|
|
464
|
+
# NOTE: This is the construction helper for "an instance of class `Foo`". For "the class object `Foo`
|
|
465
|
+
# itself" (the value of the constant), use {#singleton_for_name} instead.
|
|
524
466
|
def nominal_for_name(name)
|
|
525
467
|
registered = class_registry.nominal_for_name(name)
|
|
526
468
|
return registered if registered
|
|
@@ -528,36 +470,29 @@ module Rigor
|
|
|
528
470
|
class_known_in_rbs?(name) ? Type::Combinator.nominal_of(name.to_s) : nil
|
|
529
471
|
end
|
|
530
472
|
|
|
531
|
-
# Resolves a constant name to a Rigor::Type::Singleton (the *class
|
|
532
|
-
# object
|
|
533
|
-
#
|
|
534
|
-
# corresponding Rigor construction helper.
|
|
473
|
+
# Resolves a constant name to a Rigor::Type::Singleton (the *class object* carrier). The expression `Foo`
|
|
474
|
+
# evaluates to the class object, whose RBS type is `singleton(Foo)` -- this method is the corresponding
|
|
475
|
+
# Rigor construction helper.
|
|
535
476
|
#
|
|
536
|
-
# The lookup uses the same registry/RBS chain as {#nominal_for_name}
|
|
537
|
-
#
|
|
477
|
+
# The lookup uses the same registry/RBS chain as {#nominal_for_name} so a class is either known to both
|
|
478
|
+
# queries or to neither.
|
|
538
479
|
def singleton_for_name(name)
|
|
539
480
|
return nil unless class_known?(name)
|
|
540
481
|
|
|
541
482
|
Type::Combinator.singleton_of(name.to_s)
|
|
542
483
|
end
|
|
543
484
|
|
|
544
|
-
# Slice A constant-value lookup. Returns the translated
|
|
545
|
-
# `Rigor::
|
|
546
|
-
#
|
|
547
|
-
#
|
|
548
|
-
#
|
|
549
|
-
#
|
|
550
|
-
# only resolves names that name a class or module. Callers
|
|
551
|
-
# that need to type a `Prism::ConstantReadNode`/
|
|
552
|
-
# `Prism::ConstantPathNode` MUST consult {#singleton_for_name}
|
|
553
|
-
# first and fall through to this query when the constant is
|
|
554
|
-
# not a class.
|
|
485
|
+
# Slice A constant-value lookup. Returns the translated `Rigor::Type` for an RBS-declared **non-class**
|
|
486
|
+
# constant (`Rigor::Analysis::FactStore::BUCKETS: Array[Symbol]`, `Rigor::Configuration::DEFAULT_PATH:
|
|
487
|
+
# String`, ...) or `nil` when no RBS constant declaration covers `name`. This is the value-bearing
|
|
488
|
+
# counterpart of {#singleton_for_name}, which only resolves names that name a class or module. Callers
|
|
489
|
+
# that need to type a `Prism::ConstantReadNode`/ `Prism::ConstantPathNode` MUST consult
|
|
490
|
+
# {#singleton_for_name} first and fall through to this query when the constant is not a class.
|
|
555
491
|
def constant_for_name(name)
|
|
556
492
|
return nil if rbs_loader.nil?
|
|
557
493
|
|
|
558
|
-
# Pure function of `name` for this Environment's lifetime — the
|
|
559
|
-
#
|
|
560
|
-
# memoise across the lexical-candidate ladder's heavy name reuse.
|
|
494
|
+
# Pure function of `name` for this Environment's lifetime — the refinement table and the RBS constant
|
|
495
|
+
# table are both fixed — so memoise across the lexical-candidate ladder's heavy name reuse.
|
|
561
496
|
key = name.to_s
|
|
562
497
|
@constant_type_cache.fetch(key) do
|
|
563
498
|
Builtins::PredefinedConstantRefinements.lookup(key) ||
|
|
@@ -565,50 +500,39 @@ module Rigor
|
|
|
565
500
|
end
|
|
566
501
|
end
|
|
567
502
|
|
|
568
|
-
# Returns true when the constant name is known to either the static
|
|
569
|
-
#
|
|
570
|
-
# presence check without materialising a type carrier.
|
|
503
|
+
# Returns true when the constant name is known to either the static registry or the RBS loader. Useful
|
|
504
|
+
# for callers that only need a presence check without materialising a type carrier.
|
|
571
505
|
def class_known?(name)
|
|
572
506
|
return true if class_registry.nominal_for_name(name)
|
|
573
507
|
return true if class_known_in_rbs?(name)
|
|
574
508
|
|
|
575
|
-
# ADR-36 nested-class emission — a variant subclass the
|
|
576
|
-
#
|
|
577
|
-
#
|
|
578
|
-
# class for resolution purposes even though no RBS / source
|
|
579
|
-
# declares it.
|
|
509
|
+
# ADR-36 nested-class emission — a variant subclass the substrate synthesised (e.g. `Shape::Circle`
|
|
510
|
+
# from a `variants do variant Circle, Float end` block) is a real class for resolution purposes even
|
|
511
|
+
# though no RBS / source declares it.
|
|
580
512
|
@synthetic_method_index&.knows_class?(name) || false
|
|
581
513
|
end
|
|
582
514
|
|
|
583
|
-
# ADR-15 Phase 2b — returns the loader's read-only,
|
|
584
|
-
#
|
|
585
|
-
#
|
|
586
|
-
# access; subsequent calls return the same instance.
|
|
587
|
-
# Returns `nil` when the environment carries no RBS
|
|
588
|
-
# loader (test-only `Environment.new` without
|
|
515
|
+
# ADR-15 Phase 2b — returns the loader's read-only, `Ractor.shareable?` query surface as a frozen
|
|
516
|
+
# {Environment::Reflection}. Built lazily on first access; subsequent calls return the same instance.
|
|
517
|
+
# Returns `nil` when the environment carries no RBS loader (test-only `Environment.new` without
|
|
589
518
|
# `rbs_loader:`).
|
|
590
519
|
def reflection
|
|
591
520
|
@rbs_loader&.reflection
|
|
592
521
|
end
|
|
593
522
|
|
|
594
|
-
# Returns true when the RBS environment carries the named
|
|
595
|
-
#
|
|
596
|
-
# `
|
|
597
|
-
#
|
|
598
|
-
# unresolved method calls through the `Nominal[Object]`
|
|
599
|
-
# fallback — every concrete includer of M honours Kernel /
|
|
600
|
-
# Object instance methods through its own ancestor chain.
|
|
523
|
+
# Returns true when the RBS environment carries the named declaration as a Module (not a Class). Used by
|
|
524
|
+
# the `user_class_fallback_receiver` tier to detect a module-mixin receiver (e.g. `PP::ObjectMixin`) so
|
|
525
|
+
# the dispatcher can route unresolved method calls through the `Nominal[Object]` fallback — every
|
|
526
|
+
# concrete includer of M honours Kernel / Object instance methods through its own ancestor chain.
|
|
601
527
|
def rbs_module?(name)
|
|
602
528
|
return false unless rbs_loader
|
|
603
529
|
|
|
604
530
|
rbs_loader.rbs_module?(name)
|
|
605
531
|
end
|
|
606
532
|
|
|
607
|
-
# Compares two class/module names using analyzer-owned class data.
|
|
608
|
-
#
|
|
609
|
-
#
|
|
610
|
-
# loader handles project/stdlib classes without relying on host Ruby
|
|
611
|
-
# constants being loaded.
|
|
533
|
+
# Compares two class/module names using analyzer-owned class data. Returns `:equal`, `:subclass`,
|
|
534
|
+
# `:superclass`, `:disjoint`, or `:unknown`. The static registry handles built-ins cheaply; the RBS
|
|
535
|
+
# loader handles project/stdlib classes without relying on host Ruby constants being loaded.
|
|
612
536
|
def class_ordering(lhs, rhs)
|
|
613
537
|
lhs = normalize_class_name(lhs)
|
|
614
538
|
rhs = normalize_class_name(rhs)
|
|
@@ -634,14 +558,11 @@ module Rigor
|
|
|
634
558
|
name.to_s.delete_prefix("::")
|
|
635
559
|
end
|
|
636
560
|
|
|
637
|
-
# ADR-13 slice 3b — composes the per-run plugin-supplied
|
|
638
|
-
# {Rigor::TypeNode::
|
|
639
|
-
# {Rigor::
|
|
640
|
-
#
|
|
641
|
-
#
|
|
642
|
-
# `nil` when no plugin contributes a type-node resolver so
|
|
643
|
-
# the parser short-circuits the chain consultation and
|
|
644
|
-
# behaves bit-for-bit like the v0.1.0 → v0.1.3 default.
|
|
561
|
+
# ADR-13 slice 3b — composes the per-run plugin-supplied {Rigor::TypeNode::ResolverChain} into a single
|
|
562
|
+
# {Rigor::TypeNode::NameScope} that the RBS::Extended directive parser threads down to the
|
|
563
|
+
# {Rigor::Builtins::ImportedRefinements::Resolver}. Returns `nil` when no plugin contributes a type-node
|
|
564
|
+
# resolver so the parser short-circuits the chain consultation and behaves bit-for-bit like the v0.1.0 →
|
|
565
|
+
# v0.1.3 default.
|
|
645
566
|
def build_name_scope
|
|
646
567
|
return nil if @plugin_registry.nil? || @plugin_registry.empty?
|
|
647
568
|
|