rigortype 0.3.8 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/data/capability_roles/capability_roles.rbs +36 -0
- data/data/core_overlay/enumerable.rbs +51 -0
- data/data/core_overlay/enumerator.rbs +84 -0
- data/data/core_overlay/hash_rbs3.rbs +41 -0
- data/data/core_overlay/process.rbs +40 -0
- data/data/core_overlay/string_io.rbs +33 -0
- data/data/effects/core.yml +3 -3
- data/data/gem_overlay/activesupport/core_ext.rbs +236 -17
- data/docs/handbook/02-everyday-types.md +17 -14
- data/docs/handbook/03-narrowing.md +132 -14
- data/docs/handbook/04-tuples-and-shapes.md +8 -6
- 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 +19 -1
- data/docs/handbook/10-sorbet.md +9 -10
- data/docs/handbook/11-sig-gen.md +525 -13
- 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 +95 -6
- data/docs/manual/03-configuration.md +18 -0
- data/docs/manual/04-diagnostics.md +15 -0
- data/docs/manual/07-plugins.md +15 -5
- data/docs/manual/08-skills.md +23 -2
- data/docs/manual/10-mcp-server.md +3 -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 +46 -8
- data/docs/manual/18-removing-dead-code.md +10 -8
- data/docs/manual/19-effect-labels.md +10 -0
- data/docs/manual/plugins/README.md +7 -0
- data/docs/manual/plugins/rigor-actioncable.md +8 -1
- data/docs/manual/plugins/rigor-actionmailer.md +7 -0
- data/docs/manual/plugins/rigor-actionpack.md +261 -0
- data/docs/manual/plugins/rigor-active-model-serializers.md +153 -0
- data/docs/manual/plugins/rigor-activejob.md +7 -0
- data/docs/manual/plugins/rigor-activerecord.md +138 -4
- data/docs/manual/plugins/rigor-activestorage.md +8 -1
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +43 -7
- data/docs/manual/plugins/rigor-grape.md +106 -0
- data/docs/manual/plugins/rigor-graphql.md +23 -2
- data/docs/manual/plugins/rigor-pundit.md +8 -1
- data/docs/manual/plugins/rigor-rails-i18n.md +10 -5
- data/docs/manual/plugins/rigor-rails-routes.md +7 -0
- data/docs/manual/plugins/rigor-rbs-inline.md +229 -1
- data/docs/manual/plugins/rigor-sidekiq.md +8 -1
- data/docs/manual/plugins/rigor-sorbet.md +21 -5
- data/exe/rigor +19 -4
- data/lib/rigor/analysis/baseline.rb +3 -3
- 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/declaration_sourced_guard.rb +167 -2
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +10 -2
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +189 -0
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +6 -4
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +15 -6
- data/lib/rigor/analysis/check_rules/rule_ids.rb +21 -6
- data/lib/rigor/analysis/check_rules/rule_walk.rb +41 -5
- 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/source_arity.rb +323 -0
- data/lib/rigor/analysis/check_rules/special_global_setters.rb +146 -0
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +38 -4
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +0 -1
- data/lib/rigor/analysis/check_rules.rb +718 -79
- data/lib/rigor/analysis/crash_signature.rb +8 -24
- data/lib/rigor/analysis/dependency_recorder.rb +23 -0
- 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 +15 -1
- data/lib/rigor/analysis/incremental.rb +42 -0
- data/lib/rigor/analysis/incremental_session.rb +117 -26
- data/lib/rigor/analysis/plugin_fact_fingerprint.rb +0 -1
- data/lib/rigor/analysis/project_scan.rb +11 -1
- data/lib/rigor/analysis/reachability/graph.rb +3 -5
- data/lib/rigor/analysis/reachability/plugin_roots.rb +5 -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 +3 -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 +131 -1
- data/lib/rigor/analysis/run_cache_key.rb +21 -12
- 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 +340 -33
- data/lib/rigor/analysis/runner/effect_annotation_residual_pass.rb +2 -3
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +18 -14
- data/lib/rigor/analysis/runner/pool_coordinator.rb +357 -97
- data/lib/rigor/analysis/runner/project_pre_passes.rb +38 -13
- data/lib/rigor/analysis/runner/run_snapshots.rb +6 -1
- data/lib/rigor/analysis/runner.rb +407 -51
- data/lib/rigor/analysis/template_unit_collector.rb +303 -0
- data/lib/rigor/analysis/template_unit_paths.rb +91 -0
- data/lib/rigor/analysis/template_unit_positions.rb +293 -0
- data/lib/rigor/analysis/template_units.rb +399 -0
- data/lib/rigor/analysis/worker_session.rb +62 -20
- data/lib/rigor/bleeding_edge.rb +10 -24
- data/lib/rigor/builtins/hkt_builtins.rb +3 -2
- data/lib/rigor/builtins/imported_refinements.rb +159 -21
- data/lib/rigor/builtins/predefined_constant_refinements.rb +5 -7
- data/lib/rigor/builtins/regex_refinement.rb +21 -13
- data/lib/rigor/builtins/static_return_refinements.rb +7 -6
- data/lib/rigor/cache/annotation_location.rb +2 -4
- data/lib/rigor/cache/descriptor.rb +63 -20
- data/lib/rigor/cache/engine_source.rb +33 -5
- data/lib/rigor/cache/file_digest.rb +9 -1
- data/lib/rigor/cache/incremental_snapshot.rb +72 -6
- data/lib/rigor/cache/rbs_cache_producer.rb +4 -0
- 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 +112 -14
- data/lib/rigor/cache/rbs_environment.rb +8 -4
- data/lib/rigor/cache/rbs_known_class_names.rb +0 -3
- data/lib/rigor/cache/store.rb +76 -32
- data/lib/rigor/ci_detector.rb +1 -0
- 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 +4 -4
- data/lib/rigor/cli/docs_command.rb +6 -6
- 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 +4 -4
- data/lib/rigor/cli/plugins_command.rb +2 -1
- data/lib/rigor/cli/prism_colorizer.rb +1 -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 +212 -31
- data/lib/rigor/cli/skill_command.rb +2 -2
- data/lib/rigor/cli/skill_deep_probe.rb +4 -4
- data/lib/rigor/cli/skill_describe.rb +35 -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 +29 -11
- data/lib/rigor/cli/type_of_renderer.rb +20 -9
- data/lib/rigor/cli/type_of_template_probe.rb +189 -0
- 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 +89 -9
- data/lib/rigor/config_audit.rb +30 -5
- data/lib/rigor/configuration/severity_profile.rb +25 -9
- data/lib/rigor/configuration.rb +109 -7
- data/lib/rigor/effects/ancestry_recorder.rb +191 -0
- data/lib/rigor/effects/attribution.rb +12 -5
- data/lib/rigor/effects/callee_rule.rb +368 -0
- data/lib/rigor/effects/catalog.rb +7 -4
- data/lib/rigor/effects/collector.rb +11 -5
- data/lib/rigor/effects/config_envelopes.rb +15 -10
- data/lib/rigor/effects/definition_context.rb +179 -0
- data/lib/rigor/effects/definition_lines.rb +25 -6
- data/lib/rigor/effects/effect_table.rb +11 -4
- data/lib/rigor/effects/entry_points.rb +0 -2
- data/lib/rigor/effects/envelope_check.rb +9 -9
- data/lib/rigor/effects/envelope_index.rb +20 -8
- data/lib/rigor/effects/file_collection.rb +59 -5
- data/lib/rigor/effects/framework_units.rb +5 -7
- data/lib/rigor/effects/identity.rb +20 -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/local_ownership.rb +38 -12
- data/lib/rigor/effects/method_key.rb +22 -1
- data/lib/rigor/effects/mutation_classifier.rb +23 -12
- data/lib/rigor/effects/plugin_facts.rb +47 -37
- data/lib/rigor/effects/propagator.rb +297 -19
- data/lib/rigor/effects/registry.rb +1 -1
- data/lib/rigor/effects/scanner.rb +122 -73
- data/lib/rigor/effects/signature_sources.rb +4 -6
- data/lib/rigor/effects/snapshot.rb +12 -11
- data/lib/rigor/effects/snapshot_diff.rb +1 -1
- data/lib/rigor/effects/summary.rb +27 -4
- data/lib/rigor/effects/unit_scan.rb +393 -38
- data/lib/rigor/effects/unknown_label_check.rb +3 -8
- data/lib/rigor/effects/unknown_label_report.rb +3 -4
- data/lib/rigor/effects/visibility.rb +101 -0
- data/lib/rigor/environment/bundle_sig_discovery.rb +6 -6
- data/lib/rigor/environment/class_registry.rb +3 -1
- data/lib/rigor/environment/failure_slot.rb +2 -2
- data/lib/rigor/environment/installed_gem_set.rb +85 -0
- data/lib/rigor/environment/lockfile_resolver.rb +68 -4
- data/lib/rigor/environment/member_consistency/comparator.rb +708 -0
- data/lib/rigor/environment/member_consistency.rb +298 -0
- 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 +674 -79
- data/lib/rigor/environment.rb +174 -24
- data/lib/rigor/flow_contribution/merger.rb +0 -2
- data/lib/rigor/flow_contribution.rb +11 -13
- data/lib/rigor/hashing/xxh3.rb +264 -0
- data/lib/rigor/inference/acceptance.rb +292 -17
- data/lib/rigor/inference/block_auto_splat.rb +216 -0
- data/lib/rigor/inference/block_call_timing.rb +338 -0
- data/lib/rigor/inference/block_parameter_binder.rb +75 -30
- data/lib/rigor/inference/block_repetition.rb +71 -0
- data/lib/rigor/inference/body_fixpoint.rb +7 -6
- data/lib/rigor/inference/budget_trace.rb +3 -6
- data/lib/rigor/inference/builtins/method_catalog.rb +2 -1
- data/lib/rigor/inference/builtins/string_catalog.rb +1 -1
- data/lib/rigor/inference/captured_locals.rb +389 -18
- data/lib/rigor/inference/closure_escape_analyzer.rb +159 -17
- data/lib/rigor/inference/content_join.rb +200 -27
- data/lib/rigor/inference/coverage_scanner.rb +4 -6
- data/lib/rigor/inference/def_return_typer.rb +11 -7
- data/lib/rigor/inference/define_method_block_self.rb +64 -0
- data/lib/rigor/inference/dynamic_origin.rb +1 -1
- data/lib/rigor/inference/element_read_widening.rb +180 -0
- data/lib/rigor/inference/error_info.rb +196 -0
- data/lib/rigor/inference/expression_typer.rb +2124 -468
- data/lib/rigor/inference/external_ancestor_resolution.rb +267 -0
- data/lib/rigor/inference/fork_map.rb +5 -7
- data/lib/rigor/inference/fresh_frame_blocks.rb +127 -0
- data/lib/rigor/inference/global_write_census.rb +239 -0
- data/lib/rigor/inference/guard_rebinding.rb +447 -0
- data/lib/rigor/inference/hash_lookup_mutation.rb +88 -0
- data/lib/rigor/inference/hkt_reducer.rb +2 -3
- data/lib/rigor/inference/hkt_registry.rb +4 -7
- data/lib/rigor/inference/index_write_widening.rb +16 -7
- data/lib/rigor/inference/indexed_narrowing.rb +61 -9
- data/lib/rigor/inference/jump_targets.rb +82 -0
- data/lib/rigor/inference/last_line/implicit_self.rb +210 -0
- data/lib/rigor/inference/last_line/self_evidence.rb +329 -0
- data/lib/rigor/inference/last_line.rb +340 -0
- data/lib/rigor/inference/last_status.rb +144 -0
- data/lib/rigor/inference/macro_block_self_type.rb +168 -21
- data/lib/rigor/inference/match_rebinding/calls.rb +281 -0
- data/lib/rigor/inference/match_rebinding/frame.rb +148 -0
- data/lib/rigor/inference/match_rebinding/operands.rb +236 -0
- data/lib/rigor/inference/match_rebinding/self_calls.rb +83 -0
- data/lib/rigor/inference/match_rebinding.rb +392 -0
- data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +36 -0
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +87 -33
- 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/facet_distribution.rb +147 -0
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/hash_transform_keys_folding.rb +191 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +6 -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/match_data_folding.rb +159 -0
- 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 +165 -111
- data/lib/rigor/inference/method_dispatcher/process_folding.rb +56 -0
- data/lib/rigor/inference/method_dispatcher/proven_overload.rb +72 -0
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +82 -0
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +1046 -69
- 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/self_substitute.rb +142 -0
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +129 -54
- 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 +5 -6
- 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 +225 -25
- data/lib/rigor/inference/method_parameter_binder.rb +12 -9
- data/lib/rigor/inference/multi_target_binder.rb +341 -55
- data/lib/rigor/inference/mutation_rejoin.rb +171 -0
- data/lib/rigor/inference/mutation_widening.rb +156 -85
- data/lib/rigor/inference/narrowing.rb +835 -162
- data/lib/rigor/inference/operand_effects.rb +167 -0
- data/lib/rigor/inference/operand_walk.rb +88 -0
- data/lib/rigor/inference/optimistic_origin.rb +153 -16
- data/lib/rigor/inference/origin_lookup.rb +2 -3
- data/lib/rigor/inference/parameter_inference_collector.rb +7 -7
- data/lib/rigor/inference/pre_eval_constants.rb +6 -5
- data/lib/rigor/inference/precision_scanner.rb +3 -4
- data/lib/rigor/inference/project_method_ownership.rb +136 -0
- data/lib/rigor/inference/project_patched_methods.rb +9 -4
- data/lib/rigor/inference/project_patched_scanner.rb +10 -6
- 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 +93 -4
- data/lib/rigor/inference/receiver_blind_block.rb +219 -0
- data/lib/rigor/inference/refinement_mutation.rb +76 -0
- data/lib/rigor/inference/repeated_or_writes.rb +463 -0
- data/lib/rigor/inference/return_barrier.rb +54 -0
- data/lib/rigor/inference/rewrite_mutation.rb +120 -0
- data/lib/rigor/inference/scope_indexer.rb +5228 -627
- data/lib/rigor/inference/statement_evaluator.rb +3452 -595
- data/lib/rigor/inference/stored_block_call.rb +54 -0
- data/lib/rigor/inference/string_mutation.rb +97 -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/unknown_store_widening.rb +200 -0
- data/lib/rigor/inference/unthreaded_rebinds.rb +282 -0
- 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 +0 -1
- data/lib/rigor/language_server/diagnostic_publisher.rb +7 -6
- 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 +4 -4
- data/lib/rigor/language_server/incremental_sync.rb +6 -6
- data/lib/rigor/language_server/project_context.rb +7 -8
- 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/mcp/server.rb +2 -1
- data/lib/rigor/plugin/base.rb +258 -26
- data/lib/rigor/plugin/box_probe.rb +91 -0
- data/lib/rigor/plugin/bundled_catalog.rb +167 -0
- data/lib/rigor/plugin/effect_attribution.rb +65 -11
- 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 +33 -13
- data/lib/rigor/plugin/macro/block_as_method.rb +45 -6
- 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 +94 -11
- data/lib/rigor/plugin/registry.rb +76 -12
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +21 -4
- data/lib/rigor/plugin/template_unit.rb +196 -0
- data/lib/rigor/plugin/trust_policy.rb +2 -4
- data/lib/rigor/plugin/type_node_resolver.rb +3 -3
- data/lib/rigor/plugin.rb +1 -0
- 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 +14 -12
- data/lib/rigor/protection/kill_signature.rb +1 -4
- data/lib/rigor/protection/measurement_integrity.rb +1 -3
- data/lib/rigor/protection/mutation_cache.rb +7 -11
- data/lib/rigor/protection/mutation_scanner.rb +12 -15
- data/lib/rigor/protection/mutator.rb +2 -1
- data/lib/rigor/protection/test_suite_oracle.rb +5 -5
- data/lib/rigor/rbs_extended/conformance_checker.rb +4 -3
- data/lib/rigor/rbs_extended/envelope_scanner.rb +4 -6
- data/lib/rigor/rbs_extended/reporter.rb +36 -10
- data/lib/rigor/rbs_extended.rb +88 -21
- data/lib/rigor/reflection/constant_ancestors.rb +97 -0
- data/lib/rigor/reflection/constant_path.rb +139 -0
- data/lib/rigor/reflection.rb +93 -110
- data/lib/rigor/runtime/jit.rb +6 -8
- data/lib/rigor/scope/discovery_index.rb +165 -2
- data/lib/rigor/scope.rb +1041 -32
- data/lib/rigor/sig_gen/alias_index.rb +289 -0
- data/lib/rigor/sig_gen/classification.rb +22 -5
- data/lib/rigor/sig_gen/declaration_equivalence.rb +127 -0
- data/lib/rigor/sig_gen/effect_annotation.rb +202 -0
- data/lib/rigor/sig_gen/generator.rb +673 -53
- data/lib/rigor/sig_gen/inline_declarations.rb +184 -0
- 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/method_candidate.rb +47 -3
- data/lib/rigor/sig_gen/observation_collector.rb +18 -16
- 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 +128 -14
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +154 -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/write_result.rb +19 -3
- data/lib/rigor/sig_gen/writer.rb +189 -41
- data/lib/rigor/sig_gen.rb +3 -0
- 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 +0 -6
- data/lib/rigor/source/parameter_envelope.rb +72 -0
- data/lib/rigor/source.rb +1 -0
- 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 +144 -5
- data/lib/rigor/type/data_class.rb +2 -2
- data/lib/rigor/type/data_instance.rb +4 -4
- data/lib/rigor/type/difference.rb +1 -0
- data/lib/rigor/type/float_range.rb +128 -0
- data/lib/rigor/type/hash_shape.rb +6 -6
- data/lib/rigor/type/integer_range.rb +13 -8
- data/lib/rigor/type/nominal.rb +8 -2
- data/lib/rigor/type/refined.rb +4 -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/lib/rigor.rb +1 -0
- 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/effects.rb +1 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +10 -5
- 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 +14 -4
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +32 -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/controller_scan.rb +96 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/effects.rb +65 -8
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/erb_compiler.rb +270 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/render_locals.rb +402 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +370 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_units.rb +132 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +264 -3
- data/plugins/rigor-actionpack/sig/action_controller.rbs +71 -0
- data/plugins/rigor-actionpack/sig/action_view.rbs +43 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_discoverer.rb +220 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_index.rb +56 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers.rb +263 -0
- data/plugins/rigor-active-model-serializers/lib/rigor-active-model-serializers.rb +7 -0
- data/plugins/rigor-active-model-serializers/sig/active_model_serializers.rbs +45 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +0 -4
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +2 -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 +10 -5
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +35 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/effects.rb +72 -12
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +383 -7
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +14 -6
- 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 +322 -41
- data/plugins/rigor-activerecord/sig/active_record/framework.rbs +123 -0
- data/plugins/rigor-activerecord/sig/active_record/relation.rbs +206 -31
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +26 -14
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +9 -2
- 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 +290 -19
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +1 -0
- data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +3 -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 +2 -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/types.rb +1 -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-grape/lib/rigor/plugin/grape.rb +141 -0
- data/plugins/rigor-grape/lib/rigor-grape.rb +6 -0
- data/plugins/rigor-grape/sig/grape.rbs +263 -0
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +8 -6
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +78 -5
- data/plugins/rigor-graphql/sig/graphql.rbs +485 -0
- 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 +2 -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 +12 -7
- 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 +36 -37
- 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 +0 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +5 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +3 -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 +10 -17
- 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/same_line_annotations.rb +149 -0
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +324 -18
- 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 +2 -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 +10 -5
- 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 +3 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +7 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +51 -6
- data/plugins/rigor-sorbet/sig/sorbet.rbs +277 -0
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +1 -0
- data/sig/rigor/analysis/baseline.rbs +69 -7
- data/sig/rigor/analysis/fact_store.rbs +1 -1
- data/sig/rigor/analysis/project_scan.rbs +74 -0
- data/sig/rigor/analysis/reachability/scan_cache.rbs +12 -0
- data/sig/rigor/cache.rbs +2 -3
- data/sig/rigor/effects/config_envelopes.rbs +100 -0
- data/sig/rigor/effects/effect_table.rbs +60 -0
- data/sig/rigor/effects/envelope.rbs +97 -0
- data/sig/rigor/effects/envelope_index.rbs +33 -0
- data/sig/rigor/effects/file_collection.rbs +81 -0
- data/sig/rigor/effects/label.rbs +26 -0
- data/sig/rigor/effects/label_set.rbs +46 -0
- data/sig/rigor/effects/method_key.rbs +24 -0
- data/sig/rigor/effects/origin.rbs +50 -0
- data/sig/rigor/effects/plugin_facts.rbs +141 -0
- data/sig/rigor/effects/registry.rbs +68 -0
- data/sig/rigor/effects/summary.rbs +50 -0
- data/sig/rigor/effects/taint_cause.rbs +12 -0
- data/sig/rigor/environment.rbs +17 -10
- data/sig/rigor/inference/optimistic_origin.rbs +10 -0
- data/sig/rigor/inference.rbs +9 -14
- data/sig/rigor/plugin/additional_initializer.rbs +36 -0
- data/sig/rigor/plugin/base.rbs +30 -7
- data/sig/rigor/plugin/effect_ancestry.rbs +27 -0
- data/sig/rigor/plugin/effect_attribution.rbs +66 -0
- data/sig/rigor/plugin/effect_edge.rbs +33 -0
- data/sig/rigor/plugin/effect_entry_points.rbs +25 -0
- data/sig/rigor/plugin/io_boundary.rbs +4 -0
- data/sig/rigor/plugin/loader.rbs +3 -3
- data/sig/rigor/plugin/manifest.rbs +51 -11
- data/sig/rigor/plugin/protocol_contract.rbs +68 -0
- data/sig/rigor/plugin/registry.rbs +62 -1
- data/sig/rigor/plugin.rbs +1 -1
- data/sig/rigor/rbs_extended.rbs +1 -1
- data/sig/rigor/reflection.rbs +9 -6
- data/sig/rigor/scope.rbs +148 -12
- data/sig/rigor/sig_gen/skip_reason_catalog.rbs +21 -0
- data/sig/rigor/source.rbs +4 -4
- data/sig/rigor/testing.rbs +10 -4
- data/sig/rigor/type.rbs +33 -1
- data/sig/rigor.rbs +39 -20
- data/skills/rigor-ask/SKILL.md +16 -11
- data/skills/rigor-baseline-reduce/SKILL.md +4 -6
- data/skills/rigor-ci-setup/SKILL.md +17 -21
- data/skills/rigor-doctor/SKILL.md +24 -22
- data/skills/rigor-doctor/references/01-checks.md +97 -33
- data/skills/rigor-editor-setup/SKILL.md +6 -4
- data/skills/rigor-mcp-setup/SKILL.md +5 -4
- data/skills/rigor-monkeypatch-resolve/SKILL.md +5 -3
- data/skills/rigor-next-steps/SKILL.md +4 -2
- data/skills/rigor-plugin-author/SKILL.md +19 -23
- data/skills/rigor-plugin-author/references/01-plan-and-scaffold.md +9 -8
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +25 -27
- data/skills/rigor-plugin-author/references/03-test-and-ship.md +6 -8
- data/skills/rigor-plugin-review/SKILL.md +6 -4
- data/skills/rigor-plugin-review/references/01-best-practices-checklist.md +2 -1
- data/skills/rigor-plugin-tune/SKILL.md +4 -2
- data/skills/rigor-project-init/SKILL.md +15 -10
- data/skills/rigor-project-init/references/01-detect.md +13 -9
- data/skills/rigor-project-init/references/02-configure.md +43 -14
- data/skills/rigor-project-init/references/03-baseline-and-bugs.md +14 -14
- data/skills/rigor-project-init/references/04-sig-uplift.md +27 -14
- data/skills/rigor-project-init/references/06-agent-contract.md +67 -0
- data/skills/rigor-protection-uplift/SKILL.md +4 -6
- data/skills/rigor-rbs-setup/SKILL.md +4 -2
- data/skills/rigor-type-oracle/SKILL.md +226 -0
- data/skills/rigor-type-oracle/references/01-oracle-commands.md +265 -0
- data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +52 -0
- data/skills/rigor-type-oracle/references/03-gap-protocol.md +125 -0
- data/skills/rigor-unused-adjudicate/SKILL.md +12 -7
- data/skills/rigor-upgrade/SKILL.md +13 -8
- metadata +133 -3
- data/lib/rigor/cli/probe_environment.rb +0 -85
- data/sig/rigor/inference/builtins/numeric_catalog.rbs +0 -3
|
@@ -68,6 +68,77 @@ class Object
|
|
|
68
68
|
|
|
69
69
|
# `core_ext/object/inclusion` — `x.in?([a, b])` / `x.in?(1..10)`.
|
|
70
70
|
def in?: (untyped) -> bool
|
|
71
|
+
# `in?(another_object) ? self : nil` — `params[:kind].presence_in(%w[a b])`.
|
|
72
|
+
def presence_in: (untyped) -> self?
|
|
73
|
+
|
|
74
|
+
# Issue #673 — `core_ext/object/to_query`, `core_ext/object/duplicable` and
|
|
75
|
+
# `core_ext/object/instance_variables` all hang off `Object`, so every
|
|
76
|
+
# RBS-known receiver reaches them; declaring them only on `Hash` (as
|
|
77
|
+
# `to_param` / `to_query` were) or only on `NilClass` (as `duplicable?` /
|
|
78
|
+
# `instance_values` were) left `"x".to_param`, `1.duplicable?` and friends a
|
|
79
|
+
# `call.undefined-method` on ordinary Rails code.
|
|
80
|
+
#
|
|
81
|
+
# `to_param` is `to_s`; `to_query(key)` interpolates two `CGI.escape` results.
|
|
82
|
+
# `key` is `untyped` because the body only calls `to_param` on it, and both
|
|
83
|
+
# `:name` and `"user[name]"` are ordinary call sites.
|
|
84
|
+
def to_param: () -> String
|
|
85
|
+
def to_query: (untyped key) -> String
|
|
86
|
+
|
|
87
|
+
# `bool` and not `true`: `Object#duplicable?` answers true, but the
|
|
88
|
+
# `Singleton` (and, on a Ruby where methods are not duplicable, `Method` /
|
|
89
|
+
# `UnboundMethod`) overrides answer false. `-> true` on the universal
|
|
90
|
+
# receiver would make every `if x.duplicable?` an always-truthy branch —
|
|
91
|
+
# a false positive on the only shape anybody writes.
|
|
92
|
+
def duplicable?: () -> bool
|
|
93
|
+
|
|
94
|
+
# Keys without the leading `@` for `instance_values`, with it for
|
|
95
|
+
# `instance_variable_names`.
|
|
96
|
+
def instance_values: () -> Hash[String, untyped]
|
|
97
|
+
def instance_variable_names: () -> Array[String]
|
|
98
|
+
|
|
99
|
+
# `core_ext/object/deep_dup` — `duplicable? ? dup : self`, plus `Array`
|
|
100
|
+
# (`map(&:deep_dup)`), `Hash` and `Module` overrides. `self` over-claims on
|
|
101
|
+
# an `Array` subclass, whose override answers a plain `Array`. Declared on
|
|
102
|
+
# `Object` and not only on `Hash`, where it sat alone: `[[1], [2]].deep_dup`
|
|
103
|
+
# is the common shape.
|
|
104
|
+
def deep_dup: () -> self
|
|
105
|
+
|
|
106
|
+
# `core_ext/object/with` (ActiveSupport 7.1+) — sets each keyword through
|
|
107
|
+
# its public writer, yields `self`, and restores the old values in an
|
|
108
|
+
# `ensure`; the answer is the block's. There is no blockless form: `yield` without a block raises.
|
|
109
|
+
# ActiveSupport `undef_method`s it on `NilClass`, `TrueClass`, `FalseClass`,
|
|
110
|
+
# `Integer`, `Float` and `Symbol`, which RBS cannot express, so `1.with(a: 1)`
|
|
111
|
+
# resolves here where Ruby raises — a missed error, not a false one.
|
|
112
|
+
# `Data#with` (core) is a subclass override and keeps its own `-> self`.
|
|
113
|
+
def with: [T] (**untyped attributes) { (self) -> T } -> T
|
|
114
|
+
|
|
115
|
+
# `core_ext/object/with_options` — without a block, the
|
|
116
|
+
# `ActiveSupport::OptionMerger` proxy (not declared here); with one, the
|
|
117
|
+
# block's value. A zero-arity block is `instance_eval`ed on the proxy, the
|
|
118
|
+
# `with_options dependent: :destroy do has_many … end` model-body shape.
|
|
119
|
+
def with_options: (untyped options) -> untyped
|
|
120
|
+
| [T] (untyped options) { (?) -> T } -> T
|
|
121
|
+
|
|
122
|
+
# `core_ext/string/output_safety` — `false` on `Object`, `true` on
|
|
123
|
+
# `Numeric`, the buffer's own state on `ActiveSupport::SafeBuffer`. `bool`
|
|
124
|
+
# for the reason `duplicable?` is: `-> false` on the universal receiver makes
|
|
125
|
+
# every `if x.html_safe?` an always-falsy branch on the subclasses that answer
|
|
126
|
+
# true.
|
|
127
|
+
def html_safe?: () -> bool
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# ---------------------------------------------------------------
|
|
131
|
+
# Kernel — `core_ext/kernel/singleton_class`
|
|
132
|
+
# ---------------------------------------------------------------
|
|
133
|
+
|
|
134
|
+
# `singleton_class.class_eval(*args, &block)` on any object. Declared on
|
|
135
|
+
# `Kernel`, where ActiveSupport defines it; a `Module` receiver still answers
|
|
136
|
+
# core `Module#class_eval`, which is its own alias of `module_eval`. The two
|
|
137
|
+
# overloads mirror that `module_eval`: a string, or a block given the
|
|
138
|
+
# singleton class.
|
|
139
|
+
module Kernel
|
|
140
|
+
def class_eval: (string code, ?string? filename, ?int lineno) -> untyped
|
|
141
|
+
| [U] () { (untyped singleton_class) -> U } -> U
|
|
71
142
|
end
|
|
72
143
|
|
|
73
144
|
# `nil.blank?` / `nil.present?` / `nil.try` are the most frequent
|
|
@@ -80,16 +151,24 @@ class NilClass
|
|
|
80
151
|
def try!: (*untyped) -> nil
|
|
81
152
|
def duplicable?: () -> true
|
|
82
153
|
def instance_values: () -> Hash[String, untyped]
|
|
154
|
+
# `core_ext/object/to_query` overrides `to_param` on the three singleton
|
|
155
|
+
# values to return `self` rather than `Object#to_param`'s `to_s`, so the
|
|
156
|
+
# `Object` row above would carry a wrong return here. `NilClass#to_query`
|
|
157
|
+
# is its own method (`CGI.escape(key.to_param)`), still a String.
|
|
158
|
+
def to_param: () -> nil
|
|
159
|
+
def to_query: (untyped key) -> String
|
|
83
160
|
end
|
|
84
161
|
|
|
85
162
|
class TrueClass
|
|
86
163
|
def blank?: () -> false
|
|
87
164
|
def present?: () -> true
|
|
165
|
+
def to_param: () -> true
|
|
88
166
|
end
|
|
89
167
|
|
|
90
168
|
class FalseClass
|
|
91
169
|
def blank?: () -> true
|
|
92
170
|
def present?: () -> false
|
|
171
|
+
def to_param: () -> false
|
|
93
172
|
end
|
|
94
173
|
|
|
95
174
|
# ---------------------------------------------------------------
|
|
@@ -116,6 +195,10 @@ class String
|
|
|
116
195
|
def titlecase: () -> String
|
|
117
196
|
def dasherize: () -> String
|
|
118
197
|
def upcase_first: () -> String
|
|
198
|
+
def downcase_first: () -> String # ActiveSupport 7.1+
|
|
199
|
+
|
|
200
|
+
# `core_ext/string/behavior` — the `acts_like?(:string)` duck-type hook.
|
|
201
|
+
def acts_like_string?: () -> true
|
|
119
202
|
|
|
120
203
|
# `core_ext/string/filters`
|
|
121
204
|
def squish: () -> String
|
|
@@ -149,6 +232,12 @@ class String
|
|
|
149
232
|
def to_datetime: () -> DateTime
|
|
150
233
|
def to_hours: () -> Float
|
|
151
234
|
|
|
235
|
+
# `core_ext/string/zones` — `Time.find_zone!(zone).parse(self)`, or
|
|
236
|
+
# `to_time` when no zone is set. `untyped` like the `Time` / `Date` rows:
|
|
237
|
+
# the parse answers an `ActiveSupport::TimeWithZone`, or `nil` on a string
|
|
238
|
+
# with no date parts.
|
|
239
|
+
def in_time_zone: (?untyped zone) -> untyped
|
|
240
|
+
|
|
152
241
|
# `core_ext/string/access`
|
|
153
242
|
def at: (Integer | Range[Integer] | Regexp position) -> String?
|
|
154
243
|
def from: (Integer position) -> String
|
|
@@ -161,6 +250,7 @@ class String
|
|
|
161
250
|
|
|
162
251
|
# `core_ext/string/multibyte`
|
|
163
252
|
def mb_chars: () -> untyped
|
|
253
|
+
def is_utf8?: () -> bool
|
|
164
254
|
|
|
165
255
|
# `core_ext/string/inquiry`
|
|
166
256
|
def inquiry: () -> untyped # ActiveSupport::StringInquirer
|
|
@@ -169,6 +259,17 @@ class String
|
|
|
169
259
|
def exclude?: (String) -> bool
|
|
170
260
|
end
|
|
171
261
|
|
|
262
|
+
# ---------------------------------------------------------------
|
|
263
|
+
# Symbol — `core_ext/symbol/starts_ends_with`
|
|
264
|
+
# ---------------------------------------------------------------
|
|
265
|
+
|
|
266
|
+
# `alias_method`s of core `start_with?` / `end_with?`, declared with the core
|
|
267
|
+
# parameter lists.
|
|
268
|
+
class Symbol
|
|
269
|
+
def starts_with?: (*Regexp | string prefixes) -> bool
|
|
270
|
+
def ends_with?: (*string suffixes) -> bool
|
|
271
|
+
end
|
|
272
|
+
|
|
172
273
|
# ---------------------------------------------------------------
|
|
173
274
|
# Integer — `core_ext/integer/*`
|
|
174
275
|
# ---------------------------------------------------------------
|
|
@@ -263,6 +364,16 @@ end
|
|
|
263
364
|
# `spec/rigor/environment/activesupport_overlay_parity_spec.rb`); every method not listed here stays
|
|
264
365
|
# undeclared and silently `Dynamic` rather than guessed.
|
|
265
366
|
module ActiveSupport
|
|
367
|
+
# Issue #534 item 7 — the `ActiveSupport::Concern` twin of the plugin's declaration. The plugin file
|
|
368
|
+
# carries the reasoning; the short version is that naming the module makes `extend ActiveSupport::Concern`
|
|
369
|
+
# resolve, and the three members have to come with it so that `included do … end` does not become a false
|
|
370
|
+
# `call.undefined-method` on a now-RBS-known module.
|
|
371
|
+
module Concern
|
|
372
|
+
def included: (?untyped base) ?{ (?) -> untyped } -> untyped
|
|
373
|
+
def prepended: (?untyped base) ?{ (?) -> untyped } -> untyped
|
|
374
|
+
def class_methods: () { (?) -> untyped } -> untyped
|
|
375
|
+
end
|
|
376
|
+
|
|
266
377
|
class Duration
|
|
267
378
|
# The `ago` family (issue #659). `since(time = ::Time.current)` and `ago(time = ::Time.current)` are
|
|
268
379
|
# the only two real methods; `from_now` / `after` alias the first and `until` / `before` the second,
|
|
@@ -272,23 +383,25 @@ module ActiveSupport
|
|
|
272
383
|
# `GEM_OVERLAY_OPEN_RECEIVERS` cannot suppress since it protects a Duration receiver, not a `Time`
|
|
273
384
|
# one. #658 declared that surface and #670 the `Date` / `DateTime` twins, so the chains resolve now.
|
|
274
385
|
#
|
|
275
|
-
#
|
|
276
|
-
# `
|
|
277
|
-
#
|
|
278
|
-
#
|
|
279
|
-
#
|
|
280
|
-
#
|
|
281
|
-
|
|
386
|
+
# Since #673 the no-argument form answers `ActiveSupport::TimeWithZone`, the class these really
|
|
387
|
+
# build off `::Time.current` under a zone, declared below as a `::Time` SUBCLASS. That keeps every
|
|
388
|
+
# `Time`-typed chain and parameter working while `1.hour.ago.time_zone` stops being a false
|
|
389
|
+
# `call.undefined-method`. A `Time | ActiveSupport::TimeWithZone` union was measured and rejected —
|
|
390
|
+
# it types every downstream call `Dynamic[top]`. The with-an-argument form stays `untyped` because
|
|
391
|
+
# the runtime return depends on the argument's class AND on whether the duration carries a
|
|
392
|
+
# date-scale part (`(1.month).ago(Date.today)` answers a `Date`; `(30.minutes).ago(Date.today)` a
|
|
393
|
+
# `TimeWithZone`).
|
|
394
|
+
def ago: () -> TimeWithZone
|
|
282
395
|
| (untyped time) -> untyped
|
|
283
|
-
def until: () ->
|
|
396
|
+
def until: () -> TimeWithZone
|
|
284
397
|
| (untyped time) -> untyped
|
|
285
|
-
def before: () ->
|
|
398
|
+
def before: () -> TimeWithZone
|
|
286
399
|
| (untyped time) -> untyped
|
|
287
|
-
def since: () ->
|
|
400
|
+
def since: () -> TimeWithZone
|
|
288
401
|
| (untyped time) -> untyped
|
|
289
|
-
def from_now: () ->
|
|
402
|
+
def from_now: () -> TimeWithZone
|
|
290
403
|
| (untyped time) -> untyped
|
|
291
|
-
def after: () ->
|
|
404
|
+
def after: () -> TimeWithZone
|
|
292
405
|
| (untyped time) -> untyped
|
|
293
406
|
|
|
294
407
|
# `to_i` / its `in_seconds` alias return `@value.to_i` — always Integer.
|
|
@@ -315,6 +428,54 @@ module ActiveSupport
|
|
|
315
428
|
# Float` is what stays honest without costing the common `parts[:days] * 2` chain anything.
|
|
316
429
|
def parts: () -> Hash[Symbol, Integer | Float]
|
|
317
430
|
end
|
|
431
|
+
|
|
432
|
+
# ---------------------------------------------------------------
|
|
433
|
+
# ActiveSupport::TimeWithZone — issue #673
|
|
434
|
+
# ---------------------------------------------------------------
|
|
435
|
+
#
|
|
436
|
+
# `Time.current` and the `Duration#ago` family really answer a `TimeWithZone`
|
|
437
|
+
# under a zone, and this class was not modelled at all, so the four readers a
|
|
438
|
+
# TWZ has and a `Time` does not — `time_zone`, `time`, `period`,
|
|
439
|
+
# `comparable_time` — were `call.undefined-method` on every `Time.current`
|
|
440
|
+
# receiver. Declaring them on `Time` would have been wrong: a plain `Time`
|
|
441
|
+
# genuinely lacks them.
|
|
442
|
+
#
|
|
443
|
+
# `< ::Time` rather than a `Time | TimeWithZone` union at the producers. The
|
|
444
|
+
# union was measured during #632 and rejected — it types every downstream
|
|
445
|
+
# call `Dynamic[top]`. Inheritance is the cheaper shape AND the honest one
|
|
446
|
+
# here: Rails overrides `TimeWithZone#is_a?` to answer true for `::Time`, so
|
|
447
|
+
# `Time` is the class Rails itself tells callers a TWZ is, and TWZ's
|
|
448
|
+
# `method_missing` forwards every name it does not define to the wrapped
|
|
449
|
+
# `::Time` — which is exactly what inheriting `Time`'s surface models. A TWZ
|
|
450
|
+
# therefore also satisfies every `Time`-typed parameter, and a chain through
|
|
451
|
+
# `Time.current` keeps resolving instead of collapsing.
|
|
452
|
+
#
|
|
453
|
+
# The cost, taken deliberately: `Time.current` answers a plain `Time` when
|
|
454
|
+
# `Time.zone` is nil, so `Time.current.time_zone` in a zone-less
|
|
455
|
+
# activesupport-only project is a real `NoMethodError` this now types. Rails
|
|
456
|
+
# sets `config.time_zone` ("UTC") by default, so the shape is rare, and the
|
|
457
|
+
# false positive it replaces fired on correct Rails code — which AGENTS.md
|
|
458
|
+
# ranks above the worst-case static reading.
|
|
459
|
+
class TimeWithZone < ::Time
|
|
460
|
+
# `Time`'s own `initialize` takes the `(year, month, …)` parts; inheriting
|
|
461
|
+
# it would make `TimeWithZone.new(utc, zone)` — how Rails constructs one —
|
|
462
|
+
# a `call.argument-type-mismatch`. `untyped` because the zone and period
|
|
463
|
+
# carriers (`ActiveSupport::TimeZone`, `TZInfo::TimezonePeriod`) are not
|
|
464
|
+
# declared anywhere in this overlay.
|
|
465
|
+
def initialize: (untyped utc_time, untyped time_zone, ?untyped local_time, ?untyped period) -> void
|
|
466
|
+
|
|
467
|
+
# The `attr_reader`; an `ActiveSupport::TimeZone`, undeclared here.
|
|
468
|
+
def time_zone: () -> untyped
|
|
469
|
+
|
|
470
|
+
# The wall-clock `::Time` in the zone. `utc` / `getutc` / `getgm` /
|
|
471
|
+
# `gmtime` are `Time`'s own names and stay inherited; `comparable_time` is
|
|
472
|
+
# the alias of `utc` that `Time` does not carry.
|
|
473
|
+
def time: () -> ::Time
|
|
474
|
+
def comparable_time: () -> ::Time
|
|
475
|
+
|
|
476
|
+
# A `TZInfo::TimezonePeriod`, undeclared here.
|
|
477
|
+
def period: () -> untyped
|
|
478
|
+
end
|
|
318
479
|
end
|
|
319
480
|
|
|
320
481
|
# ---------------------------------------------------------------
|
|
@@ -322,7 +483,10 @@ end
|
|
|
322
483
|
# ---------------------------------------------------------------
|
|
323
484
|
|
|
324
485
|
class Time
|
|
325
|
-
|
|
486
|
+
# `Time.zone ? Time.zone.now : Time.now` — an `ActiveSupport::TimeWithZone` under a zone, which
|
|
487
|
+
# since #673 is declared as a `::Time` subclass so the four TWZ-only readers resolve without the
|
|
488
|
+
# rest of the chain losing its `Time` typing. See the class's own note for the zone-less cost.
|
|
489
|
+
def self.current: () -> ActiveSupport::TimeWithZone
|
|
326
490
|
def self.zone: () -> untyped # ActiveSupport::TimeZone | nil
|
|
327
491
|
def self.zone=: (String | Symbol | untyped) -> untyped
|
|
328
492
|
|
|
@@ -666,6 +830,8 @@ class Array[unchecked out Elem]
|
|
|
666
830
|
def fourth: () -> Elem?
|
|
667
831
|
def fifth: () -> Elem?
|
|
668
832
|
def forty_two: () -> Elem?
|
|
833
|
+
def second_to_last: () -> Elem?
|
|
834
|
+
def third_to_last: () -> Elem?
|
|
669
835
|
|
|
670
836
|
# `core_ext/array/grouping`
|
|
671
837
|
def in_groups_of: (Integer number, ?untyped fill_with) -> Array[Array[Elem]]
|
|
@@ -687,6 +853,9 @@ class Array[unchecked out Elem]
|
|
|
687
853
|
# `core_ext/array/extract`
|
|
688
854
|
def extract!: () { (Elem) -> bool } -> Array[Elem]
|
|
689
855
|
|
|
856
|
+
# `core_ext/array/extract_options`
|
|
857
|
+
def extract_options!: () -> Hash[untyped, untyped]
|
|
858
|
+
|
|
690
859
|
# `core_ext/object/blank` / `core_ext/enumerable` — both
|
|
691
860
|
# ActiveSupport additions, shipped on Array specifically.
|
|
692
861
|
def compact_blank: () -> Array[Elem]
|
|
@@ -714,6 +883,13 @@ module Enumerable[unchecked out Elem]
|
|
|
714
883
|
def minimum: (Symbol | String) -> untyped
|
|
715
884
|
def sole: () -> Elem
|
|
716
885
|
def compact_blank: () -> Array[Elem]
|
|
886
|
+
def many?: () -> bool
|
|
887
|
+
| () { (Elem) -> boolish } -> bool
|
|
888
|
+
# `key` and `series` are untyped on purpose: the default `filter: true`
|
|
889
|
+
# path is `group_by(&key).values_at(*series)`, so a Proc key or a Set /
|
|
890
|
+
# Range series is correct Rails code. `filter:` is ActiveSupport 8.x;
|
|
891
|
+
# passing it on 7.x raises, which this unversioned row does not catch.
|
|
892
|
+
def in_order_of: (untyped key, untyped series, ?filter: boolish) -> Array[Elem]
|
|
717
893
|
end
|
|
718
894
|
|
|
719
895
|
# ---------------------------------------------------------------
|
|
@@ -735,6 +911,9 @@ class Hash[unchecked out K, unchecked out V]
|
|
|
735
911
|
def deep_transform_keys!: () { (K) -> K } -> self
|
|
736
912
|
def deep_transform_values: () { (V) -> untyped } -> Hash[K, untyped]
|
|
737
913
|
def deep_transform_values!: () { (V) -> untyped } -> self
|
|
914
|
+
# `alias_method`s of `symbolize_keys` / `symbolize_keys!`.
|
|
915
|
+
def to_options: () -> Hash[Symbol, V]
|
|
916
|
+
def to_options!: () -> self
|
|
738
917
|
|
|
739
918
|
# `core_ext/hash/deep_dup`
|
|
740
919
|
def deep_dup: () -> Hash[K, V]
|
|
@@ -744,6 +923,9 @@ class Hash[unchecked out K, unchecked out V]
|
|
|
744
923
|
| (Hash[K, V]) { (K, V, V) -> V } -> Hash[K, V]
|
|
745
924
|
def deep_merge!: (Hash[K, V]) -> self
|
|
746
925
|
| (Hash[K, V]) { (K, V, V) -> V } -> self
|
|
926
|
+
# `other.is_a?(Hash)` — the hook `ActiveSupport::DeepMergeable` asks before
|
|
927
|
+
# recursing into a value. `:nodoc:`, but public.
|
|
928
|
+
def deep_merge?: (untyped other) -> bool
|
|
747
929
|
|
|
748
930
|
# `core_ext/hash/except` — `Hash#except` is in core RBS as of
|
|
749
931
|
# Ruby 3.0+; `except!` is ActiveSupport-only. ActiveSupport
|
|
@@ -757,8 +939,10 @@ class Hash[unchecked out K, unchecked out V]
|
|
|
757
939
|
def to_param: (?String namespace) -> String
|
|
758
940
|
def to_xml: (**untyped) -> String
|
|
759
941
|
|
|
760
|
-
# `core_ext/hash/indifferent_access`
|
|
942
|
+
# `core_ext/hash/indifferent_access` — `nested_under_indifferent_access`
|
|
943
|
+
# is an `alias` of `with_indifferent_access`.
|
|
761
944
|
def with_indifferent_access: () -> untyped
|
|
945
|
+
def nested_under_indifferent_access: () -> untyped
|
|
762
946
|
|
|
763
947
|
# `core_ext/hash/conversions`
|
|
764
948
|
def self.from_xml: (String, ?Symbol disallowed_types) -> Hash[String, untyped]
|
|
@@ -768,14 +952,49 @@ class Hash[unchecked out K, unchecked out V]
|
|
|
768
952
|
def compact_blank: () -> Hash[K, V]
|
|
769
953
|
def compact_blank!: () -> self
|
|
770
954
|
|
|
771
|
-
# `core_ext/
|
|
772
|
-
def
|
|
955
|
+
# `core_ext/array/extract_options`
|
|
956
|
+
def extractable_options?: () -> bool
|
|
957
|
+
|
|
958
|
+
# `core_ext/hash/reverse_merge` — `other_hash.merge(self)`, so the result
|
|
959
|
+
# carries the argument's keys and values as well as the receiver's, the
|
|
960
|
+
# same shape as core `Hash#merge`. `-> Hash[K, V]` typed
|
|
961
|
+
# `opts.reverse_merge(size: 25, velocity: 10)` as `Hash[:size, 1]`.
|
|
962
|
+
def reverse_merge: [A, B] (Hash[A, B] other_hash) -> Hash[A | K, B | V]
|
|
773
963
|
def reverse_merge!: (Hash[K, V]) -> self
|
|
964
|
+
# `alias_method`s: `with_defaults` of `reverse_merge`, `with_defaults!`
|
|
965
|
+
# and `reverse_update` of `reverse_merge!`.
|
|
966
|
+
def with_defaults: [A, B] (Hash[A, B] other_hash) -> Hash[A | K, B | V]
|
|
967
|
+
def with_defaults!: (Hash[K, V]) -> self
|
|
968
|
+
def reverse_update: (Hash[K, V]) -> self
|
|
774
969
|
|
|
775
970
|
# `core_ext/hash/slice` — `Hash#except` is in core RBS (Ruby 3.0+);
|
|
776
971
|
# `Hash#slice` is in core RBS (Ruby 2.5+); the bang variants are
|
|
777
|
-
# ActiveSupport-only.
|
|
972
|
+
# ActiveSupport-only. `extract!` deletes the named keys and answers them
|
|
973
|
+
# as a new hash; a key the receiver lacks is skipped, not `nil`-filled.
|
|
778
974
|
def slice!: (*K) -> Hash[K, V]
|
|
975
|
+
def extract!: (*K) -> Hash[K, V]
|
|
976
|
+
end
|
|
977
|
+
|
|
978
|
+
# ---------------------------------------------------------------
|
|
979
|
+
# Range — `core_ext/range/*`
|
|
980
|
+
# ---------------------------------------------------------------
|
|
981
|
+
|
|
982
|
+
# `[out E]` matches core `range.rbs`. A reopening whose parameters differ in
|
|
983
|
+
# count or variance (`class Range`, `class Range[E]`) raises
|
|
984
|
+
# `RBS::GenericParameterMismatchError` and collapses `Range`.
|
|
985
|
+
class Range[out E]
|
|
986
|
+
# `core_ext/range/overlap` — an `alias` of `overlap?`, which rbs declares
|
|
987
|
+
# since Ruby 3.3 (ActiveSupport defines the method itself only on an older
|
|
988
|
+
# Ruby). `overlap?` is therefore NOT redeclared here: a second declaration
|
|
989
|
+
# is a `DuplicatedMethodDefinitionError` that collapses the whole class.
|
|
990
|
+
def overlaps?: (Range[untyped]) -> bool
|
|
991
|
+
|
|
992
|
+
# `core_ext/range/conversions` — `ActiveSupport::RangeWithFormat`, prepended
|
|
993
|
+
# onto `Range`. An unknown format falls back to `to_s`; `:db` answers `nil`
|
|
994
|
+
# for a beginless-and-endless range, which the declared `String` does not
|
|
995
|
+
# model — `(nil..nil).to_fs(:db)` is not a shape correct code writes.
|
|
996
|
+
def to_fs: (?Symbol format) -> String
|
|
997
|
+
def to_formatted_s: (?Symbol format) -> String
|
|
779
998
|
end
|
|
780
999
|
|
|
781
1000
|
# ---------------------------------------------------------------
|
|
@@ -25,7 +25,7 @@ n = ARGV.size
|
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
A vanilla checker says: `n: Integer`. Rigor says:
|
|
28
|
-
`n:
|
|
28
|
+
`n: Integer[0..]` (a non-negative integer — `Array#size` cannot
|
|
29
29
|
return a negative count).
|
|
30
30
|
|
|
31
31
|
The reason this matters: most diagnostics Rigor wants to fire
|
|
@@ -40,7 +40,7 @@ or narrow (`Constant<3>`, `non-empty-string`). The rest of
|
|
|
40
40
|
this chapter is the carrier zoo.
|
|
41
41
|
|
|
42
42
|
One note on notation before the zoo: angle brackets hold a
|
|
43
|
-
concrete value or bound — `Constant<3>`, `
|
|
43
|
+
concrete value or bound — `Constant<3>`, `Integer[0..]` —
|
|
44
44
|
while square brackets hold type parameters, exactly as in RBS
|
|
45
45
|
— `Nominal[String]`, `Hash[K, V]`, `Dynamic[top]`. A type
|
|
46
46
|
parameter names the type of a *part*: `Hash[K, V]` is a Hash
|
|
@@ -124,27 +124,30 @@ nominal carrier or `Dynamic[top]`.
|
|
|
124
124
|
|
|
125
125
|
Some integer-valued expressions produce a known range without
|
|
126
126
|
producing a single literal value. Rigor describes those with
|
|
127
|
-
`Type::IntegerRange`, displayed as `
|
|
127
|
+
`Type::IntegerRange`, displayed as `Integer[…]` around the Ruby
|
|
128
|
+
range literal that covers the values, `Integer[1..10]`:
|
|
128
129
|
|
|
129
130
|
```ruby
|
|
130
|
-
n = ARGV.size #=> dump_type:
|
|
131
|
-
m = n + 1 #=> dump_type:
|
|
132
|
-
double = n * 2 #=> dump_type:
|
|
131
|
+
n = ARGV.size #=> dump_type: Integer[0..]
|
|
132
|
+
m = n + 1 #=> dump_type: Integer[1..]
|
|
133
|
+
double = n * 2 #=> dump_type: Integer[0..]
|
|
133
134
|
```
|
|
134
135
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
136
|
+
The literal means what it means in Ruby: `Integer[0..]` is
|
|
137
|
+
every integer `(0..).cover?` accepts, an endless range is
|
|
138
|
+
unbounded above, a beginless one (`Integer[..-1]`) is unbounded
|
|
139
|
+
below, and `Integer[1...10]` is written back as `Integer[1..9]`
|
|
140
|
+
because for integers the two are the same set. Multiplication
|
|
141
|
+
preserves the floor, so `n * 2` stays `Integer[0..]`.
|
|
139
142
|
|
|
140
143
|
A handful of common ranges have shorter names:
|
|
141
144
|
|
|
142
145
|
| Spelling | Meaning |
|
|
143
146
|
| --- | --- |
|
|
144
|
-
| `positive-int` | `
|
|
145
|
-
| `non-negative-int` | `
|
|
146
|
-
| `negative-int` | `
|
|
147
|
-
| `non-positive-int` | `
|
|
147
|
+
| `positive-int` | `Integer[1..]` |
|
|
148
|
+
| `non-negative-int` | `Integer[0..]` |
|
|
149
|
+
| `negative-int` | `Integer[..-1]` |
|
|
150
|
+
| `non-positive-int` | `Integer[..0]` |
|
|
148
151
|
|
|
149
152
|
`Array#size`, `Array#length`, `Hash#size`, `String#size`, …
|
|
150
153
|
all carry `non-negative-int`. `Array#count` does too. Adding
|
|
@@ -77,6 +77,32 @@ unless x.is_a?(Integer)
|
|
|
77
77
|
end
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
+
A guard can also name a class the variable's type says it cannot
|
|
81
|
+
be. Inside such a branch the variable reads `bot`, so no call on
|
|
82
|
+
it is checked. That matters when the type is one Rigor inferred
|
|
83
|
+
or read from a signature: `$stdout` is typed `IO`, and a test runs
|
|
84
|
+
the same code with a `StringIO`, which is not an `IO` subclass, so
|
|
85
|
+
the guarded call below is correct code and stays quiet. A guard
|
|
86
|
+
on `$stdout`, `STDOUT` or another global or constant narrows the
|
|
87
|
+
same way:
|
|
88
|
+
|
|
89
|
+
```ruby
|
|
90
|
+
require "stringio"
|
|
91
|
+
|
|
92
|
+
def captured_output
|
|
93
|
+
out = STDOUT
|
|
94
|
+
if out.is_a?(StringIO)
|
|
95
|
+
assert_type("bot", out)
|
|
96
|
+
out.string
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The rest of the branch is still checked, and its `bot` variable
|
|
102
|
+
never reaches the code after it. A `case` drops such a branch
|
|
103
|
+
from its value (see below); keeping it is tracked in
|
|
104
|
+
[#1465](https://github.com/rigortype/rigor/issues/1465).
|
|
105
|
+
|
|
80
106
|
## Equality with literal values
|
|
81
107
|
|
|
82
108
|
Rigor narrows `==` and `!=` against trusted literal values:
|
|
@@ -107,7 +133,7 @@ matched member:
|
|
|
107
133
|
```ruby
|
|
108
134
|
case n
|
|
109
135
|
when 0 then :zero # Constant<0>
|
|
110
|
-
when 1..9 then :small #
|
|
136
|
+
when 1..9 then :small # Integer[1..9]
|
|
111
137
|
when 10 then :ten # Constant<10>
|
|
112
138
|
else :large # everything else
|
|
113
139
|
end
|
|
@@ -117,17 +143,78 @@ The result type unions the per-branch results. When the input
|
|
|
117
143
|
is a finite literal union, Rigor proves the `else` branch is
|
|
118
144
|
unreachable when every member is matched.
|
|
119
145
|
|
|
120
|
-
The same narrowing also works in reverse: when
|
|
121
|
-
|
|
122
|
-
|
|
146
|
+
The same narrowing also works in reverse: when an earlier clause
|
|
147
|
+
already covered the subject, or a `when <Class>` clause is
|
|
148
|
+
disjoint from the subject's type, the clause is dead — Rigor emits
|
|
123
149
|
[`flow.unreachable-clause`](08-understanding-errors.md) so you
|
|
124
150
|
can delete it. (It ships at `:info` under the default profile.)
|
|
125
151
|
|
|
152
|
+
A disjoint `when <Class>` is reported only when the subject's
|
|
153
|
+
type is what the code literally shows: a literal (`1`, `"s"`,
|
|
154
|
+
`:a`), an array or hash literal, a class object, or `nil` /
|
|
155
|
+
`true` / `false`. When the subject's type is one Rigor inferred
|
|
156
|
+
or read from a signature, the `when` is evidence that it can hold
|
|
157
|
+
something else, as in the `is_a?` example above, so the clause is
|
|
158
|
+
not reported. It is still read as `bot`, and the `case` value
|
|
159
|
+
drops it:
|
|
160
|
+
|
|
161
|
+
```ruby
|
|
162
|
+
require "stringio"
|
|
163
|
+
|
|
164
|
+
io = STDOUT
|
|
165
|
+
assert_type(":io", (case io when StringIO then :string_io else :io end))
|
|
166
|
+
|
|
167
|
+
count = 3
|
|
168
|
+
assert_type(":number", (case count when String then :text else :number end))
|
|
169
|
+
|
|
170
|
+
case io
|
|
171
|
+
when StringIO then puts io.string # not reported
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
case count
|
|
175
|
+
when String then puts count # flow.unreachable-clause
|
|
176
|
+
end
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Both values leave the `when` branch out. Of the two `case`
|
|
180
|
+
statements after them, only the second reports
|
|
181
|
+
`flow.unreachable-clause`. The check reads a `case` the code runs
|
|
182
|
+
as a statement or assigns to a variable; one passed straight to a
|
|
183
|
+
method, like the two `assert_type` lines, is not checked.
|
|
184
|
+
|
|
126
185
|
`case x; in pattern` (one-line pattern matching) narrows the
|
|
127
186
|
same way for the patterns Rigor understands — class checks,
|
|
128
187
|
literal equality, array / hash structural patterns. The
|
|
129
188
|
clause-reachability check extends to bare-class `in` patterns
|
|
130
|
-
(`in String` / `in MyClass => x`) too
|
|
189
|
+
(`in String` / `in MyClass => x`) too, under the same literal
|
|
190
|
+
rule.
|
|
191
|
+
|
|
192
|
+
## `respond_to?`
|
|
193
|
+
|
|
194
|
+
A truthy `respond_to?(:name)` with a literal symbol removes `nil`
|
|
195
|
+
from the receiver (unless `nil` itself responds to `name`) and the
|
|
196
|
+
members whose class Rigor knows lacks `name`. When no member could
|
|
197
|
+
respond, the receiver reads `Dynamic[top]` if its type is one
|
|
198
|
+
Rigor inferred or read from a signature, so the guarded call is
|
|
199
|
+
not an error. It reads `bot` if it is a literal, an array or hash
|
|
200
|
+
literal, a class object, or `nil` / `true` / `false`, so the
|
|
201
|
+
branch goes unchecked. For a literal value that is exact: it
|
|
202
|
+
never gains the method. A class object can gain one from a gem
|
|
203
|
+
Rigor has no signature for (`Time.respond_to?(:zone)` under
|
|
204
|
+
ActiveSupport), and its branch is then not checked either:
|
|
205
|
+
|
|
206
|
+
```ruby
|
|
207
|
+
require "stringio"
|
|
208
|
+
|
|
209
|
+
value = [1, "one"].sample
|
|
210
|
+
assert_type('"one"', value) if value.respond_to?(:upcase)
|
|
211
|
+
|
|
212
|
+
io = STDOUT
|
|
213
|
+
assert_type("Dynamic[top]", io) if io.respond_to?(:string)
|
|
214
|
+
|
|
215
|
+
count = 3
|
|
216
|
+
assert_type("bot", count) if count.respond_to?(:upcase)
|
|
217
|
+
```
|
|
131
218
|
|
|
132
219
|
## Boolean composition
|
|
133
220
|
|
|
@@ -153,7 +240,7 @@ end
|
|
|
153
240
|
```
|
|
154
241
|
|
|
155
242
|
The `is_a?` narrowed `x` to `Integer`, then the integer
|
|
156
|
-
comparison narrowed it further to `
|
|
243
|
+
comparison narrowed it further to `Integer[1..]`.
|
|
157
244
|
|
|
158
245
|
## Integer comparisons
|
|
159
246
|
|
|
@@ -165,7 +252,7 @@ integer ranges:
|
|
|
165
252
|
def safe_index(arr, n)
|
|
166
253
|
return :empty if arr.empty?
|
|
167
254
|
return :out_of_range if n < 0 || n >= arr.size
|
|
168
|
-
# n:
|
|
255
|
+
# n: Integer[0..arr.size - 1] (in practice: Integer[0..]
|
|
169
256
|
# tightened against `n >= arr.size`)
|
|
170
257
|
arr.fetch(n)
|
|
171
258
|
end
|
|
@@ -176,10 +263,43 @@ Range comparisons compose with literals:
|
|
|
176
263
|
```ruby
|
|
177
264
|
n = some_input
|
|
178
265
|
if n.between?(1, 9)
|
|
179
|
-
# n:
|
|
266
|
+
# n: Integer[1..9]
|
|
180
267
|
end
|
|
181
268
|
```
|
|
182
269
|
|
|
270
|
+
## Float comparisons
|
|
271
|
+
|
|
272
|
+
A `Float` narrows on the *true* edge only. `x > 0.0` is false for
|
|
273
|
+
`NaN`, so the values that pass are a range, `Float[0.0..]`, but the
|
|
274
|
+
values that fail are everything else *plus* `NaN`, which no range
|
|
275
|
+
spells, so the else branch keeps `Float`:
|
|
276
|
+
|
|
277
|
+
```ruby
|
|
278
|
+
x = Float(input)
|
|
279
|
+
if x > 0.0
|
|
280
|
+
# x: Float[0.0..]
|
|
281
|
+
else
|
|
282
|
+
# x: Float
|
|
283
|
+
end
|
|
284
|
+
if x < 1.0
|
|
285
|
+
# x: Float[...1.0] (Ruby's exclusive end)
|
|
286
|
+
end
|
|
287
|
+
if x.between?(0.0, 1.0)
|
|
288
|
+
# x: Float[0.0..1.0]
|
|
289
|
+
end
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
`x.nan?` narrows its *false* edge to `non-nan-float`, and
|
|
293
|
+
`x.finite?` its *true* edge to `finite-float`. The range is the
|
|
294
|
+
one Ruby's `Range#cover?` would accept, so `Float[0.0..]` contains
|
|
295
|
+
`Float::INFINITY` and never `Float::NAN`.
|
|
296
|
+
|
|
297
|
+
Some calls produce a bounded Float on their own: `rand(0.0...1.0)`
|
|
298
|
+
and `Random.rand(1.0..2.0)` are the range they name, `Math.sqrt(n)` of a `non-negative-int` is
|
|
299
|
+
`Float[0.0..]`, and `x.clamp(0.0, 1.0)` or `x.clamp(0.0..1.0)` on a
|
|
300
|
+
bounded `x` is the bracket. A bounded Float knows it is not `NaN`,
|
|
301
|
+
so `u.nan?` folds to `false` and `u.round` to an integer range.
|
|
302
|
+
|
|
183
303
|
## Predicate methods on refinements
|
|
184
304
|
|
|
185
305
|
Rigor recognises a small set of "type-carrier predicate
|
|
@@ -310,12 +430,10 @@ not chase mutation).
|
|
|
310
430
|
A few forms you might expect that Rigor does **not** narrow
|
|
311
431
|
today:
|
|
312
432
|
|
|
313
|
-
- `respond_to?(:method_name)`
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
structural "this object responds to that method" capability
|
|
318
|
-
fact you could dispatch against.
|
|
433
|
+
- `respond_to?(:method_name)` narrows by removing members (see
|
|
434
|
+
[`respond_to?`](#respond_to) below), but it does **not** yet
|
|
435
|
+
expose a structural "this object responds to that method"
|
|
436
|
+
capability fact you could dispatch against.
|
|
319
437
|
- `frozen?` and other mutation guards — Rigor does not track
|
|
320
438
|
mutability as a narrowing fact yet.
|
|
321
439
|
- Open-ended class-comparison via `===` against arbitrary
|