rigortype 0.3.7 → 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 +96 -15
- 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 +39 -4
- data/docs/manual/03-configuration.md +11 -0
- data/docs/manual/04-diagnostics.md +12 -1
- 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 +69 -13
- 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 +100 -29
- 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 +316 -40
- 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 +430 -77
- data/lib/rigor/analysis/runner/project_pre_passes.rb +12 -6
- data/lib/rigor/analysis/runner/run_snapshots.rb +13 -3
- data/lib/rigor/analysis/runner.rb +200 -43
- data/lib/rigor/analysis/worker_session.rb +36 -12
- data/lib/rigor/bleeding_edge.rb +12 -24
- data/lib/rigor/builtins/hkt_builtins.rb +2 -2
- data/lib/rigor/builtins/imported_refinements.rb +166 -30
- 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 +70 -0
- 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_environment_marshal_patch.rb +39 -0
- data/lib/rigor/cache/rbs_known_class_names.rb +0 -3
- data/lib/rigor/cache/store.rb +85 -33
- 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 +31 -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 +28 -0
- 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 +613 -113
- data/lib/rigor/environment.rb +189 -27
- 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 +19 -10
- data/lib/rigor/inference/hkt_sugar_translator.rb +15 -21
- 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 +67 -14
- 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 +12 -13
- data/lib/rigor/rbs_extended/hkt_directives.rb +16 -1
- data/lib/rigor/rbs_extended/reporter.rb +122 -16
- data/lib/rigor/rbs_extended.rb +67 -22
- 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 +181 -102
- 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 +17 -11
- 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 +11 -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 +28 -3
- data/lib/rigor/cli/probe_environment.rb +0 -85
- data/sig/rigor/inference/builtins/numeric_catalog.rbs +0 -3
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rbs"
|
|
4
|
+
|
|
5
|
+
module Rigor
|
|
6
|
+
module Cache
|
|
7
|
+
# The `RBS::AST::Annotation` location carry (issue #799): the two halves of the `marshal_dump` /
|
|
8
|
+
# `marshal_load` pair {file:lib/rigor/cache/rbs_environment_marshal_patch.rb the env-cache Marshal patch}
|
|
9
|
+
# installs on `RBS::AST::Annotation`, plus the buffer a reconstructed location points at. That file's
|
|
10
|
+
# header carries the why; this one is the how.
|
|
11
|
+
#
|
|
12
|
+
# Nothing here reconstructs the annotation's SOURCE — the cached env has no file contents, and a
|
|
13
|
+
# consumer that wants the text already has `Annotation#string`. What it reconstructs is the pair of
|
|
14
|
+
# `(line, column)` answers `RBS::Location` gives, so a diagnostic positioned on the directive reads the
|
|
15
|
+
# same line warm as it does cold.
|
|
16
|
+
module AnnotationLocation
|
|
17
|
+
# The two positions {Buffer} distinguishes. `RBS::Location` addresses its buffer by character
|
|
18
|
+
# offset, and the reconstruction has no content to offset into, so the offsets are used as tags:
|
|
19
|
+
# 0 is "the start pair", 1 is "the end pair".
|
|
20
|
+
START_POS = 0
|
|
21
|
+
END_POS = 1
|
|
22
|
+
|
|
23
|
+
# A content-less `RBS::Buffer` that answers `pos_to_loc` from the pairs the cold parse had.
|
|
24
|
+
#
|
|
25
|
+
# Answering there is all it takes: `RBS::Location#start_line` and its three siblings are C methods
|
|
26
|
+
# that resolve the offset through `buffer.pos_to_loc`, so the reconstructed Location reports the real
|
|
27
|
+
# position without the buffer having to hold (or synthesize) the file it came from. The alternative —
|
|
28
|
+
# a synthetic content string of `line - 1` newlines — is exact only while an annotation stays on one
|
|
29
|
+
# line, and `%a{...}` may span two.
|
|
30
|
+
class Buffer < ::RBS::Buffer
|
|
31
|
+
def initialize(name:, start_loc:, end_loc:)
|
|
32
|
+
super(name: name, content: "")
|
|
33
|
+
@start_loc = start_loc
|
|
34
|
+
@end_loc = end_loc
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def pos_to_loc(pos)
|
|
38
|
+
pos == START_POS ? @start_loc : @end_loc
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
module_function
|
|
43
|
+
|
|
44
|
+
# @return `[name, start_line, start_column, end_line, end_column]`, or nil when there is
|
|
45
|
+
# no location to carry. Fail-soft: a location whose buffer cannot answer is dumped as nil rather
|
|
46
|
+
# than failing the whole environment's dump.
|
|
47
|
+
def dump(location)
|
|
48
|
+
return nil if location.nil?
|
|
49
|
+
|
|
50
|
+
buffer = location.buffer
|
|
51
|
+
name = buffer.respond_to?(:name) ? buffer.name.to_s : nil
|
|
52
|
+
[name, location.start_line, location.start_column, location.end_line, location.end_column]
|
|
53
|
+
rescue StandardError
|
|
54
|
+
nil
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# @param payload — what {dump} produced.
|
|
58
|
+
def load(payload)
|
|
59
|
+
return nil if payload.nil?
|
|
60
|
+
|
|
61
|
+
name, start_line, start_column, end_line, end_column = payload
|
|
62
|
+
name = ::RBS::Location::CACHED_BUFFER_NAME if name.nil? || name.empty?
|
|
63
|
+
buffer = Buffer.new(name: name, start_loc: [start_line, start_column], end_loc: [end_line, end_column])
|
|
64
|
+
::RBS::Location.new(buffer: buffer, start_pos: START_POS, end_pos: END_POS)
|
|
65
|
+
rescue StandardError
|
|
66
|
+
nil
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -48,7 +48,12 @@ module Rigor
|
|
|
48
48
|
# added to a schema-less project) invalidates the warm entry. A pre-8 entry carries no absence rows
|
|
49
49
|
# and would validate fresh across exactly that edit, so cached entries must read as misses once and
|
|
50
50
|
# rebuild carrying the rows.
|
|
51
|
-
|
|
51
|
+
# v9: #979 — the run-result dependency descriptor now carries a names-only {GlobEntry} directory
|
|
52
|
+
# listing per RBS signature root, so a `.rbs` file APPEARING under one (a `sig/roles.rbs` declaring the
|
|
53
|
+
# interface a `conforms-to` names) invalidates the warm entry. A pre-9 entry carries no signature-root
|
|
54
|
+
# row and would validate fresh across exactly that edit — the #577 reasoning, one slot over — so cached
|
|
55
|
+
# entries must read as misses once and rebuild carrying the rows.
|
|
56
|
+
SCHEMA_VERSION = 9
|
|
52
57
|
|
|
53
58
|
# Per-slot entry value objects. Constructors validate enums / required fields and freeze the resulting
|
|
54
59
|
# struct so no caller can mutate after the entry is in a Descriptor.
|
|
@@ -114,7 +119,7 @@ module Rigor
|
|
|
114
119
|
new(path: path, comparator: :exists, value: PRESENT)
|
|
115
120
|
end
|
|
116
121
|
|
|
117
|
-
# @return
|
|
122
|
+
# @return whether this row records the path as absent (see {.absent}).
|
|
118
123
|
def absent?
|
|
119
124
|
comparator == :exists && value == ABSENT
|
|
120
125
|
end
|
|
@@ -235,31 +240,58 @@ module Rigor
|
|
|
235
240
|
FIELD_SEPARATOR = "\0"
|
|
236
241
|
private_constant :ROW_SEPARATOR, :FIELD_SEPARATOR
|
|
237
242
|
|
|
243
|
+
# `:stat` is the ADR-87 WD2 signature above — it answers "did anything under this glob change",
|
|
244
|
+
# appearance and edit alike. `:names` (#979) answers only "did the SET of matching paths change":
|
|
245
|
+
# its rows are the sorted relative names, so a file whose bytes are unchanged never moves the
|
|
246
|
+
# signature however its stat tuple moved. A row exists to catch appearance/disappearance only —
|
|
247
|
+
# edits to the files it lists are already carried by their own `:stat` {FileEntry} rows — and a
|
|
248
|
+
# names row must therefore survive what those rows survive. A `:stat` glob over a signature tree
|
|
249
|
+
# would not: ADR-87 WD1 lets a `:stat` file row fall back to its recorded content digest when the
|
|
250
|
+
# tuple moves, so a `git checkout`, a `bundle install` or a CI cache restored over a fresh checkout
|
|
251
|
+
# keeps the file rows fresh while it would move every glob signature, turning every such run into a
|
|
252
|
+
# full re-analysis. `:names` also reads no stat at all, so it costs a `Dir.glob` and nothing else.
|
|
253
|
+
VALID_MODES = %i[stat names].freeze
|
|
254
|
+
|
|
238
255
|
attr_reader :root, :pattern, :value
|
|
239
256
|
|
|
240
|
-
value_fields :root, :pattern, :value
|
|
257
|
+
value_fields :root, :pattern, :mode, :value
|
|
258
|
+
|
|
259
|
+
def initialize(root:, pattern:, value:, mode: :stat)
|
|
260
|
+
raise ArgumentError, "GlobEntry mode must be one of #{VALID_MODES.inspect}, got #{mode.inspect}" \
|
|
261
|
+
unless VALID_MODES.include?(mode)
|
|
241
262
|
|
|
242
|
-
def initialize(root:, pattern:, value:)
|
|
243
263
|
@root = root.to_s.dup.freeze
|
|
244
264
|
@pattern = pattern.to_s.dup.freeze
|
|
265
|
+
@mode = mode
|
|
245
266
|
@value = value.to_s.dup.freeze
|
|
246
267
|
freeze
|
|
247
268
|
end
|
|
248
269
|
|
|
270
|
+
# Defaulted rather than an `attr_reader` because an entry Marshal-loaded from a store written before
|
|
271
|
+
# the field existed carries no `@mode` ivar; every such entry was recorded under the stat signature.
|
|
272
|
+
def mode
|
|
273
|
+
@mode || :stat
|
|
274
|
+
end
|
|
275
|
+
|
|
249
276
|
# Builds the entry for the glob's CURRENT filesystem state.
|
|
250
|
-
def self.compute(root:, pattern:)
|
|
251
|
-
new(root: root, pattern: pattern,
|
|
277
|
+
def self.compute(root:, pattern:, mode: :stat)
|
|
278
|
+
new(root: root, pattern: pattern, mode: mode,
|
|
279
|
+
value: signature_for(root: root, pattern: pattern, mode: mode))
|
|
252
280
|
end
|
|
253
281
|
|
|
254
282
|
# The aggregate signature the entry's `value` carries: SHA-256 over the sorted per-file rows. In the
|
|
255
283
|
# default (`:stat`) mode a row is the file's `(path, size, mtime_ns, ctime_ns, inode)` tuple — NO
|
|
256
284
|
# content read; in strict mode a row is `(path, content-sha256)`, restoring the pre-ADR-87 authority.
|
|
285
|
+
# In `:names` mode a row is the path alone, stat-free, so only the matching SET moves the signature.
|
|
257
286
|
# Per-file stat failures (a file vanishing between the glob and the stat) drop the row — same race
|
|
258
287
|
# posture as {Descriptor#file_entry_fresh?}. `Dir.glob` returns sorted entries by default so the row
|
|
259
288
|
# order — and therefore the signature — is stable.
|
|
260
|
-
def self.signature_for(root:, pattern:)
|
|
289
|
+
def self.signature_for(root:, pattern:, mode: :stat)
|
|
290
|
+
paths = Dir.glob(File.join(root, pattern))
|
|
291
|
+
return Digest::SHA256.hexdigest(paths.map { |path| "#{path}#{ROW_SEPARATOR}" }.join) if mode == :names
|
|
292
|
+
|
|
261
293
|
strict = FileDigest.strict_validation?
|
|
262
|
-
rows =
|
|
294
|
+
rows = paths.filter_map do |path|
|
|
263
295
|
st = File.stat(path)
|
|
264
296
|
next nil unless st.file?
|
|
265
297
|
|
|
@@ -276,23 +308,30 @@ module Rigor
|
|
|
276
308
|
end
|
|
277
309
|
|
|
278
310
|
# ADR-87 WD2 — fresh iff re-globbing + re-stat-ing reproduces the recorded signature. Zero file-content
|
|
279
|
-
# bytes are read in the default mode
|
|
280
|
-
# signature recorded under the opposite validation mode simply
|
|
311
|
+
# bytes are read in the default mode, and no stat at all in `:names`. Any failure reads as stale
|
|
312
|
+
# (recompute), never a crash. A stored signature recorded under the opposite validation mode simply
|
|
313
|
+
# mismatches and recomputes.
|
|
281
314
|
def self.fresh?(entry)
|
|
282
|
-
signature_for(root: entry.root, pattern: entry.pattern) == entry.value
|
|
315
|
+
signature_for(root: entry.root, pattern: entry.pattern, mode: entry.mode) == entry.value
|
|
283
316
|
rescue StandardError
|
|
284
317
|
false
|
|
285
318
|
end
|
|
286
319
|
|
|
287
|
-
# Composition key — {.compose} unions per (root, pattern) slot; two contributions for the same
|
|
288
|
-
# must agree on the value or {Conflict} is raised. Within one run the same glob stat-reads
|
|
289
|
-
# so contributions never conflict.
|
|
320
|
+
# Composition key — {.compose} unions per (root, pattern, mode) slot; two contributions for the same
|
|
321
|
+
# slot must agree on the value or {Conflict} is raised. Within one run the same glob stat-reads
|
|
322
|
+
# identically, so contributions never conflict. The mode is part of the key because the two signatures
|
|
323
|
+
# over one (root, pattern) are different questions, not rival answers to the same one.
|
|
290
324
|
def slot_key
|
|
291
|
-
"#{root}\0#{pattern}"
|
|
325
|
+
"#{root}\0#{pattern}\0#{mode}"
|
|
292
326
|
end
|
|
293
327
|
|
|
294
328
|
def to_h
|
|
295
|
-
{ "root" => root, "pattern" => pattern, "value" => value }
|
|
329
|
+
h = { "root" => root, "pattern" => pattern, "value" => value }
|
|
330
|
+
# Omitted in the default mode so a descriptor carrying only stat globs keeps its pre-#979 canonical
|
|
331
|
+
# bytes: this FIELD moves no producer's key. (Every key still moved once with SCHEMA_VERSION 9,
|
|
332
|
+
# which the storage layer mixes in; that is the #979 migration, not the mode.)
|
|
333
|
+
h["mode"] = mode.to_s unless mode == :stat
|
|
334
|
+
h
|
|
296
335
|
end
|
|
297
336
|
end
|
|
298
337
|
|
|
@@ -352,9 +391,8 @@ module Rigor
|
|
|
352
391
|
dependencies: dependencies, globs: globs)
|
|
353
392
|
end
|
|
354
393
|
|
|
355
|
-
# @param
|
|
356
|
-
# @
|
|
357
|
-
# @return [String] hex SHA-256 cache key for the value
|
|
394
|
+
# @param params — inputs the producer was called with
|
|
395
|
+
# @return hex SHA-256 cache key for the value
|
|
358
396
|
def cache_key_for(producer_id:, params: {})
|
|
359
397
|
payload = {
|
|
360
398
|
"schema_version" => SCHEMA_VERSION,
|
|
@@ -377,7 +415,7 @@ module Rigor
|
|
|
377
415
|
"dependencies" => sort_entries(dependencies, "gem_name").map(&:to_h),
|
|
378
416
|
"files" => sort_entries(files, "path").map(&:to_h),
|
|
379
417
|
"gems" => sort_entries(gems, "name").map(&:to_h),
|
|
380
|
-
"globs" => globs.sort_by { |e| [e.root, e.pattern] }.map(&:to_h),
|
|
418
|
+
"globs" => globs.sort_by { |e| [e.root, e.pattern, e.mode.to_s] }.map(&:to_h),
|
|
381
419
|
"plugins" => sort_entries(plugins, "id").map(&:to_h)
|
|
382
420
|
}
|
|
383
421
|
end
|
|
@@ -65,15 +65,15 @@ module Rigor
|
|
|
65
65
|
|
|
66
66
|
module_function
|
|
67
67
|
|
|
68
|
-
# @return
|
|
68
|
+
# @return the gem root — the directory holding `lib/`, three levels above this file.
|
|
69
69
|
def root
|
|
70
70
|
@root ||= File.expand_path("../../..", __dir__)
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
-
# @param root
|
|
74
|
-
# @return
|
|
73
|
+
# @param root — the gem root, defaulted through {.root} so a spec can relocate the tree.
|
|
74
|
+
# @return a digest identifying the engine's current source, or nil when the tree is
|
|
75
75
|
# version-pinned and the caller should add no slot at all.
|
|
76
|
-
# @raise
|
|
76
|
+
# @raise Unavailable — when a mutable tree's source cannot be read.
|
|
77
77
|
def identity(root = self.root)
|
|
78
78
|
return nil if version_pinned?(root)
|
|
79
79
|
|
|
@@ -74,7 +74,7 @@ module Rigor
|
|
|
74
74
|
memo[path] ||= Digest::SHA256.file(path).hexdigest
|
|
75
75
|
end
|
|
76
76
|
|
|
77
|
-
# @return
|
|
77
|
+
# @return whether digest-always validation is forced for this run. The env var wins over the
|
|
78
78
|
# run-scoped config flag so an operator can bypass the stat tier without editing `.rigor.yml`.
|
|
79
79
|
def self.strict_validation?
|
|
80
80
|
return true if ENV[STRICT_ENV] == "1"
|
|
@@ -112,6 +112,14 @@ module Rigor
|
|
|
112
112
|
hexdigest(path) == digest
|
|
113
113
|
end
|
|
114
114
|
|
|
115
|
+
# The content-digest field of a packed `:stat` entry ({.pack_stat}); nil when the entry is absent or not
|
|
116
|
+
# well-formed. Exposed for the caller that must compare the recorded digest against bytes it hashes
|
|
117
|
+
# itself rather than against the file on disk — the incremental session's editor-mode freshness check,
|
|
118
|
+
# whose authority is the editor's buffer.
|
|
119
|
+
def self.content_digest(packed)
|
|
120
|
+
parse_stat(packed)&.first
|
|
121
|
+
end
|
|
122
|
+
|
|
115
123
|
# The VALIDATION-side stat, served from the per-run table when one is installed — a collecting run
|
|
116
124
|
# validates the effects entry and the diagnostics entry against the same ~thousands-of-files
|
|
117
125
|
# dependency descriptor, and the second pass is pure repetition under the run's own stable-filesystem
|
|
@@ -84,7 +84,29 @@ module Rigor
|
|
|
84
84
|
# `[]`, deserialises cleanly, and would send every unchanged file's top-level helper back to the peel
|
|
85
85
|
# on a warm run while a cold run resolved at the top level — the `--verify-incremental` divergence 14
|
|
86
86
|
# was bumped for, in the same table.
|
|
87
|
-
|
|
87
|
+
# 18: issue #728 re-keys each seed bundle's `header_nestings` VALUE from one chain per class to one
|
|
88
|
+
# chain per ancestor NAME the class's sites wrote, plus an unkeyed chain holding the old union. A
|
|
89
|
+
# pre-18 blob's Array value is not a Hash and the resolver's per-name lookup would raise on it, so the
|
|
90
|
+
# gate has to reject it — and even a reader that tolerated the old shape would serve the per-class
|
|
91
|
+
# union for every unchanged file, which is the answer this issue exists to stop giving.
|
|
92
|
+
# 19: issue #668 re-keys a constant write through a base no name reaches — `k::LIMIT = 7` — from the
|
|
93
|
+
# bare last segment to the wildcard `*::LIMIT`, in `constant_decls` and in each seed bundle's
|
|
94
|
+
# `constant_writes` census alike. A pre-19 blob's `LIMIT` key deserialises cleanly and reads as an
|
|
95
|
+
# ordinary top-level write, so every unchanged file would keep publishing the `Foo::LIMIT` the write
|
|
96
|
+
# may already have replaced while a cold run made it gradual — the `--verify-incremental` divergence
|
|
97
|
+
# 14 was bumped for.
|
|
98
|
+
# 20: issue #722 residue 2 adds each seed bundle's compact-header re-anchor census, without which a
|
|
99
|
+
# warm fold sees no candidate for an unchanged file and keeps serving the pre-fix `Wrap::Outer::Leaf`
|
|
100
|
+
# for a `class Outer::Leaf` that reopens `::Outer::Leaf`.
|
|
101
|
+
# 21: issue #915 widens the seed bundle's `extends` table to a singleton-body `include` / `prepend`;
|
|
102
|
+
# a pre-21 bundle for an unchanged file would keep the narrower record and still report the
|
|
103
|
+
# `case Widget when M` arm unreachable.
|
|
104
|
+
# 22: issues #796 / #794 add `run_level_rows` — the cold run's `definition-build-failed` set and its
|
|
105
|
+
# HKT-scan outcome, the two rows a narrowed run cannot re-derive from the files it analyses. A pre-22
|
|
106
|
+
# blob has no such section and would deserialise it as nil, which reads as "nothing cached" and is
|
|
107
|
+
# therefore not misread — but a snapshot written by an engine that did not yet REPLAY them was also
|
|
108
|
+
# written by one whose narrowed runs under-reported, so the gate rejects it and the next run is cold.
|
|
109
|
+
SCHEMA = 22
|
|
88
110
|
|
|
89
111
|
# The persisted per-file state.
|
|
90
112
|
# `cache` maps an analyzed file to its diagnostics.
|
|
@@ -136,11 +158,21 @@ module Rigor
|
|
|
136
158
|
# collection was off). It is a SEPARATE gate from the global `fingerprint`: the `effects:` block is
|
|
137
159
|
# deliberately absent from `Configuration#to_h`, so turning collection on invalidates no diagnostics,
|
|
138
160
|
# and a vocabulary / catalogue / `effects:` change must invalidate the summaries alone.
|
|
161
|
+
# Issues #796 / #794 — the run-level rows a narrowed run replays instead of re-deriving; see
|
|
162
|
+
# docs/internal-spec/cache.md § "Run-level rows the snapshot carries" for why exactly these two are
|
|
163
|
+
# fresh under the fingerprint and why no other `.rigor.yml`-level row may join them.
|
|
139
164
|
Payload = Data.define(:cache, :sources, :digests, :analyzed,
|
|
140
165
|
:symbol_sources, :ancestry_sources, :symbol_fingerprints,
|
|
141
166
|
:missing, :class_decls, :constant_decls, :seed_bundles, :plugin_fact_digest,
|
|
142
167
|
:return_summaries, :param_table,
|
|
143
|
-
:effect_collections, :effects_identity)
|
|
168
|
+
:effect_collections, :effects_identity, :run_level_rows)
|
|
169
|
+
|
|
170
|
+
# Issues #796 / #794 — the two run-level rows the snapshot carries. `definition_build_failures` is the
|
|
171
|
+
# reported per-class detail list ({Environment::RbsLoader#definition_build_failures}); `hkt_scan_failure`
|
|
172
|
+
# is the `[error_class, first_line, frame, stage]` tuple ({Rigor::Environment#hkt_scan_failure}), nil
|
|
173
|
+
# when the scan succeeded — which is why the presence of this object, not the tuple, is what says a
|
|
174
|
+
# replay is available.
|
|
175
|
+
RunLevelRows = Data.define(:definition_build_failures, :hkt_scan_failure)
|
|
144
176
|
|
|
145
177
|
# The global fingerprint that gates a snapshot load: a digest of the inputs whose change requires a full
|
|
146
178
|
# rebuild — the engine version + schema, the engine's own SOURCE when the version does not pin it, the
|
|
@@ -222,8 +254,8 @@ module Rigor
|
|
|
222
254
|
# The fingerprint that matched is returned alongside the payload so the caller can mix it into ITS own
|
|
223
255
|
# cache key — the snapshot's identity is exactly what "these dependency edges came from that world" means.
|
|
224
256
|
#
|
|
225
|
-
# @param fingerprints
|
|
226
|
-
# @return
|
|
257
|
+
# @param fingerprints — candidates, most-specific first.
|
|
258
|
+
# @return `[matched fingerprint, payload]`, or nil on any miss.
|
|
227
259
|
def load_any(fingerprints:)
|
|
228
260
|
data = read_data
|
|
229
261
|
return nil if data.nil?
|
|
@@ -259,7 +291,8 @@ module Rigor
|
|
|
259
291
|
return_summaries: data[:return_summaries] || {},
|
|
260
292
|
param_table: data[:param_table] || {},
|
|
261
293
|
effect_collections: data[:effect_collections] || {},
|
|
262
|
-
effects_identity: data[:effects_identity]
|
|
294
|
+
effects_identity: data[:effects_identity],
|
|
295
|
+
run_level_rows: data[:run_level_rows]
|
|
263
296
|
)
|
|
264
297
|
end
|
|
265
298
|
private :payload_from
|
|
@@ -283,7 +316,8 @@ module Rigor
|
|
|
283
316
|
return_summaries: payload.return_summaries,
|
|
284
317
|
param_table: payload.param_table,
|
|
285
318
|
effect_collections: payload.effect_collections,
|
|
286
|
-
effects_identity: payload.effects_identity
|
|
319
|
+
effects_identity: payload.effects_identity,
|
|
320
|
+
run_level_rows: payload.run_level_rows
|
|
287
321
|
)
|
|
288
322
|
blob = Zlib::Deflate.deflate(raw)
|
|
289
323
|
tmp = "#{@path}.#{Process.pid}.tmp"
|
|
@@ -20,9 +20,6 @@ module Rigor
|
|
|
20
20
|
class RbsClassAncestorTable < RbsCacheProducer
|
|
21
21
|
PRODUCER_ID = "rbs.class_ancestor_table"
|
|
22
22
|
|
|
23
|
-
# @param loader [Rigor::Environment::RbsLoader]
|
|
24
|
-
# @param store [Rigor::Cache::Store]
|
|
25
|
-
# @return [Hash{String => Array<String>}]
|
|
26
23
|
def self.compute(loader)
|
|
27
24
|
table = {}
|
|
28
25
|
loader.each_known_class_name do |name|
|
|
@@ -20,9 +20,6 @@ module Rigor
|
|
|
20
20
|
class RbsClassTypeParamNames < RbsCacheProducer
|
|
21
21
|
PRODUCER_ID = "rbs.class_type_param_names"
|
|
22
22
|
|
|
23
|
-
# @param loader [Rigor::Environment::RbsLoader]
|
|
24
|
-
# @param store [Rigor::Cache::Store]
|
|
25
|
-
# @return [Hash{String => Array<Symbol>}]
|
|
26
23
|
def self.compute(loader)
|
|
27
24
|
table = {}
|
|
28
25
|
loader.each_known_class_name do |name|
|
|
@@ -15,9 +15,6 @@ module Rigor
|
|
|
15
15
|
class RbsConstantTable < RbsCacheProducer
|
|
16
16
|
PRODUCER_ID = "rbs.constant_type_table"
|
|
17
17
|
|
|
18
|
-
# @param loader [Rigor::Environment::RbsLoader]
|
|
19
|
-
# @param store [Rigor::Cache::Store]
|
|
20
|
-
# @return [Hash{String => Rigor::Type}]
|
|
21
18
|
def self.compute(loader)
|
|
22
19
|
table = {}
|
|
23
20
|
loader.each_constant_decl do |name, entry|
|
|
@@ -12,13 +12,11 @@ module Rigor
|
|
|
12
12
|
# slots, so factoring the construction here keeps the producers small and ensures invalidation behaves
|
|
13
13
|
# identically across them.
|
|
14
14
|
module RbsDescriptor
|
|
15
|
-
# @param loader [Rigor::Environment::RbsLoader]
|
|
16
|
-
# @return [Rigor::Cache::Descriptor]
|
|
17
15
|
def self.build(loader)
|
|
18
16
|
Descriptor.new(
|
|
19
17
|
gems: [rbs_gem_entry],
|
|
20
18
|
files: file_entries(loader),
|
|
21
|
-
configs: config_entries(loader)
|
|
19
|
+
configs: config_entries(loader) + env_only_config_entries(loader)
|
|
22
20
|
)
|
|
23
21
|
end
|
|
24
22
|
|
|
@@ -26,8 +24,9 @@ module Rigor
|
|
|
26
24
|
# `gems` + `configs` ({Runner#run_key_descriptor}); the RBS signature-tree `files` are read solely on a
|
|
27
25
|
# MISS, by the dependency descriptor ({Runner#run_dependency_descriptor}). So a warm HIT never digests
|
|
28
26
|
# the (large, vendored) RBS tree. {RunDescriptor} is NOT a {Descriptor} — it is never composed, hashed,
|
|
29
|
-
# or `==`'d, only its
|
|
30
|
-
# / `configs`
|
|
27
|
+
# or `==`'d, only its four readers are consulted — so deferring `files` costs no soundness, and `gems`
|
|
28
|
+
# / `configs` match {.build}'s shared slots (the key is unchanged; the one slot the env key adds on
|
|
29
|
+
# top, {.env_only_config_entries}, is never read here).
|
|
31
30
|
def self.build_run(loader)
|
|
32
31
|
RunDescriptor.new(loader: loader, gems: [rbs_gem_entry], configs: config_entries(loader))
|
|
33
32
|
end
|
|
@@ -38,19 +37,47 @@ module Rigor
|
|
|
38
37
|
[libraries_entry(loader.libraries), virtual_rbs_entry(loader)].compact
|
|
39
38
|
end
|
|
40
39
|
|
|
40
|
+
# Issue #610 — the slots only the env-cache KEY reads, on top of {.config_entries}. Which of the
|
|
41
|
+
# loader's `signature_paths:` are DEFERRED (a bundled plugin's `sig/`, loaded last and allowed to
|
|
42
|
+
# stand down against a colliding generic arity) changes the env built from byte-identical files, so
|
|
43
|
+
# the partition belongs in the key: moving a plugin's `sig/` between `plugins:` and an explicit
|
|
44
|
+
# `signature_paths:` entry changes no file, and an env cached before the producer honoured the
|
|
45
|
+
# partition must read as a miss once. Kept OUT of {.config_entries} deliberately — the run-result
|
|
46
|
+
# key already digests the whole resolved configuration (`RunCacheKey`), and its boot-slimming probe
|
|
47
|
+
# reconstructs {.config_entries} without loading a plugin, so an entry there that it cannot rebuild
|
|
48
|
+
# would turn the warm fast lane into a permanent miss on every project that enables a bundled plugin.
|
|
49
|
+
def self.env_only_config_entries(loader)
|
|
50
|
+
[deferred_signature_paths_entry(loader)].compact
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.deferred_signature_paths_entry(loader)
|
|
54
|
+
return nil unless loader.respond_to?(:deferred_signature_paths)
|
|
55
|
+
|
|
56
|
+
deferred = Array(loader.deferred_signature_paths).map(&:to_s).sort
|
|
57
|
+
return nil if deferred.empty?
|
|
58
|
+
|
|
59
|
+
Descriptor::ConfigEntry.new(
|
|
60
|
+
key: "rbs.deferred_signature_paths",
|
|
61
|
+
value_hash: Digest::SHA256.hexdigest(deferred.join("\n"))
|
|
62
|
+
)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private_class_method :deferred_signature_paths_entry
|
|
66
|
+
|
|
41
67
|
# Public (ADR-87 WD4) so the boot-slimming run-cache probe reconstructs the identical `gems` +
|
|
42
68
|
# `rbs.libraries` key slots the runner writes, from the config-derived library list, without a loader.
|
|
43
69
|
def self.rbs_gem_entry
|
|
44
70
|
Descriptor::GemEntry.new(name: "rbs", requirement: ">= 0", locked: ::RBS::VERSION.to_s)
|
|
45
71
|
end
|
|
46
72
|
|
|
47
|
-
# @param comparator
|
|
73
|
+
# @param comparator — `:digest` (default) for the env-cache KEY descriptor ({.build}), where the
|
|
48
74
|
# value must be deterministic; `:stat` (ADR-87 WD1) for the validation-only run-dependency descriptor
|
|
49
75
|
# ({RunDescriptor#files}), where the stat tier short-circuits the SHA-256 on an unmoved file.
|
|
50
76
|
def self.file_entries(loader, comparator: :digest)
|
|
51
77
|
roots = loader.signature_paths +
|
|
52
78
|
Rigor::Environment::RbsLoader.vendored_gem_sig_paths +
|
|
53
|
-
Rigor::Environment::RbsLoader.core_overlay_sig_paths
|
|
79
|
+
Rigor::Environment::RbsLoader.core_overlay_sig_paths +
|
|
80
|
+
Rigor::Environment::RbsLoader.capability_role_sig_paths
|
|
54
81
|
roots.flat_map do |root|
|
|
55
82
|
next [] unless root.directory?
|
|
56
83
|
|
|
@@ -65,7 +92,40 @@ module Rigor
|
|
|
65
92
|
end
|
|
66
93
|
end
|
|
67
94
|
|
|
68
|
-
#
|
|
95
|
+
# Issue #979 — the directory-LISTING rows for the signature roots, one {Descriptor::GlobEntry} per
|
|
96
|
+
# root over `**/*.rbs`. {.file_entries} answers "did any signature file I read change", which is a
|
|
97
|
+
# question only about files that existed when the run recorded its dependencies; a `sig/roles.rbs`
|
|
98
|
+
# written afterwards is in no row, so the ADR-45 run-result slot validated fresh and the warm run kept
|
|
99
|
+
# serving diagnostics computed without it. A glob row is the same edge {Plugin::IoBoundary} records
|
|
100
|
+
# for a listed directory (#954): re-globbing on the next run sees the appearance, and one row per root
|
|
101
|
+
# (not per file) keeps the cost a single `Dir.glob`.
|
|
102
|
+
#
|
|
103
|
+
# The rows are `:names` mode, not the default `:stat`: the question they add is which signature files
|
|
104
|
+
# EXIST, and every edit to one of them is already carried by that file's own ADR-87 WD1 `:stat` row —
|
|
105
|
+
# which survives a moved stat tuple by falling back to its recorded content digest. A stat-mode glob
|
|
106
|
+
# would not, so a `git checkout`, a `bundle install`, or a CI run with a restored cache over a fresh
|
|
107
|
+
# checkout — none of which changes a byte of RBS — would turn every warm run into a full re-analysis.
|
|
108
|
+
# Names mode also reads no stat, so it neither pays for nor perturbs the per-run validation-stat memo.
|
|
109
|
+
#
|
|
110
|
+
# Scoped to the loader's own roots — the project's `signature_paths:` (including the auto-detected
|
|
111
|
+
# `sig/`), the bundled-plugin `sig/` trees (ADR-25), the bundle walk, `rbs collection`, the ADR-72
|
|
112
|
+
# overlays. Rigor's own `data/` trees ({RbsLoader.vendored_gem_sig_paths}, `.core_overlay_sig_paths`,
|
|
113
|
+
# `.capability_role_sig_paths`) are engine-owned: a file appears under one only when the engine tree is
|
|
114
|
+
# edited, which normally arrives with the `lib/` change that reads it and so re-keys every
|
|
115
|
+
# computed-value slot through {EngineSource}. They get file rows and no glob — a glob there would cost
|
|
116
|
+
# every project a stat walk of the vendored gem-signature tree per warm run to catch an
|
|
117
|
+
# engine-development edit.
|
|
118
|
+
def self.glob_entries(loader)
|
|
119
|
+
# Deduplicated by path: a root reachable twice (an explicit `signature_paths:` entry that is also a
|
|
120
|
+
# bundled plugin's `sig/`, #610) would otherwise contribute two rows whose stat signatures race.
|
|
121
|
+
loader.signature_paths.uniq(&:to_s).filter_map do |root|
|
|
122
|
+
next unless root.directory?
|
|
123
|
+
|
|
124
|
+
Descriptor::GlobEntry.compute(root: root.to_s, pattern: File.join("**", "*.rbs"), mode: :names)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# @param library_names — the loader's merged library list (or, on the WD4 probe
|
|
69
129
|
# path, `Environment::DEFAULT_LIBRARIES + config.libraries` reconstructed without a loader).
|
|
70
130
|
def self.libraries_entry(library_names)
|
|
71
131
|
sorted = library_names.map(&:to_s).sort
|
|
@@ -93,10 +153,11 @@ module Rigor
|
|
|
93
153
|
|
|
94
154
|
private_class_method :virtual_rbs_entry
|
|
95
155
|
|
|
96
|
-
# The lazy-files run descriptor {RbsDescriptor.build_run} returns. Exposes the
|
|
156
|
+
# The lazy-files run descriptor {RbsDescriptor.build_run} returns. Exposes the four readers the
|
|
97
157
|
# run-diagnostics cache consults — `gems` + `configs` are supplied eagerly (they feed the cache KEY,
|
|
98
|
-
# and are cheap); `files` (the RBS signature-tree digests
|
|
99
|
-
# first access and memoised, so a warm HIT
|
|
158
|
+
# and are cheap); `files` (the RBS signature-tree digests) and `globs` (#979, the per-root listing
|
|
159
|
+
# rows) are read only on a MISS, computed once on first access and memoised, so a warm HIT pays for
|
|
160
|
+
# neither.
|
|
100
161
|
class RunDescriptor
|
|
101
162
|
attr_reader :gems, :configs
|
|
102
163
|
|
|
@@ -106,6 +167,13 @@ module Rigor
|
|
|
106
167
|
@configs = configs
|
|
107
168
|
end
|
|
108
169
|
|
|
170
|
+
# Issue #979 — one directory-listing row per signature root, so a `.rbs` file APPEARING under one
|
|
171
|
+
# (or vanishing from it) invalidates the run-result slot. Memoised for the same reason `files` is:
|
|
172
|
+
# a collecting run asks twice about the same post-run world.
|
|
173
|
+
def globs
|
|
174
|
+
@globs ||= RbsDescriptor.glob_entries(@loader)
|
|
175
|
+
end
|
|
176
|
+
|
|
109
177
|
def files
|
|
110
178
|
# ADR-87 WD1 — this descriptor is validated (never a cache key), so the RBS signature tree rides the
|
|
111
179
|
# stat-then-digest `:stat` tier: a warm run stat-checks the (large, vendored) tree instead of
|
|
@@ -22,14 +22,18 @@ module Rigor
|
|
|
22
22
|
class RbsEnvironment < RbsCacheProducer
|
|
23
23
|
PRODUCER_ID = "rbs.environment"
|
|
24
24
|
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
25
|
+
# Issue #610 — the deferred (plugin-contributed) subset rides through too. This is the build path every
|
|
26
|
+
# cached run takes: a cache store is the CLI default and only `--no-cache` reaches the loader's own
|
|
27
|
+
# `build_env`, so a list threaded through the loader but not through here ran the arity stand-down on
|
|
28
|
+
# no real `rigor check` at all — 0.3.8 shipped exactly that, behind a green gate built over a
|
|
29
|
+
# store-less loader. Any input `build_env_for` takes MUST be passed from here as well.
|
|
28
30
|
def self.compute(loader)
|
|
29
31
|
Rigor::Environment::RbsLoader.build_env_for(
|
|
30
32
|
libraries: loader.libraries,
|
|
31
33
|
signature_paths: loader.signature_paths,
|
|
32
|
-
virtual_rbs: loader.respond_to?(:virtual_rbs) ? loader.virtual_rbs : []
|
|
34
|
+
virtual_rbs: loader.respond_to?(:virtual_rbs) ? loader.virtual_rbs : [],
|
|
35
|
+
deferred_signature_paths:
|
|
36
|
+
loader.respond_to?(:deferred_signature_paths) ? loader.deferred_signature_paths : []
|
|
33
37
|
)
|
|
34
38
|
end
|
|
35
39
|
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
require "rbs"
|
|
4
4
|
|
|
5
|
+
require_relative "annotation_location"
|
|
6
|
+
|
|
5
7
|
# Adds `_dump` / `_load` to {RBS::Location} so an `RBS::Environment` (and its transitive AST nodes, all of
|
|
6
8
|
# which carry Locations) round-trips through `Marshal`. The rbs gem's C-extension `RBS::Location` ships
|
|
7
9
|
# without the Marshal hooks; until rbs grows them upstream this patch is the minimal monkey-patch the v0.0.9
|
|
@@ -31,6 +33,25 @@ require "rbs"
|
|
|
31
33
|
# than a cold run does. ADR-6's store never evicts, so that would persist. `Cache::Store::FORMAT_VERSION`
|
|
32
34
|
# is therefore bumped to 3: `PAYLOAD_ABI_VERSION` already rebuilds across a release, and the bump closes
|
|
33
35
|
# the same-version window too.
|
|
36
|
+
# - `RBS::AST::Annotation` carries its own `marshal_dump` / `marshal_load`, which keep the annotation's
|
|
37
|
+
# POSITION as well as its file (issue #799). "Nothing reads positions" was never quite true: the two
|
|
38
|
+
# `conforms-to` rows — `rbs_extended.unsatisfied-conformance` and `dynamic.rbs-extended.unresolved` —
|
|
39
|
+
# are reported AT the directive, because there is no Ruby `def` a missing interface method could be
|
|
40
|
+
# reported at, so both read `start_line` / `start_column` off an annotation's location. (They are the
|
|
41
|
+
# only readers: {Rigor::RbsExtended::EnvelopeScanner} positions `effect.unknown-label` at an annotation
|
|
42
|
+
# too, but reaches it by parsing the project's own `.rbs` rather than the built env — refusing this very
|
|
43
|
+
# loss is one of the two reasons it does.) Cold the row is `sig/buffer.rbs:6:1`; through a `_dump`ed
|
|
44
|
+
# location it collapsed to `1:1`, which made `--verify-incremental` fail outright on any project carrying
|
|
45
|
+
# an unsatisfied directive (the replica normalises rows by position, and only one side of the comparison
|
|
46
|
+
# runs against the cached env) and made a warm `--incremental` run move a row on a tree that had not
|
|
47
|
+
# changed. The carry is scoped to annotations rather than done in `_dump` for the reason the paragraph
|
|
48
|
+
# above gives: a Location hangs off every AST node, and carrying its position measured +2.9% on Rigor's
|
|
49
|
+
# own env (9,941K to 10,229K) on top of the names. An annotation is rare by comparison — 18 of them in
|
|
50
|
+
# that same env — so the same carry costs +1.4K there, which is the whole argument for scoping it here
|
|
51
|
+
# rather than widening `_dump`. `Cache::Store::FORMAT_VERSION` is bumped to 4 for the same reason it was
|
|
52
|
+
# bumped to 3: a pre-change blob still loads (Marshal encodes an ivar dump and a `marshal_dump` payload
|
|
53
|
+
# differently, and only the latter reaches `marshal_load`), so without the bump a stale blob would keep
|
|
54
|
+
# reporting the moved position indefinitely.
|
|
34
55
|
#
|
|
35
56
|
# Idempotent: the guard checks `method_defined?(:_dump)` so requiring this file twice (or against an upstream
|
|
36
57
|
# rbs that adds Marshal hooks itself) is a no-op.
|
|
@@ -67,6 +88,24 @@ module RBS
|
|
|
67
88
|
end
|
|
68
89
|
end
|
|
69
90
|
|
|
91
|
+
module AST
|
|
92
|
+
class Annotation
|
|
93
|
+
# Carries the annotation's POSITION across the cache, not just its file. See the header's fourth
|
|
94
|
+
# bullet for why this one AST node opts out of the position-dropping `RBS::Location#_dump` above.
|
|
95
|
+
unless method_defined?(:marshal_dump)
|
|
96
|
+
def marshal_dump
|
|
97
|
+
[string, Rigor::Cache::AnnotationLocation.dump(location)]
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def marshal_load(payload)
|
|
101
|
+
dumped_string, dumped_location = payload
|
|
102
|
+
@string = dumped_string
|
|
103
|
+
@location = Rigor::Cache::AnnotationLocation.load(dumped_location)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
70
109
|
class Namespace
|
|
71
110
|
unless method_defined?(:_dump)
|
|
72
111
|
def _dump(_)
|
|
@@ -18,9 +18,6 @@ module Rigor
|
|
|
18
18
|
class RbsKnownClassNames < RbsCacheProducer
|
|
19
19
|
PRODUCER_ID = "rbs.known_class_names"
|
|
20
20
|
|
|
21
|
-
# @param loader [Rigor::Environment::RbsLoader]
|
|
22
|
-
# @param store [Rigor::Cache::Store]
|
|
23
|
-
# @return [Set<String>]
|
|
24
21
|
def self.compute(loader)
|
|
25
22
|
names = Set.new
|
|
26
23
|
loader.each_known_class_name { |name| names << name }
|