rigortype 0.4.5 → 0.4.7
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 +2 -2
- data/data/gem_overlay/activesupport/core_ext.rbs +16 -13
- data/data/vendored_gem_sigs/bundler/bundler.rbs +1 -1
- data/data/vendored_gem_sigs/rubygems/rubygems_extras.rbs +4 -3
- data/docs/handbook/01-getting-started.md +5 -2
- data/docs/handbook/11-sig-gen.md +61 -5
- data/docs/handbook/appendix-phpstan.md +4 -4
- data/docs/manual/02-cli-reference.md +192 -27
- data/docs/manual/03-configuration.md +38 -4
- data/docs/manual/04-diagnostics.md +1 -1
- data/docs/manual/06-baseline.md +6 -4
- data/docs/manual/09-editor-integration.md +13 -2
- data/docs/manual/10-mcp-server.md +47 -3
- data/docs/manual/12-caching.md +9 -1
- data/docs/manual/plugins/rigor-actionmailer.md +30 -0
- data/docs/manual/plugins/rigor-actionpack.md +49 -11
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +20 -1
- data/docs/manual/plugins/rigor-devise.md +15 -0
- data/docs/manual/plugins/rigor-rspec.md +2 -1
- data/lib/rigor/analysis/baseline.rb +24 -27
- data/lib/rigor/analysis/buffer_binding.rb +14 -0
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +5 -6
- data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +4 -4
- data/lib/rigor/analysis/check_rules/duplicate_hash_key_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/inferred_param_guard.rb +105 -12
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +143 -15
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +4 -1
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +5 -8
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +1 -1
- data/lib/rigor/analysis/check_rules/rbs_receiver_surface.rb +66 -3
- data/lib/rigor/analysis/check_rules/rebinding_block_callees/dispatch.rb +112 -0
- data/lib/rigor/analysis/check_rules/rebinding_block_callees.rb +394 -0
- data/lib/rigor/analysis/check_rules/return_in_ensure_collector.rb +1 -2
- data/lib/rigor/analysis/check_rules/ruby_deprecations.rb +7 -0
- data/lib/rigor/analysis/check_rules/rule_ids.rb +1 -1
- data/lib/rigor/analysis/check_rules/rule_walk.rb +9 -7
- data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +3 -4
- data/lib/rigor/analysis/check_rules/special_global_setters.rb +3 -3
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +53 -2
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules.rb +217 -52
- data/lib/rigor/analysis/crash_signature.rb +2 -2
- data/lib/rigor/analysis/dependency_recorder.rb +15 -4
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +14 -3
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +1 -1
- data/lib/rigor/analysis/dependency_source_inference/index.rb +6 -8
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +4 -4
- data/lib/rigor/analysis/edit_replay.rb +154 -0
- data/lib/rigor/analysis/fact_store.rb +3 -3
- data/lib/rigor/analysis/incremental.rb +37 -0
- data/lib/rigor/analysis/incremental_run_slot/write_guard.rb +2 -2
- data/lib/rigor/analysis/incremental_run_slot.rb +2 -2
- data/lib/rigor/analysis/incremental_session.rb +202 -43
- data/lib/rigor/analysis/path_expansion.rb +41 -0
- data/lib/rigor/analysis/require_relative_closure.rb +100 -0
- data/lib/rigor/analysis/rule_catalog.rb +7 -3
- data/lib/rigor/analysis/run_disclosure_credit.rb +80 -0
- data/lib/rigor/analysis/run_disclosure_ledger.rb +155 -0
- data/lib/rigor/analysis/run_stats.rb +2 -2
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +8 -4
- data/lib/rigor/analysis/runner/declaration_position.rb +1 -1
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +204 -96
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +1 -1
- data/lib/rigor/analysis/runner/pool_coordinator.rb +157 -320
- data/lib/rigor/analysis/runner/project_pre_passes.rb +48 -6
- data/lib/rigor/analysis/runner/run_level_facts.rb +304 -0
- data/lib/rigor/analysis/runner/run_snapshots.rb +44 -54
- data/lib/rigor/analysis/runner/scan_environment.rb +51 -0
- data/lib/rigor/analysis/runner/worker_payload.rb +36 -0
- data/lib/rigor/analysis/runner.rb +233 -120
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +1 -1
- data/lib/rigor/analysis/template_unit_positions.rb +2 -3
- data/lib/rigor/analysis/template_units.rb +9 -1
- data/lib/rigor/analysis/worker_session.rb +38 -33
- data/lib/rigor/bleeding_edge.rb +3 -6
- data/lib/rigor/builtins/imported_refinements.rb +6 -8
- data/lib/rigor/builtins/predefined_constant_refinements.rb +1 -1
- data/lib/rigor/builtins/regex_refinement.rb +4 -6
- data/lib/rigor/cache/descriptor.rb +6 -5
- data/lib/rigor/cache/incremental_snapshot.rb +60 -18
- data/lib/rigor/cache/rbs_cache_producer.rb +2 -2
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +1 -1
- data/lib/rigor/cache/rbs_class_type_param_names.rb +2 -2
- data/lib/rigor/cache/rbs_constant_table.rb +1 -1
- data/lib/rigor/cache/rbs_descriptor.rb +54 -3
- data/lib/rigor/cache/rbs_environment.rb +4 -1
- data/lib/rigor/cache/rbs_environment_marshal_patch.rb +2 -2
- data/lib/rigor/cache/rbs_known_class_names.rb +1 -1
- data/lib/rigor/cache/store.rb +11 -10
- data/lib/rigor/ci_detector.rb +1 -1
- data/lib/rigor/cli/annotate_command.rb +24 -19
- data/lib/rigor/cli/baseline_command.rb +145 -55
- data/lib/rigor/cli/catalogue.rb +256 -0
- data/lib/rigor/cli/check_command.rb +188 -93
- data/lib/rigor/cli/check_runner_factory.rb +2 -2
- data/lib/rigor/cli/command.rb +15 -1
- data/lib/rigor/cli/coverage_command.rb +21 -8
- data/lib/rigor/cli/coverage_mutation.rb +5 -7
- data/lib/rigor/cli/coverage_renderer.rb +2 -1
- data/lib/rigor/cli/coverage_scan.rb +3 -5
- data/lib/rigor/cli/diff_command.rb +27 -21
- data/lib/rigor/cli/docs_command.rb +1 -2
- data/lib/rigor/cli/doctor_command.rb +12 -12
- data/lib/rigor/cli/effects_command.rb +50 -40
- data/lib/rigor/cli/effects_diff_renderer.rb +18 -17
- data/lib/rigor/cli/effects_explain_renderer.rb +13 -12
- data/lib/rigor/cli/effects_renderer.rb +2 -1
- data/lib/rigor/cli/effects_snapshot_command.rb +18 -17
- data/lib/rigor/cli/explain_command.rb +18 -8
- data/lib/rigor/cli/fused_protection_renderer.rb +2 -1
- data/lib/rigor/cli/json_document.rb +41 -0
- data/lib/rigor/cli/lens_command.rb +17 -13
- data/lib/rigor/cli/lsp_command.rb +250 -23
- data/lib/rigor/cli/mcp_command.rb +14 -8
- data/lib/rigor/cli/mutation_fork_scan.rb +1 -1
- data/lib/rigor/cli/mutation_protection_renderer.rb +3 -2
- data/lib/rigor/cli/options.rb +60 -4
- data/lib/rigor/cli/plugin_command.rb +93 -46
- data/lib/rigor/cli/plugins_command.rb +22 -18
- data/lib/rigor/cli/plugins_renderer.rb +34 -8
- data/lib/rigor/cli/protection_fork_scan.rb +2 -2
- data/lib/rigor/cli/protection_renderer.rb +2 -1
- data/lib/rigor/cli/show_bleedingedge_command.rb +23 -16
- data/lib/rigor/cli/sig_gen_command.rb +130 -34
- data/lib/rigor/cli/skill_command.rb +32 -3
- data/lib/rigor/cli/skill_deep_probe.rb +1 -1
- data/lib/rigor/cli/skill_describe.rb +1 -1
- data/lib/rigor/cli/trace_command.rb +14 -9
- data/lib/rigor/cli/triage_command.rb +10 -11
- data/lib/rigor/cli/triage_renderer.rb +2 -1
- data/lib/rigor/cli/type_of_command.rb +18 -12
- data/lib/rigor/cli/type_of_project_scope.rb +24 -0
- data/lib/rigor/cli/type_of_renderer.rb +4 -1
- data/lib/rigor/cli/type_scan_command.rb +14 -9
- data/lib/rigor/cli/type_scan_renderer.rb +2 -1
- data/lib/rigor/cli/unused_command.rb +27 -17
- data/lib/rigor/cli/upgrade_command.rb +5 -0
- data/lib/rigor/cli.rb +209 -54
- data/lib/rigor/config_audit.rb +17 -6
- data/lib/rigor/configuration/severity_profile.rb +5 -5
- data/lib/rigor/configuration.rb +86 -34
- data/lib/rigor/effects/definition_context.rb +0 -2
- data/lib/rigor/effects/envelope.rb +1 -1
- data/lib/rigor/effects/framework_units.rb +1 -1
- data/lib/rigor/effects/mutation_classifier.rb +4 -7
- data/lib/rigor/effects/propagator.rb +1 -1
- data/lib/rigor/effects/registry.rb +2 -2
- data/lib/rigor/effects/snapshot.rb +1 -1
- data/lib/rigor/effects/taint_cause.rb +0 -2
- data/lib/rigor/effects/unit_scan.rb +9 -13
- data/lib/rigor/environment/bundle_sig_discovery.rb +5 -9
- data/lib/rigor/environment/class_registry.rb +3 -3
- data/lib/rigor/environment/core_root.rb +77 -0
- data/lib/rigor/environment/default_libraries.rb +1 -1
- data/lib/rigor/environment/deferred_signature_plan.rb +283 -0
- data/lib/rigor/environment/gated_signature_guard.rb +1 -1
- data/lib/rigor/environment/gated_signature_plan.rb +5 -2
- data/lib/rigor/environment/lockfile_resolver.rb +28 -12
- data/lib/rigor/environment/member_consistency/comparator.rb +18 -1
- data/lib/rigor/environment/member_consistency.rb +56 -7
- data/lib/rigor/environment/missing_gem_constant_index.rb +3 -2
- data/lib/rigor/environment/project_path_gems.rb +124 -0
- data/lib/rigor/environment/rbs_hierarchy.rb +6 -15
- data/lib/rigor/environment/rbs_loader.rb +592 -70
- data/lib/rigor/environment/reflection.rb +7 -7
- data/lib/rigor/environment/required_features.rb +136 -32
- data/lib/rigor/environment/ruby_library_roots.rb +122 -0
- data/lib/rigor/environment/vendored_signature_plan.rb +153 -0
- data/lib/rigor/environment.rb +44 -11
- data/lib/rigor/flow_contribution/merger.rb +4 -4
- data/lib/rigor/inference/acceptance.rb +93 -32
- data/lib/rigor/inference/block_parameter_binder.rb +2 -3
- data/lib/rigor/inference/block_run_count.rb +178 -0
- data/lib/rigor/inference/budget_trace.rb +8 -2
- data/lib/rigor/inference/builtins/exception_catalog.rb +2 -2
- data/lib/rigor/inference/builtins/numeric_catalog.rb +2 -5
- data/lib/rigor/inference/builtins/random_catalog.rb +2 -2
- data/lib/rigor/inference/callee_mutation_chain.rb +126 -0
- data/lib/rigor/inference/callee_write_census.rb +815 -0
- data/lib/rigor/inference/construction_escape.rb +217 -0
- data/lib/rigor/inference/declaration_walk/traversal.rb +1 -1
- data/lib/rigor/inference/deep_erasure.rb +170 -0
- data/lib/rigor/inference/def_handle.rb +1 -1
- data/lib/rigor/inference/def_node_resolver.rb +1 -1
- data/lib/rigor/inference/def_return_typer.rb +204 -12
- data/lib/rigor/inference/definer_resolution.rb +21 -5
- data/lib/rigor/inference/definers_index.rb +106 -0
- data/lib/rigor/inference/direct_ivar_writes.rb +300 -0
- data/lib/rigor/inference/element_read_widening.rb +49 -3
- data/lib/rigor/inference/error_info.rb +17 -3
- data/lib/rigor/inference/expression_typer.rb +173 -57
- data/lib/rigor/inference/external_ancestor_resolution.rb +3 -4
- data/lib/rigor/inference/global_write_census.rb +110 -1
- data/lib/rigor/inference/global_writer_reach.rb +260 -0
- data/lib/rigor/inference/hkt_body.rb +1 -2
- data/lib/rigor/inference/hkt_body_parser.rb +3 -5
- data/lib/rigor/inference/hkt_reducer.rb +2 -2
- data/lib/rigor/inference/hkt_registry.rb +3 -5
- data/lib/rigor/inference/indexed_narrowing.rb +4 -7
- data/lib/rigor/inference/intervening_ivar_reset.rb +26 -4
- data/lib/rigor/inference/ivar_writer_census.rb +246 -0
- data/lib/rigor/inference/key_presence_guard.rb +2 -1
- data/lib/rigor/inference/loop_value_record.rb +57 -0
- data/lib/rigor/inference/match_rebinding/frame.rb +65 -0
- data/lib/rigor/inference/match_rebinding/yielding_match.rb +45 -0
- data/lib/rigor/inference/match_rebinding.rb +11 -1
- data/lib/rigor/inference/memo_audit.rb +55 -0
- data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/argument_distribution.rb +40 -0
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +113 -12
- data/lib/rigor/inference/method_dispatcher/contested_overloads.rb +89 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +7 -3
- data/lib/rigor/inference/method_dispatcher/no_match_fallback.rb +54 -0
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +39 -27
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +203 -17
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/self_substitute.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +59 -24
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +83 -20
- data/lib/rigor/inference/method_dispatcher/singleton_folding.rb +0 -1
- data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +50 -17
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +5 -5
- data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +4 -6
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher.rb +109 -29
- data/lib/rigor/inference/module_function_state/spellings.rb +64 -0
- data/lib/rigor/inference/module_function_state.rb +23 -1
- data/lib/rigor/inference/multi_target_binder.rb +1 -1
- data/lib/rigor/inference/mutation_rejoin.rb +240 -4
- data/lib/rigor/inference/mutation_widening.rb +162 -29
- data/lib/rigor/inference/narrowing.rb +113 -38
- data/lib/rigor/inference/object_mixins.rb +13 -1
- data/lib/rigor/inference/optimistic_origin.rb +1 -1
- data/lib/rigor/inference/out_buffer_mutation.rb +72 -0
- data/lib/rigor/inference/parameter_inference_collector.rb +5 -6
- data/lib/rigor/inference/pre_eval_constants.rb +1 -1
- data/lib/rigor/inference/project_method_ownership.rb +6 -3
- data/lib/rigor/inference/project_seed_tables.rb +2 -1
- data/lib/rigor/inference/project_yielder.rb +122 -0
- data/lib/rigor/inference/receiver_alias.rb +20 -0
- data/lib/rigor/inference/refined_dispatch/constructed_class.rb +3 -1
- data/lib/rigor/inference/refined_dispatch/own_method.rb +2 -1
- data/lib/rigor/inference/remover_holder_scan.rb +233 -0
- data/lib/rigor/inference/remover_narrowing.rb +224 -0
- data/lib/rigor/inference/rewrite_mutation.rb +53 -2
- data/lib/rigor/inference/scope_indexer/certainty.rb +9 -1
- data/lib/rigor/inference/scope_indexer/constant_ivar_value.rb +93 -0
- data/lib/rigor/inference/scope_indexer/declared_ivar_types.rb +64 -0
- data/lib/rigor/inference/scope_indexer/declared_param_writes.rb +205 -0
- data/lib/rigor/inference/scope_indexer/derived_param_value.rb +112 -0
- data/lib/rigor/inference/scope_indexer/empty_seed.rb +99 -0
- data/lib/rigor/inference/scope_indexer/ivar_contributions.rb +135 -0
- data/lib/rigor/inference/scope_indexer/unseen_ivar_writers.rb +133 -0
- data/lib/rigor/inference/scope_indexer.rb +614 -146
- data/lib/rigor/inference/self_call_ivar_writes.rb +101 -17
- data/lib/rigor/inference/set_mutation.rb +189 -0
- data/lib/rigor/inference/singleton_hook_decline.rb +1 -2
- data/lib/rigor/inference/statement_evaluator.rb +3036 -278
- data/lib/rigor/inference/struct_fold_safety.rb +4 -6
- data/lib/rigor/inference/synthetic_method_index.rb +23 -0
- data/lib/rigor/inference/synthetic_method_scanner/project_members.rb +130 -0
- data/lib/rigor/inference/synthetic_method_scanner.rb +73 -14
- data/lib/rigor/inference/toplevel_def_census.rb +59 -0
- data/lib/rigor/inference/unknown_store_widening.rb +103 -4
- data/lib/rigor/inference/unthreaded_rebinds.rb +2 -3
- data/lib/rigor/inference/void_tail_summary.rb +2 -1
- data/lib/rigor/language_server/buffer_table.rb +9 -3
- data/lib/rigor/language_server/completion_provider.rb +26 -20
- data/lib/rigor/language_server/config_warning_announcer.rb +28 -0
- data/lib/rigor/language_server/diagnostic_publisher.rb +28 -9
- data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
- data/lib/rigor/language_server/folding_range_provider.rb +1 -2
- data/lib/rigor/language_server/hover_provider.rb +1 -7
- data/lib/rigor/language_server/hover_renderer.rb +6 -8
- data/lib/rigor/language_server/project_context.rb +98 -4
- data/lib/rigor/language_server/publish_batcher.rb +3 -4
- data/lib/rigor/language_server/selection_range_provider.rb +2 -4
- data/lib/rigor/language_server/server.rb +12 -6
- data/lib/rigor/language_server/signature_help_provider.rb +4 -4
- data/lib/rigor/lens/plugins.rb +1 -1
- data/lib/rigor/mcp/server.rb +82 -3
- data/lib/rigor/mcp.rb +1 -1
- data/lib/rigor/plugin/access_denied_error.rb +1 -2
- data/lib/rigor/plugin/base.rb +26 -11
- data/lib/rigor/plugin/bundled_catalog.rb +1 -12
- data/lib/rigor/plugin/io_boundary.rb +1 -1
- data/lib/rigor/plugin/loader.rb +25 -8
- data/lib/rigor/plugin/macro/heredoc_template.rb +7 -8
- data/lib/rigor/plugin/macro/trait_registry.rb +6 -9
- data/lib/rigor/plugin/manifest.rb +38 -16
- data/lib/rigor/plugin/registry.rb +41 -3
- data/lib/rigor/plugin/services.rb +2 -3
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +11 -0
- data/lib/rigor/plugin/trust_policy.rb +2 -2
- data/lib/rigor/plugin/type_node_resolver.rb +2 -4
- data/lib/rigor/plugin.rb +6 -8
- data/lib/rigor/plugin_gap_advisory.rb +5 -1
- data/lib/rigor/project_environment.rb +16 -2
- data/lib/rigor/protection/analysis_guard.rb +1 -1
- data/lib/rigor/protection/discovery_seed.rb +96 -2
- data/lib/rigor/protection/mutator.rb +1 -1
- data/lib/rigor/rbs_extended/envelope_scanner.rb +4 -6
- data/lib/rigor/rbs_extended/hkt_directives.rb +6 -10
- data/lib/rigor/rbs_extended/reporter.rb +27 -3
- data/lib/rigor/rbs_extended.rb +2 -3
- data/lib/rigor/reflection/constant_ancestors.rb +5 -3
- data/lib/rigor/rooted_glob.rb +25 -2
- data/lib/rigor/run_scoped_slots.rb +38 -0
- data/lib/rigor/runtime/jit.rb +1 -1
- data/lib/rigor/scope/discovery_index.rb +19 -6
- data/lib/rigor/scope/resolution_chain.rb +3 -1
- data/lib/rigor/scope.rb +379 -36
- data/lib/rigor/sig_gen/classification.rb +4 -0
- data/lib/rigor/sig_gen/effect_annotation.rb +3 -3
- data/lib/rigor/sig_gen/generator.rb +668 -84
- data/lib/rigor/sig_gen/generic_header_scan.rb +189 -0
- data/lib/rigor/sig_gen/inline_declarations.rb +2 -2
- data/lib/rigor/sig_gen/layout_index.rb +3 -3
- data/lib/rigor/sig_gen/method_candidate.rb +23 -4
- data/lib/rigor/sig_gen/observation_collector.rb +7 -6
- data/lib/rigor/sig_gen/observed_call.rb +1 -1
- data/lib/rigor/sig_gen/path_mapper.rb +6 -0
- data/lib/rigor/sig_gen/rbs_validity.rb +1 -1
- data/lib/rigor/sig_gen/renderer.rb +21 -12
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +15 -2
- data/lib/rigor/sig_gen/type_elaborator.rb +21 -5
- data/lib/rigor/sig_gen/type_name_qualification.rb +69 -0
- data/lib/rigor/sig_gen/write_reporter.rb +63 -14
- data/lib/rigor/sig_gen/write_result.rb +23 -12
- data/lib/rigor/sig_gen/writer.rb +217 -37
- data/lib/rigor/type/acceptance_router.rb +2 -2
- data/lib/rigor/type/accepts_result.rb +1 -1
- data/lib/rigor/type/app.rb +4 -6
- data/lib/rigor/type/combinator.rb +13 -16
- data/lib/rigor/type/constant.rb +48 -7
- data/lib/rigor/type/hash_shape.rb +26 -40
- data/lib/rigor/type/struct_instance.rb +3 -2
- data/lib/rigor/type/union.rb +1 -1
- data/lib/rigor/type_node/identifier.rb +1 -2
- data/lib/rigor/type_node/resolver_chain.rb +1 -1
- data/lib/rigor/type_node/string_literal.rb +1 -2
- data/lib/rigor/type_node/symbol_literal.rb +1 -2
- data/lib/rigor/type_node/union.rb +3 -6
- data/lib/rigor/value_semantics.rb +1 -10
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +2 -2
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +2 -3
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +1 -1
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +89 -70
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +4 -2
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +25 -4
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +1 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -5
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_scan.rb +0 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/erb_compiler.rb +2 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +1 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +79 -19
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +6 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/association_roots.rb +3 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/effects.rb +2 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +21 -31
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +10 -16
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +2 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +0 -1
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +5 -4
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +3 -4
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +1 -1
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +7 -12
- data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +1 -1
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +1 -1
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/symbolize_keys.rb +102 -0
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +19 -6
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +26 -13
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_index.rb +3 -3
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +5 -3
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +1 -3
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +6 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +5 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +7 -6
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/params_shape.rb +2 -3
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +5 -8
- data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +1 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +10 -18
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/analyzer.rb +0 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/discoverer.rb +0 -2
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +4 -5
- data/plugins/rigor-grape/lib/rigor/plugin/grape.rb +0 -2
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +6 -7
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +2 -4
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +2 -5
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +2 -2
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +6 -6
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +2 -1
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +3 -8
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +2 -3
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +5 -8
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +1 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +2 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +1 -1
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +4 -11
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +1 -1
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +2 -1
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +102 -11
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +2 -2
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +3 -4
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +6 -8
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +5 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +4 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +6 -7
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +1 -1
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +2 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +17 -21
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +2 -3
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_discoverer.rb +3 -2
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_index.rb +4 -4
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer.rb +1 -1
- data/sig/rigor/analysis/baseline.rbs +0 -2
- data/sig/rigor/analysis/fact_store.rbs +1 -0
- data/sig/rigor/analysis/reachability/scan_cache.rbs +1 -1
- data/sig/rigor/cli/diff_command.rbs +1 -1
- data/sig/rigor/cli/explain_command.rbs +1 -1
- data/sig/rigor/effects/file_collection.rbs +5 -6
- data/sig/rigor/effects/registry.rbs +8 -6
- data/sig/rigor/effects/summary.rbs +6 -5
- data/sig/rigor/environment.rbs +5 -3
- data/sig/rigor/inference/optimistic_origin.rbs +11 -0
- data/sig/rigor/inference.rbs +10 -1
- data/sig/rigor/plugin/additional_initializer.rbs +0 -5
- data/sig/rigor/plugin/base.rbs +1 -0
- data/sig/rigor/plugin/effect_ancestry.rbs +6 -4
- data/sig/rigor/plugin/effect_attribution.rbs +25 -10
- data/sig/rigor/plugin/effect_edge.rbs +12 -5
- data/sig/rigor/plugin/effect_entry_points.rbs +8 -3
- data/sig/rigor/plugin/io_boundary.rbs +6 -5
- data/sig/rigor/plugin/manifest.rbs +16 -18
- data/sig/rigor/plugin/protocol_contract.rbs +6 -9
- data/sig/rigor/plugin/registry.rbs +1 -1
- data/sig/rigor/scope.rbs +51 -50
- data/sig/rigor/type.rbs +0 -6
- data/skills/rigor-plugin-author/SKILL.md +4 -4
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +5 -5
- data/skills/rigor-plugin-review/SKILL.md +3 -3
- data/skills/rigor-project-init/references/03-baseline-and-bugs.md +12 -1
- metadata +55 -3
|
@@ -35,7 +35,8 @@ module Rigor
|
|
|
35
35
|
# LocalVariableReadNode. Composite receivers (`expect(foo.bar)`, `expect { ... }.to raise_error`)
|
|
36
36
|
# fall through.
|
|
37
37
|
# 3. The matcher is one of the recognised forms above (`be_a` / `be_kind_of` / `be_instance_of` /
|
|
38
|
-
# `be_an_instance_of` / `be_nil` / `eq(literal)` / `eql(literal)` / `match(/regex/)
|
|
38
|
+
# `be_an_instance_of` / `be_nil` / `eq(literal)` / `eql(literal)` / `match(/regex/)`, the last a meet
|
|
39
|
+
# with the local's members; see `regex_match_type`).
|
|
39
40
|
#
|
|
40
41
|
# ## Equality is the local's own method
|
|
41
42
|
#
|
|
@@ -152,10 +153,7 @@ module Rigor
|
|
|
152
153
|
when :eq, :eql
|
|
153
154
|
equality_type_for_literal_arg(matcher, target_local, negative: negative, scope: scope)
|
|
154
155
|
when :match
|
|
155
|
-
|
|
156
|
-
# through — the broader matcher dispatch needs the receiver to be a String, but we can only
|
|
157
|
-
# assert that for a literal regex.
|
|
158
|
-
string_type_for_regex_arg(matcher)
|
|
156
|
+
regex_match_type(matcher, target_local, negative: negative, scope: scope)
|
|
159
157
|
end
|
|
160
158
|
end
|
|
161
159
|
|
|
@@ -293,15 +291,108 @@ module Rigor
|
|
|
293
291
|
end
|
|
294
292
|
end
|
|
295
293
|
|
|
296
|
-
|
|
294
|
+
# --- `match(/regex/)` (#2033) ---
|
|
295
|
+
#
|
|
296
|
+
# RSpec's `match` passes when `expected === actual`, when `actual == expected`, or when `actual` responds to
|
|
297
|
+
# `match` and `actual.match(expected)` is truthy. `Regexp#===` matches a Symbol by its name, so a Symbol
|
|
298
|
+
# passes too, and keeps being a Symbol. The positive fact is therefore a meet with the local's members, as
|
|
299
|
+
# `eq`'s is: a String or Symbol member is kept as it is, and a member of a core class that has no `match` or
|
|
300
|
+
# `to_str` and whose `==` never equals a Regexp (`nil`, `true`, `false`, the numerics) is dropped, unless the
|
|
301
|
+
# project defines one of those methods on it or a core ancestor. An `Object`, `BasicObject`, `Kernel` or
|
|
302
|
+
# `Comparable` member reads `String | Symbol` ({#module_match_member}); any other module means no fact. Any other member (a user class, `Dynamic`) may pass, and
|
|
303
|
+
# the analyzer emits no fact; so does a subject none of whose members can pass (a `nil` local stays `nil`). The negative form emits none either: a String that does not match passes
|
|
304
|
+
# `not_to match`, so nothing leaves the local.
|
|
305
|
+
REGEX_MATCH_KEPT_CLASSES = %w[String Symbol].freeze
|
|
306
|
+
REGEX_MATCH_METHODS = %i[match to_str].freeze
|
|
307
|
+
Ractor.make_shareable(REGEX_MATCH_KEPT_CLASSES)
|
|
308
|
+
Ractor.make_shareable(REGEX_MATCH_METHODS)
|
|
309
|
+
private_constant :REGEX_MATCH_KEPT_CLASSES, :REGEX_MATCH_METHODS
|
|
310
|
+
|
|
311
|
+
def regex_match_type(matcher, target_local, negative:, scope:)
|
|
312
|
+
return nil if negative || scope.nil?
|
|
313
|
+
return nil unless regex_literal_arg?(matcher)
|
|
314
|
+
|
|
315
|
+
current = scope.local(target_local)
|
|
316
|
+
return nil if current.nil?
|
|
317
|
+
|
|
318
|
+
members = current.is_a?(Rigor::Type::Union) ? current.members : [current]
|
|
319
|
+
kept = []
|
|
320
|
+
members.each do |member|
|
|
321
|
+
met = regex_match_member(member, scope)
|
|
322
|
+
return nil if met.equal?(UNDECIDED)
|
|
323
|
+
|
|
324
|
+
kept << met unless met.nil?
|
|
325
|
+
end
|
|
326
|
+
kept.empty? ? nil : Rigor::Type::Combinator.union(*kept)
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
def regex_literal_arg?(matcher)
|
|
297
330
|
args = matcher.arguments&.arguments || []
|
|
298
|
-
|
|
331
|
+
args.size == 1 &&
|
|
332
|
+
(args.first.is_a?(Prism::RegularExpressionNode) || args.first.is_a?(Prism::InterpolatedRegularExpressionNode))
|
|
333
|
+
end
|
|
299
334
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
335
|
+
# The member itself when it may pass, nil when it cannot, UNDECIDED when Rigor cannot tell.
|
|
336
|
+
def regex_match_member(member, scope)
|
|
337
|
+
module_member = module_match_member(member, scope)
|
|
338
|
+
return module_member unless module_member.nil?
|
|
303
339
|
|
|
304
|
-
|
|
340
|
+
class_name = member_class_name(member)
|
|
341
|
+
return UNDECIDED if class_name.nil?
|
|
342
|
+
return member if REGEX_MATCH_KEPT_CLASSES.include?(class_name)
|
|
343
|
+
return member if project_defines?(class_name, :==, scope)
|
|
344
|
+
return member if REGEX_MATCH_METHODS.any? { |name| project_defines_on_chain?(class_name, name, scope) }
|
|
345
|
+
|
|
346
|
+
nil
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
OPEN_SURFACE_CLASS_NAMES = %w[Object BasicObject].freeze
|
|
350
|
+
# The modules String's or Symbol's own ancestry includes (`Kernel`, `Comparable`), read from the running Ruby.
|
|
351
|
+
STRING_SYMBOL_MODULES = (String.ancestors + Symbol.ancestors).grep_v(Class).filter_map(&:name).uniq.freeze
|
|
352
|
+
Ractor.make_shareable(OPEN_SURFACE_CLASS_NAMES)
|
|
353
|
+
Ractor.make_shareable(STRING_SYMBOL_MODULES)
|
|
354
|
+
private_constant :OPEN_SURFACE_CLASS_NAMES, :STRING_SYMBOL_MODULES
|
|
355
|
+
|
|
356
|
+
# The meet for an `Object`, `BasicObject` or module member, or nil for any other member. Its instances may be
|
|
357
|
+
# anything, a `to_str` or `match` object included. A member that declares `match` or `to_str` itself (its
|
|
358
|
+
# signature, a core ancestor, or the project's source) is kept whole. `Object`, `BasicObject` and a module
|
|
359
|
+
# String or Symbol includes otherwise read `String | Symbol`, as the String they most often are, so a String
|
|
360
|
+
# method called after the matcher reports nothing. Any other module is UNDECIDED: a passing value may include
|
|
361
|
+
# it without being a String. (Decision shared with #2256.)
|
|
362
|
+
def module_match_member(member, scope)
|
|
363
|
+
return nil unless member.is_a?(Rigor::Type::Nominal) && member.type_args.empty?
|
|
364
|
+
|
|
365
|
+
name = member.class_name
|
|
366
|
+
string_like = OPEN_SURFACE_CLASS_NAMES.include?(name) || STRING_SYMBOL_MODULES.include?(name)
|
|
367
|
+
return nil unless string_like || scope.environment&.rbs_module?(name)
|
|
368
|
+
return member if REGEX_MATCH_METHODS.any? { |method_name| declares_method?(name, method_name, scope) }
|
|
369
|
+
return UNDECIDED unless string_like
|
|
370
|
+
|
|
371
|
+
Rigor::Type::Combinator.union(Rigor::Type::Combinator.nominal_of("String"),
|
|
372
|
+
Rigor::Type::Combinator.nominal_of("Symbol"))
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
def declares_method?(name, method_name, scope)
|
|
376
|
+
project_defines_on_chain?(name, method_name, scope) ||
|
|
377
|
+
!Rigor::Reflection.instance_method_definition(name, method_name, scope: scope).nil?
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
# Each core class's (and `Object` / `BasicObject` / `Kernel`'s) runtime ancestor chain. The project's
|
|
381
|
+
# reopenings are looked up along it by name, since the scope's ancestry walk does not cross core classes:
|
|
382
|
+
# `class Numeric; def to_str` reaches a Float member, `module Kernel; def match` a nil one.
|
|
383
|
+
CORE_ANCESTOR_CHAINS = [*EQUALITY_CORE_CLASSES, Object, BasicObject, Kernel].to_h do |mod|
|
|
384
|
+
[mod.name, mod.ancestors.filter_map(&:name).freeze]
|
|
385
|
+
end.freeze
|
|
386
|
+
Ractor.make_shareable(CORE_ANCESTOR_CHAINS)
|
|
387
|
+
private_constant :CORE_ANCESTOR_CHAINS
|
|
388
|
+
|
|
389
|
+
# Whether the project's source defines `method_name` on `class_name` or an ancestor, core ones included: a
|
|
390
|
+
# `def`, an included module, or a `define_method`.
|
|
391
|
+
def project_defines_on_chain?(class_name, method_name, scope)
|
|
392
|
+
CORE_ANCESTOR_CHAINS.fetch(class_name, [class_name]).any? do |name|
|
|
393
|
+
!scope.user_def_through_ancestors(name, method_name).first.nil? ||
|
|
394
|
+
scope.discovered_method_through_ancestors?(name, method_name, :instance)
|
|
395
|
+
end
|
|
305
396
|
end
|
|
306
397
|
|
|
307
398
|
NO_LITERAL = Object.new.freeze
|
|
@@ -14,7 +14,7 @@ module Rigor
|
|
|
14
14
|
# narrows `expect(x).to MATCHER` assertions downstream, and binds `let`/`subject` locals to their
|
|
15
15
|
# inferred return types inside `it` bodies.
|
|
16
16
|
#
|
|
17
|
-
# Tier 3A of the [Rails plugins roadmap](
|
|
17
|
+
# Tier 3A of the [Rails plugins roadmap](../../../../../docs/design/20260508-rails-plugins-roadmap.md).
|
|
18
18
|
# Ships four checks:
|
|
19
19
|
#
|
|
20
20
|
# 1. **Duplicate `let` / `subject` declarations** in the same scope (`warning`). RSpec's runtime lets
|
|
@@ -44,7 +44,7 @@ module Rigor
|
|
|
44
44
|
# - **No shared-context resolution.** `include_context`, `shared_context`, and `it_behaves_like` are
|
|
45
45
|
# recognised as scope-opening calls but their declarations are not pulled into the host scope.
|
|
46
46
|
# - **Constant validation is not done here.** `RSpec.describe SomeClass do` does not validate
|
|
47
|
-
# `SomeClass`; the engine's
|
|
47
|
+
# `SomeClass`; the engine's constant-resolution diagnostics already catch that.
|
|
48
48
|
class Rspec < Rigor::Plugin::Base
|
|
49
49
|
manifest(
|
|
50
50
|
id: "rspec",
|
|
@@ -30,7 +30,7 @@ module Rigor
|
|
|
30
30
|
# - `route_to(...)` / `redirect_to(...)` — needs the routes table from `rigor-rails-routes`
|
|
31
31
|
# (`:helper_table` cross-plugin fact). Future slice.
|
|
32
32
|
# - `have_enqueued_job(JobClass)` / `have_enqueued_mail(MailerClass)` — class-existence check overlaps
|
|
33
|
-
# with engine's
|
|
33
|
+
# with the engine's constant-resolution diagnostics; queued behind a decision on which surface owns the
|
|
34
34
|
# diagnostic.
|
|
35
35
|
# - `have_received(:method)` — overlaps with engine's `call.undefined-method`; same coordination
|
|
36
36
|
# question.
|
|
@@ -44,9 +44,8 @@ module Rigor
|
|
|
44
44
|
description: "Validates rspec-rails behavioral matchers (have_http_status floor)."
|
|
45
45
|
)
|
|
46
46
|
|
|
47
|
-
# ADR-37 — the engine walks each file and hands us every CallNode; the analyzer is
|
|
48
|
-
# logic. The diagnostic points at the matcher name (`message_loc`)
|
|
49
|
-
# `message_loc || location` positioning.
|
|
47
|
+
# ADR-37 — the engine walks each file and hands us every CallNode; the analyzer is pure per-node
|
|
48
|
+
# logic. The diagnostic points at the matcher name (`message_loc`).
|
|
50
49
|
node_rule Prism::CallNode do |node, _scope, path|
|
|
51
50
|
violation = HaveHttpStatusAnalyzer.violation_for(node)
|
|
52
51
|
next [] unless violation
|
|
@@ -31,7 +31,7 @@ module Rigor
|
|
|
31
31
|
# have_db_index(:col)
|
|
32
32
|
#
|
|
33
33
|
# All look up `:col` against the model's `columns:` (the published `:model_index` fact's flat
|
|
34
|
-
#
|
|
34
|
+
# name list per model — see `Analyzer#column_names`). Unknown columns fire `unknown-column`.
|
|
35
35
|
#
|
|
36
36
|
# ### Association matchers
|
|
37
37
|
#
|
|
@@ -107,8 +107,7 @@ module Rigor
|
|
|
107
107
|
|
|
108
108
|
# A direct matcher invocation is a `CallNode` whose `name` is in `MATCHER_TABLE` and whose first
|
|
109
109
|
# argument is a `SymbolNode`. The chain shape (`should`, `expect(...).to`, `is_expected.to`) is
|
|
110
|
-
# irrelevant
|
|
111
|
-
# regardless of the surrounding chain.
|
|
110
|
+
# irrelevant: the engine visits the inner matcher call, so the diagnostic fires on it regardless.
|
|
112
111
|
def matcher_invocation?(node)
|
|
113
112
|
node.is_a?(Prism::CallNode) && MATCHER_TABLE.key?(node.name) && symbol_first_arg?(node)
|
|
114
113
|
end
|
|
@@ -172,11 +171,10 @@ module Rigor
|
|
|
172
171
|
end
|
|
173
172
|
|
|
174
173
|
# `entry` is the published fact's per-model Hash: `{ table:, columns:, associations:, ... }`.
|
|
175
|
-
# `columns:` is a flat
|
|
176
|
-
#
|
|
177
|
-
#
|
|
178
|
-
#
|
|
179
|
-
# read here.
|
|
174
|
+
# `columns:` is a flat list of column names (`Activerecord#index_to_published_hash`); `associations:`
|
|
175
|
+
# is a list of rows with `:name`, `:kind` (`:singular` | `:collection`), `:nullable`, `:polymorphic`,
|
|
176
|
+
# and a `:target` that is nil on polymorphic rows — the row shape `ModelDiscoverer#build_association_row`
|
|
177
|
+
# publishes. Only `:name` and `:kind` are read here.
|
|
180
178
|
def column_names(entry) = entry[:columns] || []
|
|
181
179
|
def association_rows(entry) = entry[:associations] || []
|
|
182
180
|
def find_association(entry, name) = association_rows(entry).find { |a| a[:name] == name.to_s }
|
|
@@ -97,8 +97,11 @@ module Rigor
|
|
|
97
97
|
|
|
98
98
|
# Cached separately from `:worker_index` because the two invalidate on different files: editing a
|
|
99
99
|
# schedule changes which workers are reached without touching `app/workers` at all. The `watch:` roots
|
|
100
|
-
# the glob at the working directory so that CREATING a schedule file — not just editing one — is seen.
|
|
101
|
-
|
|
100
|
+
# the glob at the working directory so that CREATING a schedule file — not just editing one — is seen. Each
|
|
101
|
+
# configured path is escaped to a literal name, so `sidekiq[1].yml` is watched as that file, and an
|
|
102
|
+
# absolute path is watched under its own directory (`RootedGlob.split_file`, #2222).
|
|
103
|
+
producer :scheduled_workers,
|
|
104
|
+
watch: -> { @schedule_paths.map { |path| Rigor::RootedGlob.split_file(path) } } do |_params|
|
|
102
105
|
ScheduleScan.new(
|
|
103
106
|
io_boundary: io_boundary,
|
|
104
107
|
schedule_paths: @schedule_paths
|
|
@@ -31,11 +31,10 @@ module Rigor
|
|
|
31
31
|
# behaviour: it always raises). This lets the engine's existing flow analysis treat code after
|
|
32
32
|
# `T.absurd` as unreachable, matching what users of Sorbet expect.
|
|
33
33
|
# - When the branch is REACHABLE (the discriminant's type isn't `bot`), the recogniser also records
|
|
34
|
-
# the call node in a per-plugin set. The plugin's
|
|
35
|
-
# `
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
# `diagnostics_for_file`.
|
|
34
|
+
# the call node in a per-plugin set. The plugin's node rule later emits a
|
|
35
|
+
# `plugin.sorbet.absurd-reachable` warning for each recorded call node, matched by object identity.
|
|
36
|
+
# We rely on the runner only parsing each file once per run, so the same Prism node object is seen
|
|
37
|
+
# in both the `dynamic_return` rule and the node rule.
|
|
39
38
|
module AbsurdRecognizer
|
|
40
39
|
# @return true when `call_node` is `T.absurd(x)`.
|
|
41
40
|
def self.absurd_call?(call_node)
|
|
@@ -21,7 +21,7 @@ module Rigor
|
|
|
21
21
|
# | `T.unsafe(x)` | return type ← `Dynamic[top]` |
|
|
22
22
|
# | `T.reveal_type(expr)` | return type ← `inferred(expr)` (passes through) |
|
|
23
23
|
# | `T.assert_type!(expr, T)` | return type ← translated `T` + static subtype check |
|
|
24
|
-
# | `T.bind(self, T)` | return type ← `Constant[nil]` +
|
|
24
|
+
# | `T.bind(self, T)` | return type ← `Constant[nil]` + `self` narrowing fact |
|
|
25
25
|
#
|
|
26
26
|
# The Sorbet runtime's `T.let` / `T.cast` actually return the inner expression unchanged at runtime;
|
|
27
27
|
# their job is purely to *assert* a static type. From Rigor's static perspective the simplest
|
|
@@ -36,7 +36,7 @@ module Rigor
|
|
|
36
36
|
# `T.reveal_type` is "diagnostic-only" in Sorbet: it passes the value through unchanged at runtime
|
|
37
37
|
# AND surfaces the inferred static type as a build-time message. The recogniser contributes the
|
|
38
38
|
# inferred type (so chained call sites still resolve as if the `T.reveal_type` wrapper weren't
|
|
39
|
-
# there); the plugin's
|
|
39
|
+
# there); the plugin's node rule surfaces the `plugin.sorbet.reveal-type` `:info`
|
|
40
40
|
# message for human consumption.
|
|
41
41
|
#
|
|
42
42
|
# `T.bind(self, T)` is recognised as block-scope self narrowing. The recogniser returns a
|
|
@@ -113,9 +113,9 @@ module Rigor
|
|
|
113
113
|
|
|
114
114
|
# `T.assert_type!(expr, T)` shares the typed-assertion contribution shape with `T.cast` (return is
|
|
115
115
|
# the asserted type), so the recogniser delegates the return-type half through
|
|
116
|
-
# `resolve_typed_assertion`. The static subtype check that distinguishes `assert_type!` from
|
|
117
|
-
#
|
|
118
|
-
#
|
|
116
|
+
# `resolve_typed_assertion`. The static subtype check that distinguishes `assert_type!` from `cast`
|
|
117
|
+
# is run by the plugin's `record_assert_type_check`, which records a mismatch for the node rule to
|
|
118
|
+
# emit (the absurd-recognizer pattern).
|
|
119
119
|
def assert_type_check(call_node, scope)
|
|
120
120
|
return nil if scope.nil?
|
|
121
121
|
|
|
@@ -135,8 +135,7 @@ module Rigor
|
|
|
135
135
|
# `T.reveal_type(expr)` returns `expr` unchanged at runtime; the Sorbet-side semantics is "make
|
|
136
136
|
# the inferred static type visible to the user." The contribution mirrors `T.must` minus the
|
|
137
137
|
# nil-stripping: the call's return type is the inner expression's inferred type. The companion
|
|
138
|
-
# diagnostic is emitted by
|
|
139
|
-
# contribution only.
|
|
138
|
+
# diagnostic is emitted by a node rule; this method handles the contribution only.
|
|
140
139
|
def resolve_reveal_type(call_node, scope)
|
|
141
140
|
inner = nth_argument(call_node, 0)
|
|
142
141
|
return Rigor::Type::Combinator.untyped if inner.nil? || scope.nil?
|
|
@@ -57,7 +57,7 @@ module Rigor
|
|
|
57
57
|
@entries[key_for(class_name, method_name, kind)]
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
-
# @return frozen
|
|
60
|
+
# @return frozen `:include` / `:extend` buckets of mixed-in module names.
|
|
61
61
|
# Returns {EMPTY_MIXINS} when no mixins were recorded.
|
|
62
62
|
def mixins_for(class_name)
|
|
63
63
|
@mixins[class_name] || EMPTY_MIXINS
|
|
@@ -22,8 +22,8 @@ module Rigor
|
|
|
22
22
|
#
|
|
23
23
|
# The parser walks the chain right-to-left, gathering whatever it recognises (`params` / `returns` /
|
|
24
24
|
# `void` / `abstract` / `override` / `overridable` / `final` / `type_parameters` / `checked` /
|
|
25
|
-
# `on_failure`) into a frozen result hash stored in {MethodSignature}. Modifiers
|
|
26
|
-
# `type_parameters`
|
|
25
|
+
# `on_failure`) into a frozen result hash stored in {MethodSignature}. Modifiers are recorded but not
|
|
26
|
+
# yet acted on; `type_parameters` is recognised and its payload discarded.
|
|
27
27
|
#
|
|
28
28
|
# The parser is intentionally tolerant — unknown chain nodes degrade to "the rest of the chain is
|
|
29
29
|
# opaque" rather than raising. The plugin emits a diagnostic (`plugin.sorbet.parse-error`) only when
|
|
@@ -42,8 +42,8 @@ module Rigor
|
|
|
42
42
|
# `IoBoundary`. The catalog is frozen after the first build and consulted by the `dynamic_return` rule
|
|
43
43
|
# at every gated call site. RBI files share the catalog with project-source sigs — both produce
|
|
44
44
|
# `MethodSignature` entries keyed by `(class_name, method_name, kind)`. When a key collides across
|
|
45
|
-
# files, the last-walked sig wins (
|
|
46
|
-
#
|
|
45
|
+
# files, the last-walked sig wins (`Dir.glob` results are sorted, so the walk order is stable).
|
|
46
|
+
# Sorbet's full shim-override semantics — `sorbet/rbi/shims/` overriding
|
|
47
47
|
# `sorbet/rbi/gems/` — lands in a later slice once the catalog gains per-source provenance.
|
|
48
48
|
#
|
|
49
49
|
# The plugin emits `plugin.sorbet.parse-error` warnings for malformed sig blocks (no block / empty
|
|
@@ -79,12 +79,10 @@ module Rigor
|
|
|
79
79
|
"rbi_paths" => { kind: :array, default: ["sorbet/rbi"] },
|
|
80
80
|
"enforce_sigil" => { kind: :boolean, default: true }
|
|
81
81
|
},
|
|
82
|
-
# #1097 — bundled sorbet-runtime DSL surface (`sig/sorbet.rbs`). `sig`
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
#
|
|
86
|
-
# `T::Helpers` / `T::Generic`, and `rbs_complete_ancestors:` carries the Struct/Enum family
|
|
87
|
-
# for the subclass bridge.
|
|
82
|
+
# #1097 — bundled sorbet-runtime DSL surface (`sig/sorbet.rbs`). `sig` reaches the class object
|
|
83
|
+
# through `extend T::Sig` (or the `T::Struct` / `T::Enum` family, which carry the edge themselves):
|
|
84
|
+
# `rbs_complete_extends:` is that extend-edge allow-list, and `rbs_complete_ancestors:` carries the
|
|
85
|
+
# Struct/Enum family for the subclass bridge.
|
|
88
86
|
signature_paths: ["sig"],
|
|
89
87
|
rbs_complete_extends: %w[T::Sig T::Helpers T::Generic],
|
|
90
88
|
rbs_complete_ancestors: %w[T::Struct T::InexactStruct T::ImmutableStruct T::Enum],
|
|
@@ -122,8 +120,7 @@ module Rigor
|
|
|
122
120
|
@configured_paths = Array(config.fetch("paths", services.configuration.paths)).map(&:to_s)
|
|
123
121
|
@rbi_paths = Array(config.fetch("rbi_paths")).map(&:to_s)
|
|
124
122
|
# Schema default `true` — only files marked `# typed: true` / `:strict` / `:strong` contribute
|
|
125
|
-
# their sigs. Set to `false` to record every file's sigs regardless of sigil
|
|
126
|
-
# pre-this-config).
|
|
123
|
+
# their sigs. Set to `false` to record every file's sigs regardless of sigil.
|
|
127
124
|
@enforce_sigil = config.fetch("enforce_sigil")
|
|
128
125
|
# Per-call-site assertion gating: `@sigil_by_path` (built during catalog harvest) is consulted so
|
|
129
126
|
# `T.let` / `T.cast` / `T.must` / `T.bind` / `T.assert_type!` only fire in files Sorbet itself
|
|
@@ -135,20 +132,20 @@ module Rigor
|
|
|
135
132
|
@parse_errors_by_path = {}
|
|
136
133
|
@catalog_built = false
|
|
137
134
|
# ADR-11 slice 6 — Prism nodes for `T.absurd` calls we observed in the `dynamic_return` rule to be
|
|
138
|
-
# *reachable* (i.e., their discriminant didn't narrow to `bot`).
|
|
139
|
-
#
|
|
140
|
-
#
|
|
141
|
-
#
|
|
135
|
+
# *reachable* (i.e., their discriminant didn't narrow to `bot`). The node rule below surfaces these
|
|
136
|
+
# as `plugin.sorbet.absurd-reachable` warnings. The Hash is keyed by node identity
|
|
137
|
+
# (`compare_by_identity`) because the runner only parses each file once per run, so identity is
|
|
138
|
+
# stable across the two plugin hooks.
|
|
142
139
|
@reachable_absurd_nodes = {}.compare_by_identity
|
|
143
140
|
# ADR-11 light follow-up — `T.reveal_type` calls observed in the `dynamic_return` rule, paired
|
|
144
141
|
# with the display string for the inferred type at the call site. Mirrors the absurd-node
|
|
145
|
-
# compare-by-identity hash;
|
|
142
|
+
# compare-by-identity hash; the node rule below surfaces each entry as a
|
|
146
143
|
# `plugin.sorbet.reveal-type` `:info` diagnostic.
|
|
147
144
|
@reveal_type_calls = {}.compare_by_identity
|
|
148
145
|
# T.bind / T.assert_type! priority slice 1 — `T.assert_type!` calls observed in the
|
|
149
146
|
# `dynamic_return` rule whose static subtype check FAILED, paired with the inferred + asserted
|
|
150
|
-
# type display strings. Same compare-by-identity discipline.
|
|
151
|
-
#
|
|
147
|
+
# type display strings. Same compare-by-identity discipline. The node rule below surfaces matching
|
|
148
|
+
# entries as
|
|
152
149
|
# `plugin.sorbet.assert-type-mismatch` `:error` diagnostics.
|
|
153
150
|
@assert_type_mismatches = {}.compare_by_identity
|
|
154
151
|
end
|
|
@@ -245,7 +242,7 @@ module Rigor
|
|
|
245
242
|
# analysis treats code after it as unreachable; the legacy contribution's `exceptional: :raises`
|
|
246
243
|
# slot was never consumed on the dispatcher path — only `return_type` survives the merge). When
|
|
247
244
|
# the discriminant *isn't* narrowed to `bot` at this scope, also records the call node so
|
|
248
|
-
#
|
|
245
|
+
# the node rule can surface a `plugin.sorbet.absurd-reachable` warning.
|
|
249
246
|
if AbsurdRecognizer.absurd_call?(call_node)
|
|
250
247
|
@reachable_absurd_nodes[call_node] = true unless AbsurdRecognizer.exhaustive?(call_node, scope)
|
|
251
248
|
return Rigor::Type::Combinator.bot
|
|
@@ -255,7 +252,7 @@ module Rigor
|
|
|
255
252
|
# cheaper to recognise (no catalog walk required) and they win over any cataloged signature: the
|
|
256
253
|
# user explicitly asserted the type at the call site. The light follow-up extends the recogniser
|
|
257
254
|
# to `T.must_because` (alias of `T.must`) and `T.reveal_type` (passes the type through; the
|
|
258
|
-
# human-facing diagnostic is recorded here for
|
|
255
|
+
# human-facing diagnostic is recorded here for the node rule to emit).
|
|
259
256
|
#
|
|
260
257
|
# Per-call-site sigil gating: with `enforce_sigil: true` (default), assertions only fire in files
|
|
261
258
|
# Sorbet itself would enforce. Files at `# typed: false` (or sigil-less, which Sorbet treats as
|
|
@@ -502,8 +499,7 @@ module Rigor
|
|
|
502
499
|
# ADR-88 WD2 — deterministic fold order matters now that the catalog VALUE is digested into the
|
|
503
500
|
# incremental fact-surface fingerprint: a duplicate `(class, method, kind)` sig's last-wins winner
|
|
504
501
|
# must not vary by machine / run. `Dir.glob` sorts its results by default on Ruby 3.0+, so the fold
|
|
505
|
-
# order is already stable
|
|
506
|
-
# this walk relies on it rather than re-sorting.
|
|
502
|
+
# order is already stable; this walk relies on it rather than re-sorting.
|
|
507
503
|
Dir.glob("**/*#{ext}", base: absolute).each do |relative|
|
|
508
504
|
harvest_file(canonicalize(File.join(absolute, relative)), catalog, sigil_by_path, parse_errors_by_path)
|
|
509
505
|
end
|
|
@@ -11,9 +11,8 @@ module Rigor
|
|
|
11
11
|
#
|
|
12
12
|
# 1. **Collect pass.** Walk the file once to gather every state name declared inside a
|
|
13
13
|
# `state_machine do ... end` block (`state :draft`, `state :submitted`, ...).
|
|
14
|
-
# 2. **Validate pass.** Walk the file again, validating each `transition_to(:sym)`
|
|
15
|
-
#
|
|
16
|
-
# suggestions.
|
|
14
|
+
# 2. **Validate pass.** Walk the file again, validating each `transition_to(:sym)` reference against
|
|
15
|
+
# the collected state set. `DidYouMean::SpellChecker` drives the did-you-mean suggestions.
|
|
17
16
|
#
|
|
18
17
|
# Useful for `aasm` / `statesman` / hand-rolled DSLs and any framework where declarations and uses
|
|
19
18
|
# live in the same file. The same skeleton lifts to GraphQL types, ActiveModel validations, route
|
|
@@ -10,8 +10,9 @@ require_relative "serializer_index"
|
|
|
10
10
|
module Rigor
|
|
11
11
|
module Plugin
|
|
12
12
|
class Typelizer < Rigor::Plugin::Base
|
|
13
|
-
# Reads every `.rb` file under the configured typelizer dirs and the project's `paths:` through the
|
|
14
|
-
# {SerializerCollector} over each and merges the results into one
|
|
13
|
+
# Reads every `.rb` file under the configured typelizer dirs and the project's `paths:` through the
|
|
14
|
+
# plugin's `IoBoundary`, runs a {SerializerCollector} over each and merges the results into one
|
|
15
|
+
# {SerializerIndex}.
|
|
15
16
|
class SerializerDiscoverer
|
|
16
17
|
def initialize(io_boundary:, dirs:, project_paths: [])
|
|
17
18
|
@io_boundary = io_boundary
|
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
module Rigor
|
|
4
4
|
module Plugin
|
|
5
5
|
class Typelizer < Rigor::Plugin::Base
|
|
6
|
-
# The project's classes (every file of the project's `paths:` and the typelizer `dirs`), as the
|
|
7
|
-
# object the `:serializer_index` producer caches.
|
|
6
|
+
# The project's classes (every file of the project's `paths:` and the typelizer `dirs`), as the
|
|
7
|
+
# {SerializerCollector} found them. A frozen value object the `:serializer_index` producer caches.
|
|
8
8
|
#
|
|
9
9
|
# {#roots} answers the one question, conservatively — a wrong "no" costs a missing root, a wrong "yes"
|
|
10
10
|
# hides a dead class.
|
|
11
11
|
class SerializerIndex
|
|
12
12
|
# A class the project declares. `superclass` is the constant as written (`nil` when absent) and
|
|
13
13
|
# `nesting` the `Module.nesting` chain (innermost first) its header was written under, which is where
|
|
14
|
-
# Ruby resolves that constant. `dsl` is true when its body includes or extends `Typelizer::DSL`;
|
|
15
|
-
# typelizer `dirs` declares it (only such a class is published as a root).
|
|
14
|
+
# Ruby resolves that constant. `dsl` is true when its body includes or extends `Typelizer::DSL`;
|
|
15
|
+
# `in_dirs` when a file under the typelizer `dirs` declares it (only such a class is published as a root).
|
|
16
16
|
ClassEntry = Data.define(:name, :superclass, :nesting, :dsl, :in_dirs)
|
|
17
17
|
|
|
18
18
|
def initialize(classes:)
|
|
@@ -62,7 +62,7 @@ module Rigor
|
|
|
62
62
|
if io_boundary.directory?(File.expand_path(entry))
|
|
63
63
|
[entry, "**/*.rb"]
|
|
64
64
|
elsif entry.end_with?(".rb") && io_boundary.file?(File.expand_path(entry))
|
|
65
|
-
[File.dirname(entry), File.basename(entry)]
|
|
65
|
+
[File.dirname(entry), Rigor::RootedGlob.literal(File.basename(entry))]
|
|
66
66
|
end
|
|
67
67
|
end
|
|
68
68
|
end
|
|
@@ -66,8 +66,6 @@ module Rigor
|
|
|
66
66
|
|
|
67
67
|
# Always an Array of Bucket — `initialize` freezes what it is given and every caller hands it
|
|
68
68
|
# Bucket instances (parse_row rows, from_diagnostics groups, `without`'s reject, or `[]`).
|
|
69
|
-
# sig-gen gap: #1154 — an `attr_reader` over an ivar assigned in `initialize` from a parameter
|
|
70
|
-
# is skipped (untyped return); the element type is hand-written.
|
|
71
69
|
attr_reader buckets: Array[Bucket]
|
|
72
70
|
|
|
73
71
|
# `project_root` is `Pathname.new`'d, so a `Pathname` is accepted as well as a `String`
|
|
@@ -3,6 +3,7 @@ module Rigor
|
|
|
3
3
|
module CheckRules
|
|
4
4
|
def self?.diagnose: (path: String, root: untyped, scope_index: Hash[untyped, Scope]) -> Array[Diagnostic]
|
|
5
5
|
def self?.build_node_collectors: (String path, untyped scope_index, ?untyped root) -> Hash[Symbol, untyped]
|
|
6
|
+
# authored: returns Rigor::Analysis::CheckRules::RuleWalk::CollectorDriver, which has no RBS declaration yet (#2404); stays `untyped` until it is declared
|
|
6
7
|
def self?.node_collector_driver: (Hash[Symbol, untyped] collectors) -> untyped
|
|
7
8
|
def self?.shadow_verify_converged_collectors: (String path, untyped root, untyped scope_index, Hash[Symbol, untyped]? collectors) -> void
|
|
8
9
|
def self?.filter_suppressed: (Array[Diagnostic] diagnostics, comments: untyped, disabled_rules: Array[String]) -> Array[Diagnostic]
|
|
@@ -3,7 +3,7 @@ module Rigor
|
|
|
3
3
|
module Reachability
|
|
4
4
|
class ScanCache
|
|
5
5
|
def self.open: (untyped, ?target_ruby: untyped) -> Rigor::Analysis::Reachability::ScanCache
|
|
6
|
-
def self.source_digest: () -> String
|
|
6
|
+
def self.source_digest: () -> ("unreadable" | String)
|
|
7
7
|
def initialize: (path: untyped, header: untyped) -> void
|
|
8
8
|
def save: () -> nil
|
|
9
9
|
end
|
|
@@ -45,16 +45,15 @@ module Rigor
|
|
|
45
45
|
# The collection a file with nothing to say contributes.
|
|
46
46
|
def self.empty: (?String? path) -> FileCollection
|
|
47
47
|
|
|
48
|
-
# sig-gen gap: #1154 — `initialize` freezes the kwarg tables rather than assigning them
|
|
49
|
-
# verbatim, so sig-gen proposes the default constant's shape for each reader.
|
|
50
48
|
attr_reader path: String?
|
|
51
|
-
# sig-gen gap: #
|
|
49
|
+
# sig-gen gap: #2312 — `{ "Class#m" => Summary }`, through the private `freeze_table` helper, whose parameters
|
|
50
|
+
# are undeclared.
|
|
52
51
|
attr_reader summaries: Hash[String, Summary]
|
|
53
|
-
# sig-gen gap: #
|
|
52
|
+
# sig-gen gap: #2312 — `{ "Class#m" => [Edge] }`, sorted and de-duplicated.
|
|
54
53
|
attr_reader edges: Hash[String, Array[Edge]]
|
|
55
|
-
# sig-gen gap: #
|
|
54
|
+
# sig-gen gap: #2312 — `{ class_name => superclass_name }`, `OPAQUE_ANCESTOR` included.
|
|
56
55
|
attr_reader superclasses: Hash[String, String]
|
|
57
|
-
# sig-gen gap: #
|
|
56
|
+
# sig-gen gap: #2312 — `{ class_name => [module_name] }`, include/prepend merged.
|
|
58
57
|
attr_reader includes: Hash[String, Array[String]]
|
|
59
58
|
|
|
60
59
|
def initialize: (?path: String?, ?summaries: Hash[String, Summary],
|
|
@@ -32,17 +32,19 @@ module Rigor
|
|
|
32
32
|
# an empty vocabulary (fail-open).
|
|
33
33
|
def self.load_file: (untyped path) -> Registry
|
|
34
34
|
|
|
35
|
-
# sig-gen gap: #1154 — `attr_reader` over an ivar assigned in `initialize` from the
|
|
36
|
-
# parameter of the same name; sig-gen proposes `untyped` for it.
|
|
37
35
|
attr_reader vocabulary_version: Integer
|
|
38
|
-
# sig-gen gap: #
|
|
39
|
-
#
|
|
36
|
+
# sig-gen gap: #2325 — `labels:` is declared `Array[untyped]` (input `untyped`, looks deliberate; a declared
|
|
37
|
+
# type is authoring intent tracked by #2325, and only then does this row generate; coercion-facing:
|
|
38
|
+
# `map(&:to_s)`); every declared label, sorted. Implied ancestors are recognised by {#known?} but not listed
|
|
39
|
+
# here.
|
|
40
40
|
attr_reader labels: Array[String]
|
|
41
41
|
# The roots of the vocabulary — the outermost segments {#with} treats as already owned.
|
|
42
42
|
# Unmarked residue: `@roots` is computed from `@known` in `initialize`, not assigned from a
|
|
43
|
-
# parameter, so
|
|
43
|
+
# parameter, so no parameter credit applies.
|
|
44
44
|
attr_reader roots: Array[String]
|
|
45
|
-
# sig-gen gap: #
|
|
45
|
+
# sig-gen gap: #2325 — `descriptions:` is declared `Hash[untyped, untyped]` (input `untyped`, looks deliberate;
|
|
46
|
+
# a declared type is authoring intent tracked by #2325, and only then does this row generate; coercion-facing:
|
|
47
|
+
# keys and texts `to_s`'d); one line per root, from the data file's `descriptions:`.
|
|
46
48
|
attr_reader descriptions: Hash[String, String]
|
|
47
49
|
|
|
48
50
|
def initialize: (vocabulary_version: Integer, labels: Array[untyped],
|
|
@@ -12,17 +12,18 @@ module Rigor
|
|
|
12
12
|
# could not finish.
|
|
13
13
|
def self.tainted: (String cause, ?String? detail) -> Summary
|
|
14
14
|
|
|
15
|
-
# sig-gen gap: #
|
|
16
|
-
# `normalize_bundles` (join-merging per origin),
|
|
15
|
+
# sig-gen gap: #2312 — `initialize` normalizes the `bundles:`/`declared_bundles:` kwargs through
|
|
16
|
+
# `normalize_bundles` (join-merging per origin), a private helper whose parameters are undeclared.
|
|
17
17
|
attr_reader bundles: Hash[Origin, LabelSet]
|
|
18
|
-
# sig-gen gap: #
|
|
18
|
+
# sig-gen gap: #2312 — as above.
|
|
19
19
|
attr_reader declared_bundles: Hash[Origin, LabelSet]
|
|
20
20
|
# Unmarked residue — `proven`/`declared` are flattened from the bundle tables by `initialize`,
|
|
21
|
-
# not assigned from a parameter, so
|
|
21
|
+
# not assigned from a parameter at all, so no parameter credit applies (same shape as
|
|
22
22
|
# `Registry#additional_initializers`).
|
|
23
23
|
attr_reader declared: LabelSet
|
|
24
24
|
attr_reader proven: LabelSet
|
|
25
|
-
# sig-gen gap: #
|
|
25
|
+
# sig-gen gap: #2312 — `causes` are `[cause, detail]` pairs normalized by the private `normalize_causes` helper,
|
|
26
|
+
# whose parameters are undeclared.
|
|
26
27
|
attr_reader causes: Array[[String, String?]]
|
|
27
28
|
|
|
28
29
|
def initialize: (?bundles: Hash[Origin, LabelSet], ?declared_bundles: Hash[Origin, LabelSet],
|
data/sig/rigor/environment.rbs
CHANGED
|
@@ -31,8 +31,6 @@ module Rigor
|
|
|
31
31
|
def nominal_for_name: (String | Symbol name) -> Type::Nominal?
|
|
32
32
|
def singleton_for_name: (String | Symbol name) -> Type::Singleton?
|
|
33
33
|
def constant_for_name: (String | Symbol name) -> Type::t?
|
|
34
|
-
# sig-gen gap: #1154 — the answer comes through `rbs_loader`, an `attr_reader` over an ivar assigned in
|
|
35
|
-
# `initialize` from a parameter, which reaches `untyped`.
|
|
36
34
|
def global_for_name: (String | Symbol name, ?builtin: bool) -> Type::t?
|
|
37
35
|
def class_known?: (String | Symbol name) -> bool
|
|
38
36
|
def rbs_module?: (String | Symbol name) -> bool
|
|
@@ -57,7 +55,8 @@ module Rigor
|
|
|
57
55
|
attr_reader libraries: Array[String]
|
|
58
56
|
attr_reader signature_paths: Array[String | _ToPath]
|
|
59
57
|
attr_reader cache_store: untyped?
|
|
60
|
-
# sig-gen gap: #160 — sig-gen emits no `attr_reader` for the loader's readers; typed as the initializer stores
|
|
58
|
+
# sig-gen gap: #160 — sig-gen emits no `attr_reader` for the loader's readers; typed as the initializer stores
|
|
59
|
+
# it.
|
|
61
60
|
attr_reader deferred_signature_paths: Array[Pathname]
|
|
62
61
|
|
|
63
62
|
def self.default: () -> RbsLoader
|
|
@@ -82,6 +81,9 @@ module Rigor
|
|
|
82
81
|
def singleton_extended_module_names: (String | Symbol class_name) -> Array[String]
|
|
83
82
|
def constant_type: (String name) -> Type::t?
|
|
84
83
|
def constant_names: () -> Array[String]
|
|
84
|
+
# sig-gen gap: #2326 — the answer is `global_declarations[name.to_sym]&.first`, a lookup in the loader's memo
|
|
85
|
+
# hash `@state`, which sig-gen skips as untyped.
|
|
86
|
+
def global_type: (String | Symbol name) -> Type::t?
|
|
85
87
|
def each_known_class_name: () { (String name) -> void } -> void
|
|
86
88
|
| () -> ::Enumerator[String, void]
|
|
87
89
|
end
|