rigortype 0.3.8 → 0.3.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/capability_roles/capability_roles.rbs +36 -0
- data/data/gem_overlay/activesupport/core_ext.rbs +109 -13
- data/docs/handbook/02-everyday-types.md +17 -14
- data/docs/handbook/03-narrowing.md +37 -4
- data/docs/handbook/05-methods-and-blocks.md +1 -1
- data/docs/handbook/06-classes.md +2 -2
- data/docs/handbook/07-rbs-and-extended.md +14 -1
- data/docs/handbook/11-sig-gen.md +72 -1
- data/docs/handbook/README.md +1 -1
- data/docs/handbook/appendix-elixir.md +2 -2
- data/docs/handbook/appendix-go.md +2 -2
- data/docs/handbook/appendix-java-csharp.md +2 -2
- data/docs/handbook/appendix-mypy.md +2 -2
- data/docs/handbook/appendix-phpstan.md +1 -1
- data/docs/handbook/appendix-rust.md +1 -1
- data/docs/handbook/appendix-type-theory.md +4 -4
- data/docs/handbook/appendix-typescript.md +1 -1
- data/docs/llms.txt +2 -0
- data/docs/manual/02-cli-reference.md +32 -4
- data/docs/manual/03-configuration.md +11 -0
- data/docs/manual/04-diagnostics.md +11 -0
- data/docs/manual/07-plugins.md +15 -5
- data/docs/manual/08-skills.md +23 -2
- data/docs/manual/11-ci.md +9 -0
- data/docs/manual/15-type-protection-coverage.md +8 -0
- data/docs/manual/16-rbs-extended-annotations.md +6 -1
- data/docs/manual/18-removing-dead-code.md +10 -8
- data/docs/manual/plugins/rigor-actionpack.md +18 -0
- data/docs/manual/plugins/rigor-activerecord.md +28 -0
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +32 -2
- data/docs/manual/plugins/rigor-rbs-inline.md +42 -1
- data/lib/rigor/analysis/baseline.rb +2 -2
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/dead_version_guard_arms.rb +1 -5
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +10 -2
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +15 -6
- data/lib/rigor/analysis/check_rules/rule_ids.rb +1 -1
- data/lib/rigor/analysis/check_rules/rule_walk.rb +39 -4
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +1 -1
- data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +0 -1
- data/lib/rigor/analysis/check_rules.rb +200 -32
- data/lib/rigor/analysis/crash_signature.rb +8 -24
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +1 -1
- data/lib/rigor/analysis/dependency_source_inference/builder.rb +0 -2
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +0 -2
- data/lib/rigor/analysis/dependency_source_inference/index.rb +5 -5
- data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +1 -2
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +4 -4
- data/lib/rigor/analysis/effects_cache_probe.rb +3 -4
- data/lib/rigor/analysis/erb_template_detector.rb +1 -2
- data/lib/rigor/analysis/fact_store.rb +6 -1
- data/lib/rigor/analysis/incremental.rb +16 -0
- data/lib/rigor/analysis/incremental_session.rb +81 -22
- data/lib/rigor/analysis/plugin_fact_fingerprint.rb +0 -1
- data/lib/rigor/analysis/reachability/graph.rb +3 -5
- data/lib/rigor/analysis/reachability/plugin_roots.rb +6 -5
- data/lib/rigor/analysis/reachability/project_files.rb +2 -2
- data/lib/rigor/analysis/reachability/scan.rb +5 -5
- data/lib/rigor/analysis/reachability/scan_cache.rb +2 -2
- data/lib/rigor/analysis/reachability/signature_scan.rb +2 -2
- data/lib/rigor/analysis/result.rb +1 -3
- data/lib/rigor/analysis/rule_catalog.rb +4 -1
- data/lib/rigor/analysis/run_cache_key.rb +1 -1
- data/lib/rigor/analysis/run_cache_probe.rb +3 -5
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +6 -8
- data/lib/rigor/analysis/runner/declaration_position.rb +1 -2
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +177 -26
- data/lib/rigor/analysis/runner/effect_annotation_residual_pass.rb +2 -3
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +9 -10
- data/lib/rigor/analysis/runner/pool_coordinator.rb +256 -88
- data/lib/rigor/analysis/runner/project_pre_passes.rb +12 -6
- data/lib/rigor/analysis/runner/run_snapshots.rb +6 -1
- data/lib/rigor/analysis/runner.rb +133 -35
- data/lib/rigor/analysis/worker_session.rb +9 -10
- data/lib/rigor/bleeding_edge.rb +12 -24
- data/lib/rigor/builtins/hkt_builtins.rb +2 -2
- data/lib/rigor/builtins/imported_refinements.rb +155 -21
- data/lib/rigor/builtins/predefined_constant_refinements.rb +5 -7
- data/lib/rigor/builtins/regex_refinement.rb +4 -4
- data/lib/rigor/builtins/static_return_refinements.rb +5 -6
- data/lib/rigor/cache/annotation_location.rb +2 -4
- data/lib/rigor/cache/descriptor.rb +58 -20
- data/lib/rigor/cache/engine_source.rb +4 -4
- data/lib/rigor/cache/file_digest.rb +9 -1
- data/lib/rigor/cache/incremental_snapshot.rb +40 -6
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +0 -3
- data/lib/rigor/cache/rbs_class_type_param_names.rb +0 -3
- data/lib/rigor/cache/rbs_constant_table.rb +0 -3
- data/lib/rigor/cache/rbs_descriptor.rb +79 -11
- data/lib/rigor/cache/rbs_environment.rb +8 -4
- data/lib/rigor/cache/rbs_known_class_names.rb +0 -3
- data/lib/rigor/cache/store.rb +77 -32
- data/lib/rigor/cli/annotate_command.rb +5 -6
- data/lib/rigor/cli/check_command.rb +57 -10
- data/lib/rigor/cli/check_invocation.rb +6 -11
- data/lib/rigor/cli/check_runner_factory.rb +1 -5
- data/lib/rigor/cli/coverage_command.rb +1 -1
- data/lib/rigor/cli/coverage_mutation.rb +12 -3
- data/lib/rigor/cli/coverage_scan.rb +1 -5
- data/lib/rigor/cli/diff_command.rb +1 -1
- data/lib/rigor/cli/doc_links.rb +3 -3
- data/lib/rigor/cli/docs_command.rb +2 -2
- data/lib/rigor/cli/doctor_command.rb +85 -38
- data/lib/rigor/cli/effects_command.rb +2 -2
- data/lib/rigor/cli/effects_diff_renderer.rb +3 -3
- data/lib/rigor/cli/effects_snapshot_command.rb +1 -1
- data/lib/rigor/cli/explain_command.rb +34 -1
- data/lib/rigor/cli/fused_protection_report.rb +7 -1
- data/lib/rigor/cli/lsp_command.rb +1 -1
- data/lib/rigor/cli/mcp_command.rb +1 -1
- data/lib/rigor/cli/measurement_integrity_warning.rb +4 -5
- data/lib/rigor/cli/mutation_fork_scan.rb +6 -6
- data/lib/rigor/cli/mutation_protection_report.rb +7 -1
- data/lib/rigor/cli/plugin_command.rb +1 -1
- data/lib/rigor/cli/plugins_command.rb +2 -1
- data/lib/rigor/cli/prism_colorizer.rb +2 -2
- data/lib/rigor/cli/protection_fork_scan.rb +6 -6
- data/lib/rigor/cli/show_bleedingedge_command.rb +1 -1
- data/lib/rigor/cli/sig_gen_command.rb +2 -2
- data/lib/rigor/cli/skill_command.rb +1 -1
- data/lib/rigor/cli/skill_deep_probe.rb +4 -4
- data/lib/rigor/cli/skill_describe.rb +36 -35
- data/lib/rigor/cli/trace_command.rb +4 -4
- data/lib/rigor/cli/trace_renderer.rb +5 -6
- data/lib/rigor/cli/triage_command.rb +1 -1
- data/lib/rigor/cli/type_of_command.rb +10 -6
- data/lib/rigor/cli/type_scan_command.rb +4 -4
- data/lib/rigor/cli/unused_command.rb +11 -3
- data/lib/rigor/cli/upgrade_command.rb +1 -1
- data/lib/rigor/cli.rb +68 -6
- data/lib/rigor/config_audit.rb +30 -5
- data/lib/rigor/configuration/severity_profile.rb +6 -6
- data/lib/rigor/configuration.rb +43 -4
- data/lib/rigor/effects/attribution.rb +1 -3
- data/lib/rigor/effects/config_envelopes.rb +6 -8
- data/lib/rigor/effects/definition_lines.rb +25 -6
- data/lib/rigor/effects/effect_table.rb +0 -1
- data/lib/rigor/effects/entry_points.rb +0 -2
- data/lib/rigor/effects/envelope_check.rb +8 -8
- data/lib/rigor/effects/envelope_index.rb +5 -8
- data/lib/rigor/effects/framework_units.rb +4 -6
- data/lib/rigor/effects/identity.rb +4 -6
- data/lib/rigor/effects/inline_anchor.rb +7 -7
- data/lib/rigor/effects/label_intent.rb +3 -4
- data/lib/rigor/effects/liskov_check.rb +8 -8
- data/lib/rigor/effects/method_key.rb +1 -1
- data/lib/rigor/effects/plugin_facts.rb +4 -6
- data/lib/rigor/effects/propagator.rb +2 -3
- data/lib/rigor/effects/scanner.rb +1 -1
- data/lib/rigor/effects/signature_sources.rb +3 -5
- data/lib/rigor/effects/snapshot.rb +10 -10
- data/lib/rigor/effects/snapshot_diff.rb +1 -1
- data/lib/rigor/effects/unit_scan.rb +10 -10
- data/lib/rigor/effects/unknown_label_check.rb +3 -8
- data/lib/rigor/effects/unknown_label_report.rb +3 -4
- data/lib/rigor/environment/bundle_sig_discovery.rb +6 -6
- data/lib/rigor/environment/class_registry.rb +3 -1
- data/lib/rigor/environment/failure_slot.rb +2 -2
- data/lib/rigor/environment/installed_gem_set.rb +85 -0
- data/lib/rigor/environment/lockfile_resolver.rb +51 -4
- data/lib/rigor/environment/missing_gem_constant_index.rb +4 -4
- data/lib/rigor/environment/rbs_collection_discovery.rb +5 -5
- data/lib/rigor/environment/rbs_coverage_report.rb +5 -5
- data/lib/rigor/environment/rbs_hierarchy.rb +3 -1
- data/lib/rigor/environment/rbs_loader.rb +388 -59
- data/lib/rigor/environment.rb +105 -20
- data/lib/rigor/flow_contribution/merger.rb +0 -2
- data/lib/rigor/flow_contribution.rb +11 -13
- data/lib/rigor/inference/acceptance.rb +153 -8
- data/lib/rigor/inference/block_parameter_binder.rb +2 -3
- data/lib/rigor/inference/body_fixpoint.rb +5 -5
- data/lib/rigor/inference/budget_trace.rb +1 -5
- data/lib/rigor/inference/captured_locals.rb +2 -3
- data/lib/rigor/inference/closure_escape_analyzer.rb +2 -4
- data/lib/rigor/inference/coverage_scanner.rb +4 -6
- data/lib/rigor/inference/dynamic_origin.rb +1 -1
- data/lib/rigor/inference/element_read_widening.rb +168 -0
- data/lib/rigor/inference/expression_typer.rb +763 -143
- data/lib/rigor/inference/fork_map.rb +5 -7
- data/lib/rigor/inference/hkt_reducer.rb +2 -3
- data/lib/rigor/inference/hkt_registry.rb +4 -7
- data/lib/rigor/inference/index_write_widening.rb +1 -5
- data/lib/rigor/inference/macro_block_self_type.rb +1 -4
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +2 -9
- data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +305 -19
- data/lib/rigor/inference/method_dispatcher/data_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/json_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +7 -1
- data/lib/rigor/inference/method_dispatcher/math_folding.rb +41 -3
- data/lib/rigor/inference/method_dispatcher/method_folding.rb +2 -5
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +61 -47
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +82 -0
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +165 -31
- data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +25 -4
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +2 -8
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +1 -2
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +4 -5
- data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +85 -4
- data/lib/rigor/inference/method_dispatcher/time_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/universal_object_dispatch.rb +1 -2
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher.rb +12 -13
- data/lib/rigor/inference/method_parameter_binder.rb +4 -6
- data/lib/rigor/inference/multi_target_binder.rb +1 -3
- data/lib/rigor/inference/mutation_rejoin.rb +168 -0
- data/lib/rigor/inference/mutation_widening.rb +100 -51
- data/lib/rigor/inference/narrowing.rb +299 -46
- data/lib/rigor/inference/optimistic_origin.rb +1 -7
- data/lib/rigor/inference/origin_lookup.rb +2 -3
- data/lib/rigor/inference/parameter_inference_collector.rb +5 -6
- data/lib/rigor/inference/pre_eval_constants.rb +6 -5
- data/lib/rigor/inference/precision_scanner.rb +3 -4
- data/lib/rigor/inference/project_patched_methods.rb +2 -2
- data/lib/rigor/inference/project_patched_scanner.rb +3 -3
- data/lib/rigor/inference/protection_scanner.rb +1 -2
- data/lib/rigor/inference/range_constant.rb +57 -0
- data/lib/rigor/inference/rbs_type_translator.rb +49 -11
- data/lib/rigor/inference/receiver_alias.rb +3 -3
- data/lib/rigor/inference/refinement_mutation.rb +72 -0
- data/lib/rigor/inference/scope_indexer.rb +688 -151
- data/lib/rigor/inference/statement_evaluator.rb +221 -50
- data/lib/rigor/inference/string_mutation.rb +60 -0
- data/lib/rigor/inference/struct_fold_safety.rb +6 -7
- data/lib/rigor/inference/synthetic_method_index.rb +1 -2
- data/lib/rigor/inference/synthetic_method_scanner.rb +4 -6
- data/lib/rigor/inference/version_guard.rb +28 -21
- data/lib/rigor/inference/void_origin.rb +3 -3
- data/lib/rigor/inference/void_tail_summary.rb +2 -4
- data/lib/rigor/language_server/buffer_table.rb +4 -4
- data/lib/rigor/language_server/completion_provider.rb +1 -1
- data/lib/rigor/language_server/debouncer.rb +1 -1
- data/lib/rigor/language_server/diagnostic_publisher.rb +4 -4
- data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
- data/lib/rigor/language_server/folding_range_provider.rb +1 -1
- data/lib/rigor/language_server/hover_provider.rb +1 -1
- data/lib/rigor/language_server/hover_renderer.rb +2 -2
- data/lib/rigor/language_server/incremental_sync.rb +6 -6
- data/lib/rigor/language_server/project_context.rb +2 -5
- data/lib/rigor/language_server/publish_batcher.rb +2 -2
- data/lib/rigor/language_server/selection_range_provider.rb +2 -2
- data/lib/rigor/language_server/server.rb +9 -9
- data/lib/rigor/language_server/signature_help_provider.rb +1 -1
- data/lib/rigor/language_server/uri.rb +1 -1
- data/lib/rigor/plugin/base.rb +90 -21
- data/lib/rigor/plugin/bundled_catalog.rb +167 -0
- data/lib/rigor/plugin/effect_attribution.rb +7 -7
- data/lib/rigor/plugin/effect_entry_points.rb +3 -3
- data/lib/rigor/plugin/fact_store.rb +6 -6
- data/lib/rigor/plugin/io_boundary.rb +93 -8
- data/lib/rigor/plugin/isolation.rb +29 -6
- data/lib/rigor/plugin/loader.rb +31 -12
- data/lib/rigor/plugin/macro/heredoc_template.rb +1 -1
- data/lib/rigor/plugin/macro/trait_registry.rb +1 -1
- data/lib/rigor/plugin/manifest.rb +23 -1
- data/lib/rigor/plugin/registry.rb +42 -12
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +12 -1
- data/lib/rigor/plugin/trust_policy.rb +2 -4
- data/lib/rigor/plugin/type_node_resolver.rb +3 -3
- data/lib/rigor/plugin_gap_advisory.rb +96 -0
- data/lib/rigor/project_environment.rb +138 -0
- data/lib/rigor/protection/analysis_guard.rb +93 -14
- data/lib/rigor/protection/closure_kill_oracle.rb +67 -23
- data/lib/rigor/protection/dependency_closure.rb +5 -8
- data/lib/rigor/protection/diagnostic_oracle.rb +2 -2
- data/lib/rigor/protection/discovery_seed.rb +11 -11
- data/lib/rigor/protection/kill_signature.rb +2 -4
- data/lib/rigor/protection/measurement_integrity.rb +1 -3
- data/lib/rigor/protection/mutation_cache.rb +6 -9
- data/lib/rigor/protection/mutation_scanner.rb +12 -15
- data/lib/rigor/protection/mutator.rb +2 -1
- data/lib/rigor/protection/test_suite_oracle.rb +5 -5
- data/lib/rigor/rbs_extended/conformance_checker.rb +4 -3
- data/lib/rigor/rbs_extended/envelope_scanner.rb +4 -6
- data/lib/rigor/rbs_extended/reporter.rb +36 -10
- data/lib/rigor/rbs_extended.rb +61 -21
- data/lib/rigor/reflection/constant_path.rb +126 -0
- data/lib/rigor/reflection.rb +26 -10
- data/lib/rigor/runtime/jit.rb +6 -8
- data/lib/rigor/scope/discovery_index.rb +30 -0
- data/lib/rigor/scope.rb +203 -4
- data/lib/rigor/sig_gen/generator.rb +115 -22
- data/lib/rigor/sig_gen/layout_index.rb +3 -4
- data/lib/rigor/sig_gen/meta_class_shape.rb +3 -5
- data/lib/rigor/sig_gen/observation_collector.rb +17 -15
- data/lib/rigor/sig_gen/path_mapper.rb +4 -6
- data/lib/rigor/sig_gen/rbs_validity.rb +4 -4
- data/lib/rigor/sig_gen/renderer.rb +4 -5
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +111 -0
- data/lib/rigor/sig_gen/superclass_spelling.rb +27 -0
- data/lib/rigor/sig_gen/type_elaborator.rb +1 -3
- data/lib/rigor/sig_gen/writer.rb +23 -6
- data/lib/rigor/signature_path_audit.rb +153 -6
- data/lib/rigor/source/literals.rb +0 -23
- data/lib/rigor/source/node_children.rb +0 -2
- data/lib/rigor/source/node_locator.rb +5 -11
- data/lib/rigor/source/node_walker.rb +2 -5
- data/lib/rigor/triage/catalogue.rb +1 -3
- data/lib/rigor/triage.rb +3 -5
- data/lib/rigor/type/accepts_result.rb +24 -6
- data/lib/rigor/type/combinator.rb +68 -5
- data/lib/rigor/type/data_class.rb +2 -2
- data/lib/rigor/type/data_instance.rb +4 -4
- data/lib/rigor/type/float_range.rb +128 -0
- data/lib/rigor/type/hash_shape.rb +5 -5
- data/lib/rigor/type/integer_range.rb +13 -8
- data/lib/rigor/type/nominal.rb +8 -2
- data/lib/rigor/type/refined.rb +3 -3
- data/lib/rigor/type/struct_class.rb +3 -3
- data/lib/rigor/type/struct_instance.rb +4 -4
- data/lib/rigor/type.rb +1 -0
- data/lib/rigor/type_node/generic.rb +1 -1
- data/lib/rigor/type_node/range_literal.rb +25 -0
- data/lib/rigor/type_node/resolver_chain.rb +1 -1
- data/lib/rigor/type_node.rb +1 -0
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +0 -4
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +0 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +0 -2
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +1 -0
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +0 -4
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +3 -5
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +1 -4
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +1 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +33 -30
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +0 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -3
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +28 -2
- data/plugins/rigor-actionpack/sig/action_controller.rbs +71 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +0 -4
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +0 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +0 -2
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/recurring_scan.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +1 -0
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +3 -4
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +1 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +1 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +42 -7
- data/plugins/rigor-activerecord/sig/active_record/framework.rbs +123 -0
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +1 -0
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +9 -2
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +119 -14
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +1 -0
- data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +1 -0
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +9 -7
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +7 -3
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +1 -0
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +8 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +11 -7
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -11
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +9 -4
- data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +1 -0
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +0 -5
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +8 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +36 -4
- data/plugins/rigor-ffi-rzmq/lib/rigor/plugin/ffi_rzmq.rb +1 -0
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +8 -6
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +6 -3
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +1 -0
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +2 -1
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +0 -3
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +1 -0
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +0 -5
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/authorization_scan.rb +2 -2
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +0 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +0 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +1 -0
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +0 -12
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +1 -3
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +0 -1
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +1 -0
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/acronyms.rb +5 -5
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +1 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +3 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/grape_api_discoverer.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +9 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +2 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +1 -0
- data/plugins/rigor-railties/lib/rigor/plugin/railties.rb +1 -0
- data/plugins/rigor-rbnacl/lib/rigor/plugin/rbnacl.rb +13 -1
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +128 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +0 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +0 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +1 -5
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +2 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +1 -0
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +0 -3
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +1 -0
- data/plugins/rigor-sassc/lib/rigor/plugin/sassc.rb +1 -0
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +1 -9
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +1 -0
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +0 -4
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/effects.rb +1 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/schedule_scan.rb +1 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +0 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +0 -2
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +1 -0
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +1 -0
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +2 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +1 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +3 -9
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +4 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +1 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +4 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +7 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +5 -5
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +1 -0
- data/sig/rigor/analysis/reachability/scan_cache.rbs +12 -0
- data/sig/rigor/cache.rbs +2 -3
- data/sig/rigor/environment.rbs +5 -0
- data/sig/rigor/inference.rbs +3 -10
- data/sig/rigor/plugin/io_boundary.rbs +4 -0
- data/sig/rigor/plugin/manifest.rbs +2 -1
- data/sig/rigor/reflection.rbs +3 -1
- data/sig/rigor/scope.rbs +24 -3
- data/sig/rigor/sig_gen/skip_reason_catalog.rbs +14 -0
- data/sig/rigor/type.rbs +27 -1
- data/sig/rigor.rbs +1 -0
- data/skills/rigor-ask/SKILL.md +8 -6
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +13 -2
- data/skills/rigor-project-init/SKILL.md +6 -3
- data/skills/rigor-project-init/references/02-configure.md +10 -6
- data/skills/rigor-project-init/references/06-agent-contract.md +67 -0
- data/skills/rigor-type-oracle/SKILL.md +228 -0
- data/skills/rigor-type-oracle/references/01-oracle-commands.md +261 -0
- data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +52 -0
- data/skills/rigor-type-oracle/references/03-gap-protocol.md +128 -0
- data/skills/rigor-unused-adjudicate/SKILL.md +8 -5
- metadata +26 -3
- data/lib/rigor/cli/probe_environment.rb +0 -85
- data/sig/rigor/inference/builtins/numeric_catalog.rbs +0 -3
|
@@ -86,7 +86,17 @@ module Rigor
|
|
|
86
86
|
env = RBS::Environment.from_loader(rbs_loader)
|
|
87
87
|
project_files = project_sig_files(signature_paths)
|
|
88
88
|
add_project_signatures(env, signature_paths, deferred_signature_paths)
|
|
89
|
-
|
|
89
|
+
# Issue #928 — the capability-role catalog goes in AFTER the project's own signatures, per
|
|
90
|
+
# declaration, so a project that already declares one of these interface names keeps its own
|
|
91
|
+
# (`add_capability_role_signatures`). The rest of the bundled RBS cannot be ordered that way (it
|
|
92
|
+
# is what `from_loader` builds the env FROM), which is why a colliding project file is quarantined
|
|
93
|
+
# instead — and losing a whole `sig/` file to a name as ordinary as `_Closable` is exactly what
|
|
94
|
+
# shipping a top-level interface catalog would otherwise cost.
|
|
95
|
+
add_capability_role_signatures(env)
|
|
96
|
+
# Issue #824 — the project's own signatures are already in `env` at this point, so the inline
|
|
97
|
+
# contribution can be asked the question that keeps the two from colliding: which of its members
|
|
98
|
+
# does a `.rbs` file already declare? Those stand down per member ({.add_virtual_rbs}).
|
|
99
|
+
add_virtual_rbs(env, virtual_rbs, sig_member_owners: signature_member_owners(project_files, virtual_rbs))
|
|
90
100
|
synthesize_missing_namespaces(env)
|
|
91
101
|
# Issue #777 — resolve-time backstop: also unload colliding PROJECT buffers (class-vs-module /
|
|
92
102
|
# constant redeclarations against bundled RBS). Virtual culprits are preferred when both appear.
|
|
@@ -119,8 +129,8 @@ module Rigor
|
|
|
119
129
|
BIG_MATH_SIG_BASENAME = "big_math.rbs"
|
|
120
130
|
private_constant :BIG_MATH_SIG_BASENAME
|
|
121
131
|
|
|
122
|
-
# @param libraries
|
|
123
|
-
# @return
|
|
132
|
+
# @param libraries — the resolved library list, `DEFAULT_LIBRARIES` included.
|
|
133
|
+
# @return the same list, minus `bigdecimal-math` when `bigdecimal` already brings
|
|
124
134
|
# `BigMath` in.
|
|
125
135
|
def libraries_without_shadowed_bigdecimal_math(libraries)
|
|
126
136
|
return libraries unless libraries.include?(BIGDECIMAL_LIBRARY) && libraries.include?(BIGDECIMAL_MATH_LIBRARY)
|
|
@@ -383,7 +393,7 @@ module Rigor
|
|
|
383
393
|
end
|
|
384
394
|
|
|
385
395
|
# Issue #610 — which deferred (plugin-contributed) files stood down, as
|
|
386
|
-
# `[absolute_path, class_name, existing_arity, incoming_arity]`, sorted. DERIVED from a built env
|
|
396
|
+
# `[absolute_path, class_name, existing_arity, incoming_arity, existing_file]`, sorted. DERIVED from a built env
|
|
387
397
|
# rather than recorded during the build, for {RbsLoader#quarantined_signatures}' reason: a cache HIT
|
|
388
398
|
# never runs the build, and a condition only the build knew would silently disappear on the second
|
|
389
399
|
# run. Re-asking the same question of the FINAL env gives the same answer — the file's declaration is
|
|
@@ -400,21 +410,40 @@ module Rigor
|
|
|
400
410
|
end
|
|
401
411
|
end
|
|
402
412
|
|
|
403
|
-
# The first `[class_name, existing_arity, incoming_arity]` where `decls` would
|
|
404
|
-
# env already has with a DIFFERENT number of type parameters, or nil when
|
|
405
|
-
# Equal arity is not a conflict: RBS reopens the class, which is the ordinary
|
|
406
|
-
# the stand-down must not fire on it.
|
|
413
|
+
# The first `[class_name, existing_arity, incoming_arity, existing_file]` where `decls` would
|
|
414
|
+
# re-declare a class the env already has with a DIFFERENT number of type parameters, or nil when
|
|
415
|
+
# they agree everywhere. Equal arity is not a conflict: RBS reopens the class, which is the ordinary
|
|
416
|
+
# and supported case, so the stand-down must not fire on it.
|
|
417
|
+
#
|
|
418
|
+
# The existing arity is read off the entry's FIRST declaration, never through `entry.type_params`:
|
|
419
|
+
# rbs 4.x's `ClassEntry#type_params` validates every declaration against the first before answering
|
|
420
|
+
# and raises `GenericParameterMismatchError` on an entry that already disagrees with itself (rbs
|
|
421
|
+
# 3.x's does not), so the derived reader ({.deferred_standdowns}) raised on exactly the env it exists
|
|
422
|
+
# to describe — one a user's own two sources collided, or one the cache served from before the
|
|
423
|
+
# producer passed the deferred list. The first declaration is also the one rbs compares against.
|
|
424
|
+
# `existing_file` is that declaration's buffer name — the source that displaced the plugin's — or
|
|
425
|
+
# nil when it has none or carries only the cached-position sentinel.
|
|
407
426
|
def generic_arity_conflict(env, decls)
|
|
408
427
|
each_declared_class(decls) do |name, arity|
|
|
409
428
|
entry = env.class_decls[::RBS::TypeName.parse(name)]
|
|
410
|
-
next if entry.nil?
|
|
429
|
+
next if entry.nil?
|
|
411
430
|
|
|
412
|
-
|
|
413
|
-
|
|
431
|
+
first = entry_declarations(entry).first
|
|
432
|
+
existing = first.respond_to?(:type_params) ? first.type_params&.size : nil
|
|
433
|
+
return [name, existing, arity, declaration_buffer_name(first)] if existing && existing != arity
|
|
414
434
|
end
|
|
415
435
|
nil
|
|
416
436
|
end
|
|
417
437
|
|
|
438
|
+
def declaration_buffer_name(decl)
|
|
439
|
+
location = decl.respond_to?(:location) ? decl.location : nil
|
|
440
|
+
buffer = location&.buffer
|
|
441
|
+
name = buffer.nil? ? nil : buffer.name.to_s
|
|
442
|
+
return nil if name.nil? || name.empty? || name == CACHED_LOCATION_BUFFER_NAME
|
|
443
|
+
|
|
444
|
+
name
|
|
445
|
+
end
|
|
446
|
+
|
|
418
447
|
# Yields `[absolute_class_name, type_param_count]` for every class declared anywhere in `decls`,
|
|
419
448
|
# descending through modules and nested classes. Names inside a `module`/`class` body are parsed
|
|
420
449
|
# RELATIVE, so the enclosing path is accumulated here — the env is keyed by absolute name, and
|
|
@@ -798,7 +827,12 @@ module Rigor
|
|
|
798
827
|
# provenance (RBS parse errors cite it) — it is not a real file path. Per WD6 the synthesizer-emit
|
|
799
828
|
# path is responsible for catching its own parse errors and returning `nil` rather than garbage; this
|
|
800
829
|
# method assumes its input is parseable and only rescues `RBS::ParsingError` as a fail-soft.
|
|
801
|
-
|
|
830
|
+
# @param sig_member_owners — issue #824 — `{[class, method, kind] => signature_path}`
|
|
831
|
+
# from {.signature_member_owners}. Every member it names is removed from the inline contribution
|
|
832
|
+
# before the declaration is added, so `sig/` wins per MEMBER instead of the two colliding and
|
|
833
|
+
# costing the whole class its method surface (ADR-32 WD13). The stand-down is reported, never
|
|
834
|
+
# silent: {RbsLoader#inline_member_standdowns} re-derives the same set for the run's `:info` row.
|
|
835
|
+
def add_virtual_rbs(env, virtual_rbs, sig_member_owners: {})
|
|
802
836
|
return if virtual_rbs.nil? || virtual_rbs.empty?
|
|
803
837
|
|
|
804
838
|
virtual_rbs.each do |filename, content|
|
|
@@ -809,6 +843,7 @@ module Rigor
|
|
|
809
843
|
|
|
810
844
|
buffer = ::RBS::Buffer.new(name: filename.to_s, content: content.to_s)
|
|
811
845
|
_, directives, decls = ::RBS::Parser.parse_signature(buffer)
|
|
846
|
+
strip_members_declared_in_signatures!(decls, sig_member_owners) unless sig_member_owners.empty?
|
|
812
847
|
add_parsed_decls(env, buffer, directives, decls)
|
|
813
848
|
rescue ::RBS::BaseError
|
|
814
849
|
# WD6 fail-soft: a single broken virtual RBS contribution does not pull the whole env down — for
|
|
@@ -828,6 +863,187 @@ module Rigor
|
|
|
828
863
|
end
|
|
829
864
|
end
|
|
830
865
|
|
|
866
|
+
# Issue #824 / ADR-32 WD13 — the member-level half of inline-vs-`sig/` precedence.
|
|
867
|
+
#
|
|
868
|
+
# A method declared BOTH by a project `.rbs` and by an inline annotation in its own `.rb` lands twice
|
|
869
|
+
# in one `RBS::Environment`: rbs merges the two sources into a single `ClassEntry` and ranks neither,
|
|
870
|
+
# so `RBS::DefinitionBuilder::MethodBuilder::Methods#validate!` raises
|
|
871
|
+
# `RBS::DuplicatedMethodDefinitionError` and the WHOLE class loses its method surface — every call on
|
|
872
|
+
# it, real methods and typos alike, reads `Dynamic[top]`. Measured on Rigor's own tree while
|
|
873
|
+
# [#779](https://github.com/rigortype/rigor/pull/779) was evaluated: 17 of 234 annotated files
|
|
874
|
+
# overlapped `sig/`, and the collision took 44 classes down. Steep 2.1 / rbs 4.1 have no precedence
|
|
875
|
+
# rule to follow here (Steep reports the same collision as a signature diagnostic and the class still
|
|
876
|
+
# fails to build), so the spec's "SHOULD follow Steep 2.0" pointer resolves to nothing and the choice
|
|
877
|
+
# is Rigor's: the reviewed, `sig-gen`-managed `.rbs` wins, per member.
|
|
878
|
+
#
|
|
879
|
+
# @return `{[class_name, method_name, kind] => signature_path}` for every
|
|
880
|
+
# method-shaped member the project's own `signature_paths:` files declare and the inline sources
|
|
881
|
+
# also name. Empty — and free — for a project that contributes no inline RBS, which is every
|
|
882
|
+
# project without a `source_rbs_synthesizer:` plugin.
|
|
883
|
+
#
|
|
884
|
+
# The parse is scoped by a substring pre-filter over each file's text: a declaration has to spell its
|
|
885
|
+
# own name, so a signature file mentioning none of the names the inline sources declare cannot
|
|
886
|
+
# collide with them. The filter over-approximates (it matches a name in a comment or a type position
|
|
887
|
+
# too), so it can only cost an unnecessary parse, never miss a collision.
|
|
888
|
+
def signature_member_owners(project_files, virtual_rbs)
|
|
889
|
+
return {} if project_files.nil? || virtual_rbs.nil? || virtual_rbs.empty?
|
|
890
|
+
|
|
891
|
+
names = inline_declared_name_segments(virtual_rbs)
|
|
892
|
+
return {} if names.empty?
|
|
893
|
+
|
|
894
|
+
project_files.to_a.sort.each_with_object({}) do |file, owners|
|
|
895
|
+
decls = parse_signature_file_if_mentions(file, names)
|
|
896
|
+
next if decls.nil?
|
|
897
|
+
|
|
898
|
+
each_declared_member(decls) do |class_name, member|
|
|
899
|
+
member_method_keys(member).each do |method_name, kind|
|
|
900
|
+
owners[[class_name, method_name, kind]] ||= file
|
|
901
|
+
end
|
|
902
|
+
end
|
|
903
|
+
end
|
|
904
|
+
end
|
|
905
|
+
|
|
906
|
+
# The `[class, method, kind, signature_path, virtual_buffer_name]` record for every inline member
|
|
907
|
+
# {.add_virtual_rbs} stands down, sorted and deduplicated.
|
|
908
|
+
#
|
|
909
|
+
# Derived from the loader's own INPUTS — the synthesized sources and the project's signature files —
|
|
910
|
+
# never from the built environment, for {RbsLoader#quarantined_signatures}' reason turned inside out:
|
|
911
|
+
# a cache HIT never runs the build, and the stripped member leaves no trace in the environment to
|
|
912
|
+
# read back. The same two inputs answer identically warm and cold, which is what makes the reported
|
|
913
|
+
# set independent of cache state.
|
|
914
|
+
def inline_member_standdowns_for(signature_paths:, virtual_rbs:)
|
|
915
|
+
owners = signature_member_owners(project_sig_files(signature_paths), virtual_rbs)
|
|
916
|
+
return [].freeze if owners.empty?
|
|
917
|
+
|
|
918
|
+
records = virtual_rbs.flat_map do |name, content|
|
|
919
|
+
next [] if content.nil? || content.empty? || invalid_encoding?(content.to_s)
|
|
920
|
+
|
|
921
|
+
decls = parse_signature_source(name, content.to_s)
|
|
922
|
+
decls.nil? ? [] : member_standdowns_in(name, decls, owners)
|
|
923
|
+
end
|
|
924
|
+
records.uniq.sort_by { |record| [record[0], record[1].to_s, record[2].to_s] }.freeze
|
|
925
|
+
end
|
|
926
|
+
|
|
927
|
+
def member_standdowns_in(virtual_name, decls, owners)
|
|
928
|
+
records = []
|
|
929
|
+
each_declared_member(decls) do |class_name, member|
|
|
930
|
+
member_method_keys(member).each do |method_name, kind|
|
|
931
|
+
signature_path = owners[[class_name, method_name, kind]]
|
|
932
|
+
next if signature_path.nil?
|
|
933
|
+
|
|
934
|
+
records << [class_name, method_name, kind, signature_path, virtual_name.to_s].freeze
|
|
935
|
+
end
|
|
936
|
+
end
|
|
937
|
+
records
|
|
938
|
+
end
|
|
939
|
+
|
|
940
|
+
# Removes, in place, every member `owners` says a project signature already declares. Nested
|
|
941
|
+
# declarations are descended into after the rejection, and a declaration member contributes no method
|
|
942
|
+
# key, so nesting is never itself removed.
|
|
943
|
+
def strip_members_declared_in_signatures!(decls, owners, prefix = [])
|
|
944
|
+
Array(decls).each do |decl|
|
|
945
|
+
next unless declaration_with_members?(decl)
|
|
946
|
+
|
|
947
|
+
inner = prefix + [decl.name.to_s.delete_prefix("::")]
|
|
948
|
+
class_name = inner.join("::")
|
|
949
|
+
decl.members.reject! do |member|
|
|
950
|
+
member_method_keys(member).any? { |method_name, kind| owners.key?([class_name, method_name, kind]) }
|
|
951
|
+
end
|
|
952
|
+
strip_members_declared_in_signatures!(decl.members, owners, inner)
|
|
953
|
+
end
|
|
954
|
+
end
|
|
955
|
+
|
|
956
|
+
# Yields `[class_name, member]` for every member of every class / module declaration in `decls`,
|
|
957
|
+
# descending through nesting. The enclosing path is accumulated and the name rendered `::`-stripped,
|
|
958
|
+
# so a `module Foo; class Bar` and a `class Foo::Bar` elsewhere key the same — which is what makes a
|
|
959
|
+
# `sig/` declaration and an inline one comparable at all.
|
|
960
|
+
def each_declared_member(decls, prefix = [], &block)
|
|
961
|
+
Array(decls).each do |decl|
|
|
962
|
+
next unless declaration_with_members?(decl)
|
|
963
|
+
|
|
964
|
+
inner = prefix + [decl.name.to_s.delete_prefix("::")]
|
|
965
|
+
class_name = inner.join("::")
|
|
966
|
+
decl.members.each { |member| block.call(class_name, member) }
|
|
967
|
+
each_declared_member(decl.members, inner, &block)
|
|
968
|
+
end
|
|
969
|
+
end
|
|
970
|
+
|
|
971
|
+
def declaration_with_members?(decl)
|
|
972
|
+
(decl.is_a?(::RBS::AST::Declarations::Module) || decl.is_a?(::RBS::AST::Declarations::Class)) &&
|
|
973
|
+
decl.respond_to?(:members)
|
|
974
|
+
end
|
|
975
|
+
|
|
976
|
+
# The `[method_name, kind]` pairs one RBS member contributes to a definition build, mirroring
|
|
977
|
+
# `RBS::DefinitionBuilder::MethodBuilder#build_instance` / `#build_singleton` — which is what decides
|
|
978
|
+
# whether two members collide. An attribute contributes its reader and / or writer name (`foo`,
|
|
979
|
+
# `foo=`), an alias its new name, and `def self?.x` both sides. An `overloading?` member (`def x: ...
|
|
980
|
+
# | ...`) contributes NOTHING: rbs files those under `overloads` rather than `originals`, so they are
|
|
981
|
+
# designed to compose with an existing declaration and must not stand down against it.
|
|
982
|
+
def member_method_keys(member)
|
|
983
|
+
case member
|
|
984
|
+
when ::RBS::AST::Members::MethodDefinition then method_definition_keys(member)
|
|
985
|
+
when ::RBS::AST::Members::AttrReader then [[member.name, member.kind]]
|
|
986
|
+
when ::RBS::AST::Members::AttrWriter then [[:"#{member.name}=", member.kind]]
|
|
987
|
+
when ::RBS::AST::Members::AttrAccessor then [[member.name, member.kind], [:"#{member.name}=", member.kind]]
|
|
988
|
+
when ::RBS::AST::Members::Alias then [[member.new_name, member.kind]]
|
|
989
|
+
else []
|
|
990
|
+
end
|
|
991
|
+
end
|
|
992
|
+
|
|
993
|
+
def method_definition_keys(member)
|
|
994
|
+
return [] if member.respond_to?(:overloading?) && member.overloading?
|
|
995
|
+
|
|
996
|
+
case member.kind
|
|
997
|
+
when :instance then [[member.name, :instance]]
|
|
998
|
+
when :singleton then [[member.name, :singleton]]
|
|
999
|
+
else [[member.name, :instance], [member.name, :singleton]] # `def self?.x` defines both sides
|
|
1000
|
+
end
|
|
1001
|
+
end
|
|
1002
|
+
|
|
1003
|
+
# A class / module declaration header, as the pre-filter in {.signature_member_owners} reads it out of
|
|
1004
|
+
# synthesized RBS text.
|
|
1005
|
+
INLINE_DECLARATION_NAME = /^[ \t]*(?:class|module)[ \t]+([A-Z][A-Za-z0-9_]*(?:::[A-Z][A-Za-z0-9_]*)*)/
|
|
1006
|
+
private_constant :INLINE_DECLARATION_NAME
|
|
1007
|
+
|
|
1008
|
+
# Every `::`-separated segment of every class / module name the inline sources declare, read off the
|
|
1009
|
+
# synthesized TEXT rather than a parse: the set only has to be a SUPERSET (it feeds the pre-filter),
|
|
1010
|
+
# and a regexp over the handful of annotated files is far cheaper than parsing them a second time.
|
|
1011
|
+
# Entries {.add_virtual_rbs} would skip are skipped here too — an empty or invalid-UTF-8 contribution
|
|
1012
|
+
# declares nothing, and `String#scan` raises `ArgumentError` on invalid bytes rather than returning
|
|
1013
|
+
# no match.
|
|
1014
|
+
def inline_declared_name_segments(virtual_rbs)
|
|
1015
|
+
virtual_rbs.each_with_object(Set.new) do |(_name, content), acc|
|
|
1016
|
+
content = content.to_s
|
|
1017
|
+
next if content.empty? || invalid_encoding?(content)
|
|
1018
|
+
|
|
1019
|
+
content.scan(INLINE_DECLARATION_NAME) { |(declared)| acc.merge(declared.split("::")) }
|
|
1020
|
+
end
|
|
1021
|
+
end
|
|
1022
|
+
|
|
1023
|
+
# Parses one project signature file, or nil when it is unreadable, not valid UTF-8, unparseable, or
|
|
1024
|
+
# mentions none of `names` (so nothing in it can collide with the inline sources).
|
|
1025
|
+
def parse_signature_file_if_mentions(file, names)
|
|
1026
|
+
content = File.read(file, encoding: "UTF-8")
|
|
1027
|
+
return nil if invalid_encoding?(content)
|
|
1028
|
+
return nil if names.none? { |name| content.include?(name) }
|
|
1029
|
+
|
|
1030
|
+
parse_signature_source(file, content)
|
|
1031
|
+
rescue Errno::ENOENT, Errno::EISDIR, Errno::EACCES
|
|
1032
|
+
nil
|
|
1033
|
+
end
|
|
1034
|
+
|
|
1035
|
+
# The declarations of already-read RBS text, or nil when it does not parse. The twin of
|
|
1036
|
+
# {.parse_signature_file} for content the caller already holds (a synthesized virtual source, or a
|
|
1037
|
+
# signature file the pre-filter has just read).
|
|
1038
|
+
def parse_signature_source(name, content)
|
|
1039
|
+
_buffer, _directives, decls = ::RBS::Parser.parse_signature(
|
|
1040
|
+
::RBS::Buffer.new(name: name.to_s, content: content)
|
|
1041
|
+
)
|
|
1042
|
+
decls
|
|
1043
|
+
rescue ::RBS::BaseError
|
|
1044
|
+
nil
|
|
1045
|
+
end
|
|
1046
|
+
|
|
831
1047
|
# Per-gem `data/vendored_gem_sigs/<gem>/` directories that ship with Rigor. Each subdirectory is one
|
|
832
1048
|
# gem's RBS surface (the `<gem>.rbs` file is the typical content; `LICENSE.upstream` records
|
|
833
1049
|
# provenance). Coverage is deliberately scoped to the native-extension and "everywhere in Rails" gems
|
|
@@ -854,6 +1070,51 @@ module Rigor
|
|
|
854
1070
|
[Pathname(CORE_OVERLAY_SIGS_ROOT)]
|
|
855
1071
|
end
|
|
856
1072
|
|
|
1073
|
+
# Rigor's capability-role catalog (`data/capability_roles/`) — the structural interfaces ADR-1 and
|
|
1074
|
+
# `docs/type-specification/structural-interfaces-and-object-shapes.md` name as shipped, so a
|
|
1075
|
+
# `%a{rigor:v1:conforms-to _ClosableStream}` written by following the specification resolves in a
|
|
1076
|
+
# default run instead of failing soft to an unresolved-interface row. Public for the same reason
|
|
1077
|
+
# {.core_overlay_sig_paths} is: the cache descriptor digests these files into the env-blob key.
|
|
1078
|
+
CAPABILITY_ROLES_SIGS_ROOT = File.expand_path(
|
|
1079
|
+
"../../../data/capability_roles",
|
|
1080
|
+
__dir__
|
|
1081
|
+
).freeze
|
|
1082
|
+
|
|
1083
|
+
def capability_role_sig_paths
|
|
1084
|
+
return [] unless File.directory?(CAPABILITY_ROLES_SIGS_ROOT)
|
|
1085
|
+
|
|
1086
|
+
[Pathname(CAPABILITY_ROLES_SIGS_ROOT)]
|
|
1087
|
+
end
|
|
1088
|
+
|
|
1089
|
+
# Adds the catalog to an env that already holds the project's own signatures, one INTERFACE at a
|
|
1090
|
+
# time, skipping any name the env already declares. Granularity is the declaration rather than the
|
|
1091
|
+
# file (the #610 stand-down's unit) because this one file carries five unrelated roles: a project
|
|
1092
|
+
# declaring `_Closable` must not also lose `_ClosableStream`.
|
|
1093
|
+
def add_capability_role_signatures(env)
|
|
1094
|
+
declared = declared_interface_names(env)
|
|
1095
|
+
capability_role_sig_paths.each do |dir|
|
|
1096
|
+
dir.children.sort.each do |file|
|
|
1097
|
+
next unless file.file? && file.extname == ".rbs"
|
|
1098
|
+
|
|
1099
|
+
parsed = parse_signature_file(file.to_s)
|
|
1100
|
+
next if parsed.nil?
|
|
1101
|
+
|
|
1102
|
+
buffer, directives, decls = parsed
|
|
1103
|
+
standing = decls.reject { |decl| declared.include?(decl.name.absolute!) }
|
|
1104
|
+
next if standing.empty?
|
|
1105
|
+
|
|
1106
|
+
add_parsed_decls(env, buffer, directives, standing)
|
|
1107
|
+
end
|
|
1108
|
+
end
|
|
1109
|
+
end
|
|
1110
|
+
|
|
1111
|
+
# @param env — the environment the project's signatures are already in.
|
|
1112
|
+
def declared_interface_names(env)
|
|
1113
|
+
return Set.new unless env.respond_to?(:interface_decls)
|
|
1114
|
+
|
|
1115
|
+
env.interface_decls.keys.to_set
|
|
1116
|
+
end
|
|
1117
|
+
|
|
857
1118
|
# Bundled signature sources that SUPPLEMENT a stdlib library's own declarations rather than stand
|
|
858
1119
|
# alone: each re-opens a class the named `RBS::EnvironmentLoader` library declares with a mixin
|
|
859
1120
|
# (`CGI::QueryExtension`), a superclass (`Prism::Result`), or an `| ...` overload continuation
|
|
@@ -890,7 +1151,7 @@ module Rigor
|
|
|
890
1151
|
# that Rigor's arithmetic-chain widening produces). The overlay is added per-file, not
|
|
891
1152
|
# per-directory, because the `LIBRARY_SUPPLEMENT_CORE_OVERLAYS` files must be gated individually.
|
|
892
1153
|
#
|
|
893
|
-
# @param loaded_library_names
|
|
1154
|
+
# @param loaded_library_names — libraries that actually resolved on this loader.
|
|
894
1155
|
def add_bundled_signatures(rbs_loader, loaded_library_names)
|
|
895
1156
|
vendored_gem_sig_paths.each do |path|
|
|
896
1157
|
next unless path.directory?
|
|
@@ -910,10 +1171,10 @@ module Rigor
|
|
|
910
1171
|
end
|
|
911
1172
|
end
|
|
912
1173
|
|
|
913
|
-
# @param supplements
|
|
914
|
-
# @param path
|
|
915
|
-
# @param loaded_library_names
|
|
916
|
-
# @return
|
|
1174
|
+
# @param supplements — basename → gating library map.
|
|
1175
|
+
# @param path — the vendored directory or overlay file to test.
|
|
1176
|
+
# @param loaded_library_names — libraries that actually resolved on this loader.
|
|
1177
|
+
# @return true when `path` carries no library dependency, or its library loaded.
|
|
917
1178
|
def supplement_dependency_loaded?(supplements, path, loaded_library_names)
|
|
918
1179
|
library = supplements[path.basename.to_s]
|
|
919
1180
|
library.nil? || loaded_library_names.include?(library)
|
|
@@ -929,9 +1190,9 @@ module Rigor
|
|
|
929
1190
|
__dir__
|
|
930
1191
|
).freeze
|
|
931
1192
|
|
|
932
|
-
# @param gem_names
|
|
1193
|
+
# @param gem_names — overlay-eligible Gemfile.lock gem names (the caller filters
|
|
933
1194
|
# to the `:missing`-coverage, no-conflicting-plugin set).
|
|
934
|
-
# @return
|
|
1195
|
+
# @return the bundled overlay directory for each gem that ships one; empty when
|
|
935
1196
|
# none match or the overlay root is absent.
|
|
936
1197
|
def gem_overlay_sig_paths(gem_names)
|
|
937
1198
|
return [] unless File.directory?(GEM_OVERLAY_SIGS_ROOT)
|
|
@@ -942,9 +1203,9 @@ module Rigor
|
|
|
942
1203
|
end
|
|
943
1204
|
end
|
|
944
1205
|
|
|
945
|
-
# @param path
|
|
1206
|
+
# @param path — typically an entry from an {RbsLoader} instance's
|
|
946
1207
|
# {#signature_paths}.
|
|
947
|
-
# @return
|
|
1208
|
+
# @return whether `path` sits under the bundled gem-overlay root — what
|
|
948
1209
|
# `CheckRules::GEM_OVERLAY_OPEN_RECEIVERS`'s gate consults so that a class name's membership in
|
|
949
1210
|
# that list alone never grants the open-receiver exemption; the overlay directory that made the
|
|
950
1211
|
# entry true must have actually loaded THIS run too (issue #632, tracked further by #660).
|
|
@@ -982,7 +1243,7 @@ module Rigor
|
|
|
982
1243
|
# answer to the very same question, on the class that already owns the overlay's layout
|
|
983
1244
|
# ({GEM_OVERLAY_SIGS_ROOT}, {.gem_overlay_sig_paths}).
|
|
984
1245
|
#
|
|
985
|
-
# @param signature_paths
|
|
1246
|
+
# @param signature_paths — typically an {RbsLoader} instance's
|
|
986
1247
|
# {#signature_paths}. Takes the whole list rather than one entry so the twin's file set resolves
|
|
987
1248
|
# once per question — `CheckRules` asks it per `ActiveSupport::Duration` receiver.
|
|
988
1249
|
def gem_overlay_twin_signatures_loaded?(signature_paths)
|
|
@@ -997,7 +1258,7 @@ module Rigor
|
|
|
997
1258
|
# id mapping and passes the id; this resolves the id to the engine's own bundled `sig/` and answers
|
|
998
1259
|
# the filesystem question.
|
|
999
1260
|
#
|
|
1000
|
-
# @param plugin_id
|
|
1261
|
+
# @param plugin_id — a manifest id, e.g. `"activesupport-core-ext"`.
|
|
1001
1262
|
def bundled_overlay_twin_signatures_loaded?(plugin_id, signature_paths)
|
|
1002
1263
|
return false if signature_paths.nil? || signature_paths.empty?
|
|
1003
1264
|
|
|
@@ -1065,23 +1326,27 @@ module Rigor
|
|
|
1065
1326
|
end
|
|
1066
1327
|
end
|
|
1067
1328
|
|
|
1068
|
-
attr_reader :libraries, :signature_paths, :cache_store, :virtual_rbs
|
|
1329
|
+
attr_reader :libraries, :signature_paths, :cache_store, :virtual_rbs, :deferred_signature_paths
|
|
1069
1330
|
|
|
1070
|
-
# @param libraries
|
|
1331
|
+
# @param libraries — stdlib library names to load on top of core (e.g.,
|
|
1071
1332
|
# `["pathname", "json"]`). Empty by default. Each entry MUST correspond to a directory under the
|
|
1072
1333
|
# `rbs` gem's `stdlib/` tree; unknown names are silently dropped on environment build (the underlying
|
|
1073
1334
|
# `RBS::EnvironmentLoader` raises and we fail-soft).
|
|
1074
|
-
# @param signature_paths
|
|
1335
|
+
# @param signature_paths — additional directories of `.rbs` files to load
|
|
1075
1336
|
# (typically the project's `sig/` tree). Non-existent or non-directory paths are filtered out at
|
|
1076
1337
|
# build time so the loader stays robust to fixtures and bare repositories.
|
|
1077
|
-
# @param cache_store
|
|
1338
|
+
# @param cache_store — the persistent cache the loader threads through to
|
|
1078
1339
|
# `RbsEnvironment`, `RbsKnownClassNames`, `RbsConstantTable`, `RbsClassAncestorTable`, and
|
|
1079
1340
|
# `RbsClassTypeParamNames` producers. Pass `nil` (the default) to skip caching; the runner threads
|
|
1080
1341
|
# its own Store through here when enabled.
|
|
1081
|
-
# @param virtual_rbs
|
|
1342
|
+
# @param virtual_rbs — >] ADR-32 WD4 — `[virtual_filename, rbs_source]` pairs
|
|
1082
1343
|
# synthesised from project source by a plugin's `Manifest#source_rbs_synthesizer`. Merged into the
|
|
1083
1344
|
# env after `signature_paths:` and the vendored stubs. Pass `[]` (the default) when no
|
|
1084
1345
|
# synthesizer-emitting plugin is loaded.
|
|
1346
|
+
# @param deferred_signature_paths — the subset of `signature_paths:` a bundled plugin
|
|
1347
|
+
# contributed (issue #610): loaded last and allowed to stand down against a colliding generic
|
|
1348
|
+
# arity. Read back by the env-cache producer, which rebuilds the env from the loader's readers on
|
|
1349
|
+
# a miss — a list it cannot read is a stand-down that runs only on a `--no-cache` build.
|
|
1085
1350
|
def initialize(libraries: [], signature_paths: [], cache_store: nil, virtual_rbs: [],
|
|
1086
1351
|
deferred_signature_paths: [])
|
|
1087
1352
|
@libraries = libraries.map(&:to_s).freeze
|
|
@@ -1097,8 +1362,8 @@ module Rigor
|
|
|
1097
1362
|
# names currently consulted: `:env`, `:env_loaded`, `:env_build_warned`, `:definition_build_warned`,
|
|
1098
1363
|
# `:definition_build_details`, `:definition_build_reported`, `:definition_build_failures`,
|
|
1099
1364
|
# `:definition_build_deferred_count`, `:definition_build_deferred_first`,
|
|
1100
|
-
# `:definition_build_summary_warned`, `:
|
|
1101
|
-
# `:reflection`,
|
|
1365
|
+
# `:definition_build_summary_warned`, `:inline_member_standdowns`, `:internal_demand`,
|
|
1366
|
+
# `:internal_demand_status`, `:builder`, `:reflection`,
|
|
1102
1367
|
# `:instance_definitions_table`, `:singleton_definitions_table`.
|
|
1103
1368
|
# Constructed via `Hash.new` (NOT a `{ ... }` literal) so Rigor's `HashShape` narrowing doesn't
|
|
1104
1369
|
# infer a fixed key set from the initial state and fold post-initial slot reads (e.g.
|
|
@@ -1127,7 +1392,7 @@ module Rigor
|
|
|
1127
1392
|
# the stderr banner) reads it, and a cache HIT reaches it too — the env was built with the file already
|
|
1128
1393
|
# quarantined, so the condition is invisible in the cached env itself.
|
|
1129
1394
|
#
|
|
1130
|
-
# @return
|
|
1395
|
+
# @return empty when every `signature_paths:` file parses.
|
|
1131
1396
|
def quarantined_signatures
|
|
1132
1397
|
@state[:quarantined] ||= begin
|
|
1133
1398
|
parse_quarantined = self.class.quarantined_project_signatures(@signature_paths)
|
|
@@ -1135,17 +1400,24 @@ module Rigor
|
|
|
1135
1400
|
@state[:env], @signature_paths
|
|
1136
1401
|
)
|
|
1137
1402
|
parse_paths = parse_quarantined.to_set { |path, _note| path }
|
|
1403
|
+
# Issue #610 — a deferred file that STOOD DOWN is absent from the env by design, which is exactly
|
|
1404
|
+
# what the collision derivation reads as "quarantined". Derived from the same env, so a cache HIT
|
|
1405
|
+
# excludes it too; {#signature_standdowns} is where it is reported instead.
|
|
1406
|
+
stood_down = self.class.deferred_standdowns(@state[:env], @deferred_signature_paths).to_set(&:first)
|
|
1138
1407
|
(
|
|
1139
1408
|
parse_quarantined +
|
|
1140
|
-
collision_quarantined.reject
|
|
1409
|
+
collision_quarantined.reject do |entry|
|
|
1410
|
+
parse_paths.include?(entry[0]) || stood_down.include?(entry[0])
|
|
1411
|
+
end
|
|
1141
1412
|
).freeze
|
|
1142
1413
|
end
|
|
1143
1414
|
end
|
|
1144
1415
|
|
|
1145
1416
|
# Issue #610 — plugin-contributed signature files that stood down against a colliding generic arity,
|
|
1146
|
-
# as `[absolute_path, class_name, existing_arity, incoming_arity]`. Empty whenever no
|
|
1147
|
-
# collides, which is every project that has not run `rbs collection install` for a gem a
|
|
1148
|
-
# plugin also declares.
|
|
1417
|
+
# as `[absolute_path, class_name, existing_arity, incoming_arity, existing_file]`. Empty whenever no
|
|
1418
|
+
# plugin sig collides, which is every project that has not run `rbs collection install` for a gem a
|
|
1419
|
+
# bundled plugin also declares. Reported as `rbs.coverage.plugin-signature-stood-down` (`:info`); the
|
|
1420
|
+
# same file MUST NOT also appear in {#quarantined_signatures}.
|
|
1149
1421
|
def signature_standdowns
|
|
1150
1422
|
@state[:signature_standdowns] ||= self.class.deferred_standdowns(env, @deferred_signature_paths).freeze
|
|
1151
1423
|
end
|
|
@@ -1199,7 +1471,7 @@ module Rigor
|
|
|
1199
1471
|
# persisted, so every run re-attempts and re-raises), so this is captured directly in {#env}'s rescue
|
|
1200
1472
|
# rather than re-derived. Forcing `env` (any query does) populates it.
|
|
1201
1473
|
#
|
|
1202
|
-
# @return
|
|
1474
|
+
# @return `[error_class_name, first_error_line,
|
|
1203
1475
|
# conflicting_buffer_names]`, or nil when the environment built successfully.
|
|
1204
1476
|
def env_build_failure
|
|
1205
1477
|
env unless @state[:env_loaded]
|
|
@@ -1223,7 +1495,7 @@ module Rigor
|
|
|
1223
1495
|
# definition-build failure leaves no trace in the env at all — the env is fine; it is the BUILD over it
|
|
1224
1496
|
# that raised — so the rescue is the only place that ever knows.
|
|
1225
1497
|
#
|
|
1226
|
-
# @return
|
|
1498
|
+
# @return `[class_name, error_class_name,
|
|
1227
1499
|
# first_error_line, conflicting_buffer_names]`, one per class, in first-failure order. Empty for a
|
|
1228
1500
|
# healthy sig set, which is the common case.
|
|
1229
1501
|
def definition_build_failures
|
|
@@ -1237,7 +1509,7 @@ module Rigor
|
|
|
1237
1509
|
# the {#quarantined_signatures} trick — so a cache HIT, which never runs the build, reports the same
|
|
1238
1510
|
# condition: the marshalled env simply lacks the dropped buffers.
|
|
1239
1511
|
#
|
|
1240
|
-
# @return
|
|
1512
|
+
# @return virtual buffer names (source-file paths) whose contribution was dropped.
|
|
1241
1513
|
def virtual_rbs_collision_quarantined
|
|
1242
1514
|
@state[:virtual_rbs_collisions] ||= begin
|
|
1243
1515
|
built = @state[:env]
|
|
@@ -1252,6 +1524,25 @@ module Rigor
|
|
|
1252
1524
|
end
|
|
1253
1525
|
end
|
|
1254
1526
|
|
|
1527
|
+
# Issue #824 / ADR-32 WD13 — the inline (rbs-inline) members that stood down because the project's own
|
|
1528
|
+
# `signature_paths:` already declare the same `(class, method, kind)`. The `.rbs` wins per member; the
|
|
1529
|
+
# rest of the file's annotations still bind, and the class keeps its method surface instead of failing
|
|
1530
|
+
# its definition build.
|
|
1531
|
+
#
|
|
1532
|
+
# The sibling of {#virtual_rbs_collision_quarantined} one granularity finer: that one names a whole
|
|
1533
|
+
# inline FILE dropped for a class-level duplicate, this one names a single member. Both are derived
|
|
1534
|
+
# rather than recorded, so a cache HIT — where no build ran — reports the same condition; here the
|
|
1535
|
+
# derivation reads the loader's inputs rather than the built env, because a stripped member leaves no
|
|
1536
|
+
# trace in the env at all.
|
|
1537
|
+
#
|
|
1538
|
+
# @return `[class_name, method_name, kind, signature_path,
|
|
1539
|
+
# virtual_buffer_name]` records, sorted. Empty (and free) whenever the project contributes no inline
|
|
1540
|
+
# RBS or none of it overlaps a signature file.
|
|
1541
|
+
def inline_member_standdowns
|
|
1542
|
+
@state[:inline_member_standdowns] ||=
|
|
1543
|
+
self.class.inline_member_standdowns_for(signature_paths: @signature_paths, virtual_rbs: @virtual_rbs)
|
|
1544
|
+
end
|
|
1545
|
+
|
|
1255
1546
|
# The referenced-but-undeclared types {.stub_missing_referenced_types} stubbed so the project classes
|
|
1256
1547
|
# that mention them could build (e.g. an unavailable `DRb::DRbServer`, or a stale
|
|
1257
1548
|
# `Textbringer::EditorError`). Recovered off the built env like {#synthesized_namespaces}, so it
|
|
@@ -1415,7 +1706,7 @@ module Rigor
|
|
|
1415
1706
|
{}.freeze
|
|
1416
1707
|
end
|
|
1417
1708
|
|
|
1418
|
-
# @return
|
|
1709
|
+
# @return the resolved instance definition for `class_name`, or nil when the
|
|
1419
1710
|
# class is unknown or its definition cannot be built (RBS may raise on broken hierarchies; we
|
|
1420
1711
|
# fail-soft and return nil so the caller can fall back).
|
|
1421
1712
|
#
|
|
@@ -1441,7 +1732,6 @@ module Rigor
|
|
|
1441
1732
|
definition
|
|
1442
1733
|
end
|
|
1443
1734
|
|
|
1444
|
-
# @return [RBS::Definition::Method, nil]
|
|
1445
1735
|
def instance_method(class_name:, method_name:)
|
|
1446
1736
|
definition = instance_definition(class_name)
|
|
1447
1737
|
return nil unless definition
|
|
@@ -1449,7 +1739,7 @@ module Rigor
|
|
|
1449
1739
|
definition.methods[method_name.to_sym]
|
|
1450
1740
|
end
|
|
1451
1741
|
|
|
1452
|
-
# @return
|
|
1742
|
+
# @return every instance-method name on `class_name` — own, inherited, and
|
|
1453
1743
|
# included — as resolved by `RBS::DefinitionBuilder`. Returns `nil` (NOT `[]`) when the class
|
|
1454
1744
|
# definition cannot be built so callers can tell "no methods" apart from "unknown class". Used by the
|
|
1455
1745
|
# `rigor:v1:conforms-to` presence check ({Rigor::RbsExtended::ConformanceChecker}).
|
|
@@ -1460,7 +1750,7 @@ module Rigor
|
|
|
1460
1750
|
definition.methods.keys
|
|
1461
1751
|
end
|
|
1462
1752
|
|
|
1463
|
-
# @return
|
|
1753
|
+
# @return the built definition for the RBS interface `interface_name`
|
|
1464
1754
|
# (`_RewindableStream`), whose `.methods` are the required members (including interface-ancestor
|
|
1465
1755
|
# members). Returns `nil` when the name does not resolve to a loaded interface (a typo, or the
|
|
1466
1756
|
# defining library / sig set is not on the load path). Fail-soft on RBS build errors.
|
|
@@ -1475,15 +1765,15 @@ module Rigor
|
|
|
1475
1765
|
nil
|
|
1476
1766
|
end
|
|
1477
1767
|
|
|
1478
|
-
# @return
|
|
1768
|
+
# @return every method name required by the RBS interface `interface_name`, or nil
|
|
1479
1769
|
# when it does not resolve. Thin accessor over {#interface_definition} for the presence check.
|
|
1480
1770
|
def interface_method_names(interface_name)
|
|
1481
1771
|
interface_definition(interface_name)&.methods&.keys
|
|
1482
1772
|
end
|
|
1483
1773
|
|
|
1484
|
-
# @param rbs_alias
|
|
1774
|
+
# @param rbs_alias — a type-alias reference (`string`, `int`, `range[int?]`, …)
|
|
1485
1775
|
# appearing in a method signature.
|
|
1486
|
-
# @return
|
|
1776
|
+
# @return the alias's aliased type one level out, with type arguments substituted
|
|
1487
1777
|
# for a generic alias (`string` → `::String | ::_ToStr`; `range[int?]` → `::Range[int?] |
|
|
1488
1778
|
# ::_Range[int?]`), or nil for an unresolved name. Lets a caller see through the alias that
|
|
1489
1779
|
# {Inference::RbsTypeTranslator} otherwise degrades to `untyped`, which is why an interface/alias
|
|
@@ -1508,7 +1798,7 @@ module Rigor
|
|
|
1508
1798
|
nil
|
|
1509
1799
|
end
|
|
1510
1800
|
|
|
1511
|
-
# @return
|
|
1801
|
+
# @return the resolved singleton (class object) definition for `class_name`. The
|
|
1512
1802
|
# methods on this definition are the *class methods* of `class_name`, including those inherited from
|
|
1513
1803
|
# `Class` and `Module` for class types. Returns nil for unknown names and on RBS build errors
|
|
1514
1804
|
# (fail-soft).
|
|
@@ -1529,7 +1819,37 @@ module Rigor
|
|
|
1529
1819
|
definition
|
|
1530
1820
|
end
|
|
1531
1821
|
|
|
1532
|
-
#
|
|
1822
|
+
# Issue #915 — the MODULE names in `class_name`'s singleton ancestry, as RBS declares it. A
|
|
1823
|
+
# `class C; extend M; end` written in a project's own `sig/` puts `M` there and nothing else in the
|
|
1824
|
+
# environment surface exposes it: {#ancestor_names_for} answers the instance side only.
|
|
1825
|
+
#
|
|
1826
|
+
# Modules only, deliberately. `RBS::DefinitionBuilder#build_singleton` mixes the extended modules in
|
|
1827
|
+
# with the singleton's class chain (`Class`, `Module`, `Object`, `BasicObject`), and the classes there
|
|
1828
|
+
# are already what the `Class` approximation in `Inference::Narrowing` reasons through. The modules
|
|
1829
|
+
# that survive the filter — the declared `extend` targets, plus `Kernel` through `Object` — are each a
|
|
1830
|
+
# true answer to `C.is_a?(M)`.
|
|
1831
|
+
#
|
|
1832
|
+
# Marked as an internal demand for the same reason {#ancestor_names_for} is (issue #696): asking
|
|
1833
|
+
# whether a module sits in an ancestry is not asking whether the class's method surface resolves, and
|
|
1834
|
+
# letting it report would make the reported class list depend on the cache state.
|
|
1835
|
+
#
|
|
1836
|
+
# @return `::`-stripped module names, or `[]` for an unknown class and on any RBS build error.
|
|
1837
|
+
def singleton_extended_module_names(class_name)
|
|
1838
|
+
key = class_name.to_s.delete_prefix("::")
|
|
1839
|
+
during_internal_demand do
|
|
1840
|
+
definition = singleton_definition(key)
|
|
1841
|
+
next [].freeze if definition.nil?
|
|
1842
|
+
|
|
1843
|
+
definition.ancestors.ancestors.filter_map do |ancestor|
|
|
1844
|
+
name = ancestor.name.to_s.delete_prefix("::")
|
|
1845
|
+
name if ancestor.is_a?(::RBS::Definition::Ancestor::Instance) && rbs_module?(name)
|
|
1846
|
+
end.uniq.freeze
|
|
1847
|
+
end
|
|
1848
|
+
rescue ::RBS::BaseError, StandardError
|
|
1849
|
+
[].freeze
|
|
1850
|
+
end
|
|
1851
|
+
|
|
1852
|
+
# @return the class method on `class_name`. For example,
|
|
1533
1853
|
# `singleton_method(class_name: "Integer", method_name: :sqrt)` returns the definition for
|
|
1534
1854
|
# `Integer.sqrt`, while `singleton_method(class_name: "Foo", method_name: :new)` returns Class#new
|
|
1535
1855
|
# for any class type.
|
|
@@ -1553,18 +1873,29 @@ module Rigor
|
|
|
1553
1873
|
# process) through {Cache::RbsClassTypeParamNames.fetch} and answers point lookups from it. Cold runs
|
|
1554
1874
|
# build the table once and persist it; warm runs (and a separate loader sharing the same Store) skip
|
|
1555
1875
|
# the env walk entirely.
|
|
1876
|
+
#
|
|
1877
|
+
# #775 — memoised per class name and answered as a frozen list. `RBS::Definition#type_params` is not
|
|
1878
|
+
# an accessor: it re-derives the names through the entry's type-param declarations (a substitution
|
|
1879
|
+
# per call), and generic dispatch asks for the receiver class's names on every call (~110k times on
|
|
1880
|
+
# the lib self-check, the largest remaining rbs-side allocation). The env is immutable for the
|
|
1881
|
+
# loader's lifetime, so the answer never changes; every consumer only reads it.
|
|
1556
1882
|
def class_type_param_names(class_name)
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
end
|
|
1561
|
-
|
|
1562
|
-
definition = instance_definition(class_name)
|
|
1563
|
-
return [] unless definition
|
|
1883
|
+
memo = (@state[:type_param_names] ||= {})
|
|
1884
|
+
key = class_name.to_s
|
|
1885
|
+
return memo[key] if memo.key?(key)
|
|
1564
1886
|
|
|
1565
|
-
|
|
1887
|
+
memo[key] =
|
|
1888
|
+
if cache_store
|
|
1889
|
+
type_param_names_table.fetch(key.delete_prefix("::"), NO_TYPE_PARAMS).freeze
|
|
1890
|
+
else
|
|
1891
|
+
definition = instance_definition(class_name)
|
|
1892
|
+
definition ? definition.type_params.freeze : NO_TYPE_PARAMS
|
|
1893
|
+
end
|
|
1566
1894
|
end
|
|
1567
1895
|
|
|
1896
|
+
NO_TYPE_PARAMS = [].freeze
|
|
1897
|
+
private_constant :NO_TYPE_PARAMS
|
|
1898
|
+
|
|
1568
1899
|
def class_ordering(lhs, rhs)
|
|
1569
1900
|
@hierarchy.class_ordering(lhs, rhs)
|
|
1570
1901
|
end
|
|
@@ -1595,7 +1926,7 @@ module Rigor
|
|
|
1595
1926
|
# way, and both yield `[]` for an unknown or unbuildable class. Pinned by spec across all three cache
|
|
1596
1927
|
# states.
|
|
1597
1928
|
#
|
|
1598
|
-
# @return
|
|
1929
|
+
# @return `::`-stripped ancestor names, or `[]` for an unknown or unbuildable class.
|
|
1599
1930
|
def ancestor_names_for(class_name)
|
|
1600
1931
|
key = class_name.to_s.delete_prefix("::")
|
|
1601
1932
|
during_internal_demand do
|
|
@@ -1610,7 +1941,7 @@ module Rigor
|
|
|
1610
1941
|
[].freeze
|
|
1611
1942
|
end
|
|
1612
1943
|
|
|
1613
|
-
# @return
|
|
1944
|
+
# @return every RBS-declared constant name (top-level prefixed, e.g., `"::Math::PI"`)
|
|
1614
1945
|
# currently loaded into the environment. Used by the cache producer that materialises the
|
|
1615
1946
|
# constant-type table; ordinary callers should keep using {#constant_type} for point lookups.
|
|
1616
1947
|
def constant_names
|
|
@@ -2276,8 +2607,6 @@ module Rigor
|
|
|
2276
2607
|
# `#method_name`; `UnknownMethodAliasError` and `NoSuperclassFoundError` have `#type_name`;
|
|
2277
2608
|
# `SuperclassMismatchError` has `#name`. `RecursiveAncestorError` has none of them and yields nil, and
|
|
2278
2609
|
# the diagnostic then omits the clause rather than inventing one.
|
|
2279
|
-
#
|
|
2280
|
-
# @return [String, nil]
|
|
2281
2610
|
def definition_build_member(error)
|
|
2282
2611
|
return error.qualified_method_name.to_s if error.respond_to?(:qualified_method_name)
|
|
2283
2612
|
|