rigortype 0.3.9 → 0.4.1
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 +5 -4
- 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 +127 -4
- data/docs/handbook/03-narrowing.md +95 -10
- data/docs/handbook/04-tuples-and-shapes.md +8 -6
- data/docs/handbook/07-rbs-and-extended.md +16 -11
- data/docs/handbook/08-understanding-errors.md +3 -2
- data/docs/handbook/10-sorbet.md +9 -10
- data/docs/handbook/11-sig-gen.md +454 -13
- data/docs/install.md +87 -15
- data/docs/manual/02-cli-reference.md +65 -4
- data/docs/manual/03-configuration.md +12 -0
- data/docs/manual/04-diagnostics.md +4 -0
- data/docs/manual/07-plugins.md +1 -1
- data/docs/manual/08-skills.md +4 -3
- data/docs/manual/10-mcp-server.md +3 -2
- data/docs/manual/12-caching.md +43 -4
- data/docs/manual/14-rails-quickstart.md +19 -11
- data/docs/manual/16-rbs-extended-annotations.md +40 -7
- 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 +243 -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 +110 -4
- data/docs/manual/plugins/rigor-activestorage.md +8 -1
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +11 -5
- 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 +212 -25
- 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 +1 -1
- data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +167 -2
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +189 -0
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +5 -3
- data/lib/rigor/analysis/check_rules/rule_ids.rb +20 -5
- data/lib/rigor/analysis/check_rules/rule_walk.rb +2 -1
- data/lib/rigor/analysis/check_rules/source_arity.rb +427 -0
- data/lib/rigor/analysis/check_rules/special_global_setters.rb +146 -0
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +36 -2
- data/lib/rigor/analysis/check_rules.rb +638 -136
- data/lib/rigor/analysis/dependency_recorder.rb +222 -17
- data/lib/rigor/analysis/fact_store.rb +9 -0
- data/lib/rigor/analysis/incremental.rb +26 -0
- data/lib/rigor/analysis/incremental_run_slot/write_guard.rb +266 -0
- data/lib/rigor/analysis/incremental_run_slot.rb +171 -0
- data/lib/rigor/analysis/incremental_session.rb +309 -53
- data/lib/rigor/analysis/plugin_fact_fingerprint.rb +24 -13
- data/lib/rigor/analysis/project_scan.rb +11 -1
- data/lib/rigor/analysis/reachability/plugin_roots.rb +0 -1
- data/lib/rigor/analysis/reachability/scan_cache.rb +3 -1
- data/lib/rigor/analysis/rule_catalog.rb +127 -0
- data/lib/rigor/analysis/run_cache_key.rb +46 -18
- data/lib/rigor/analysis/run_stats.rb +2 -2
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +168 -12
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +9 -4
- data/lib/rigor/analysis/runner/pool_coordinator.rb +109 -17
- data/lib/rigor/analysis/runner/project_pre_passes.rb +44 -17
- data/lib/rigor/analysis/runner.rb +603 -54
- data/lib/rigor/analysis/shadow_harness.rb +27 -0
- data/lib/rigor/analysis/source_rbs_gate.rb +157 -0
- data/lib/rigor/analysis/template_unit_collector.rb +303 -0
- data/lib/rigor/analysis/template_unit_paths.rb +93 -0
- data/lib/rigor/analysis/template_unit_positions.rb +293 -0
- data/lib/rigor/analysis/template_units.rb +409 -0
- data/lib/rigor/analysis/worker_session.rb +57 -13
- data/lib/rigor/bleeding_edge.rb +0 -2
- data/lib/rigor/builtins/hkt_builtins.rb +1 -0
- data/lib/rigor/builtins/imported_refinements.rb +4 -0
- data/lib/rigor/builtins/regex_refinement.rb +17 -9
- data/lib/rigor/builtins/static_return_refinements.rb +2 -0
- data/lib/rigor/cache/descriptor.rb +45 -1
- data/lib/rigor/cache/engine_source.rb +29 -1
- data/lib/rigor/cache/file_digest.rb +28 -0
- data/lib/rigor/cache/incremental_snapshot.rb +102 -8
- data/lib/rigor/cache/rbs_cache_producer.rb +4 -0
- data/lib/rigor/cache/rbs_descriptor.rb +37 -7
- data/lib/rigor/cache/store.rb +63 -4
- data/lib/rigor/cache/value_digest.rb +325 -0
- data/lib/rigor/ci_detector.rb +1 -0
- data/lib/rigor/cli/check_command.rb +83 -13
- data/lib/rigor/cli/doc_links.rb +1 -1
- data/lib/rigor/cli/docs_command.rb +4 -4
- data/lib/rigor/cli/doctor_command.rb +1 -1
- data/lib/rigor/cli/effects_report.rb +2 -2
- data/lib/rigor/cli/plugin_command.rb +3 -3
- data/lib/rigor/cli/prism_colorizer.rb +0 -1
- data/lib/rigor/cli/sig_gen_command.rb +210 -29
- data/lib/rigor/cli/skill_command.rb +1 -1
- data/lib/rigor/cli/skill_describe.rb +0 -1
- data/lib/rigor/cli/type_of_command.rb +19 -5
- 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/unused_command.rb +3 -3
- data/lib/rigor/cli.rb +21 -3
- data/lib/rigor/config_audit.rb +3 -2
- data/lib/rigor/config_path.rb +29 -0
- data/lib/rigor/configuration/severity_profile.rb +24 -3
- data/lib/rigor/configuration.rb +71 -7
- data/lib/rigor/effects/ancestry_recorder.rb +191 -0
- data/lib/rigor/effects/attribution.rb +11 -2
- 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 +9 -2
- data/lib/rigor/effects/definition_context.rb +179 -0
- data/lib/rigor/effects/effect_table.rb +11 -3
- data/lib/rigor/effects/envelope_check.rb +1 -1
- data/lib/rigor/effects/envelope_index.rb +15 -0
- data/lib/rigor/effects/file_collection.rb +59 -5
- data/lib/rigor/effects/framework_units.rb +1 -1
- data/lib/rigor/effects/identity.rb +16 -0
- data/lib/rigor/effects/local_ownership.rb +38 -12
- data/lib/rigor/effects/method_key.rb +21 -0
- data/lib/rigor/effects/mutation_classifier.rb +23 -12
- data/lib/rigor/effects/plugin_facts.rb +49 -37
- data/lib/rigor/effects/propagator.rb +295 -16
- data/lib/rigor/effects/registry.rb +1 -1
- data/lib/rigor/effects/scanner.rb +121 -72
- data/lib/rigor/effects/signature_sources.rb +1 -1
- data/lib/rigor/effects/snapshot.rb +2 -1
- data/lib/rigor/effects/summary.rb +27 -4
- data/lib/rigor/effects/unit_scan.rb +385 -30
- data/lib/rigor/effects/visibility.rb +101 -0
- data/lib/rigor/environment/bundle_sig_discovery.rb +5 -3
- data/lib/rigor/environment/lockfile_resolver.rb +27 -1
- data/lib/rigor/environment/member_consistency/comparator.rb +708 -0
- data/lib/rigor/environment/member_consistency.rb +298 -0
- data/lib/rigor/environment/rbs_collection_discovery.rb +10 -1
- data/lib/rigor/environment/rbs_loader.rb +400 -134
- data/lib/rigor/environment/source_rbs_synthesis.rb +147 -0
- data/lib/rigor/environment.rb +104 -96
- data/lib/rigor/hashing/xxh3.rb +264 -0
- data/lib/rigor/inference/acceptance.rb +139 -9
- 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 +88 -26
- data/lib/rigor/inference/block_repetition.rb +71 -0
- data/lib/rigor/inference/body_fixpoint.rb +2 -1
- data/lib/rigor/inference/budget_trace.rb +2 -1
- 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 +393 -15
- data/lib/rigor/inference/closure_escape_analyzer.rb +157 -13
- data/lib/rigor/inference/content_join.rb +200 -27
- data/lib/rigor/inference/declaration_walk/context.rb +195 -0
- data/lib/rigor/inference/declaration_walk/errors.rb +18 -0
- data/lib/rigor/inference/declaration_walk/shadow.rb +147 -0
- data/lib/rigor/inference/declaration_walk/traversal.rb +441 -0
- data/lib/rigor/inference/declaration_walk.rb +7 -0
- data/lib/rigor/inference/def_node_resolver.rb +3 -2
- 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/definer_resolution.rb +266 -0
- data/lib/rigor/inference/element_read_widening.rb +22 -10
- data/lib/rigor/inference/error_info.rb +196 -0
- data/lib/rigor/inference/expression_typer.rb +1665 -538
- data/lib/rigor/inference/external_ancestor_resolution.rb +264 -0
- 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 +488 -0
- data/lib/rigor/inference/hash_lookup_mutation.rb +88 -0
- data/lib/rigor/inference/index_write_widening.rb +16 -3
- 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 +179 -17
- 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 +85 -24
- data/lib/rigor/inference/method_dispatcher/facet_distribution.rb +147 -0
- data/lib/rigor/inference/method_dispatcher/hash_transform_keys_folding.rb +191 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +4 -0
- data/lib/rigor/inference/method_dispatcher/match_data_folding.rb +159 -0
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +113 -73
- 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/rbs_dispatch.rb +901 -38
- data/lib/rigor/inference/method_dispatcher/self_substitute.rb +142 -0
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +128 -53
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher.rb +214 -13
- data/lib/rigor/inference/method_parameter_binder.rb +8 -3
- data/lib/rigor/inference/module_function_state.rb +213 -0
- data/lib/rigor/inference/multi_target_binder.rb +345 -52
- data/lib/rigor/inference/mutation_rejoin.rb +4 -1
- data/lib/rigor/inference/mutation_widening.rb +70 -48
- data/lib/rigor/inference/narrowing.rb +674 -124
- 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 +152 -9
- data/lib/rigor/inference/parameter_inference_collector.rb +13 -11
- data/lib/rigor/inference/project_method_ownership.rb +136 -0
- data/lib/rigor/inference/project_patched_methods.rb +7 -2
- data/lib/rigor/inference/project_patched_scanner.rb +7 -3
- data/lib/rigor/inference/receiver_alias.rb +90 -1
- data/lib/rigor/inference/receiver_blind_block.rb +219 -0
- data/lib/rigor/inference/refinement_mutation.rb +15 -11
- 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/certainty.rb +176 -0
- data/lib/rigor/inference/scope_indexer/class_cvars_collector.rb +35 -0
- data/lib/rigor/inference/scope_indexer/def_nestings_collector.rb +47 -0
- data/lib/rigor/inference/scope_indexer/layered_def_nestings.rb +36 -0
- data/lib/rigor/inference/scope_indexer/member_layouts_collector.rb +61 -0
- data/lib/rigor/inference/scope_indexer/mixin_accumulator.rb +130 -0
- data/lib/rigor/inference/scope_indexer/superclasses_collector.rb +64 -0
- data/lib/rigor/inference/scope_indexer.rb +5913 -701
- data/lib/rigor/inference/singleton_hook_decline.rb +253 -0
- data/lib/rigor/inference/statement_evaluator.rb +3249 -497
- data/lib/rigor/inference/stored_block_call.rb +54 -0
- data/lib/rigor/inference/string_mutation.rb +44 -7
- data/lib/rigor/inference/unknown_store_widening.rb +200 -0
- data/lib/rigor/inference/unthreaded_rebinds.rb +282 -0
- data/lib/rigor/language_server/debouncer.rb +0 -1
- data/lib/rigor/language_server/diagnostic_publisher.rb +3 -2
- data/lib/rigor/language_server/hover_renderer.rb +3 -3
- data/lib/rigor/language_server/project_context.rb +5 -3
- data/lib/rigor/mcp/server.rb +2 -1
- data/lib/rigor/plugin/base.rb +196 -13
- data/lib/rigor/plugin/box_probe.rb +91 -0
- data/lib/rigor/plugin/bundled_catalog.rb +1 -1
- data/lib/rigor/plugin/effect_attribution.rb +58 -4
- data/lib/rigor/plugin/io_boundary.rb +82 -4
- data/lib/rigor/plugin/isolation.rb +1 -1
- data/lib/rigor/plugin/loader.rb +2 -1
- data/lib/rigor/plugin/macro/block_as_method.rb +45 -6
- data/lib/rigor/plugin/manifest.rb +71 -10
- data/lib/rigor/plugin/registry.rb +35 -1
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +9 -3
- data/lib/rigor/plugin/template_unit.rb +196 -0
- data/lib/rigor/plugin/trust_policy.rb +3 -3
- data/lib/rigor/plugin.rb +1 -0
- data/lib/rigor/protection/discovery_seed.rb +20 -9
- data/lib/rigor/protection/kill_signature.rb +0 -1
- data/lib/rigor/protection/mutation_cache.rb +4 -5
- data/lib/rigor/rbs_extended.rb +27 -0
- data/lib/rigor/reflection/constant_ancestors.rb +146 -0
- data/lib/rigor/reflection/constant_path.rb +41 -13
- data/lib/rigor/reflection.rb +73 -107
- data/lib/rigor/scope/discovery_index.rb +351 -2
- data/lib/rigor/scope/resolution_chain/relevance.rb +165 -0
- data/lib/rigor/scope/resolution_chain.rb +884 -0
- data/lib/rigor/scope.rb +981 -198
- 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 +580 -47
- data/lib/rigor/sig_gen/inline_declarations.rb +184 -0
- data/lib/rigor/sig_gen/method_candidate.rb +47 -3
- data/lib/rigor/sig_gen/observation_collector.rb +1 -1
- data/lib/rigor/sig_gen/renderer.rb +124 -9
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +44 -1
- data/lib/rigor/sig_gen/write_result.rb +19 -3
- data/lib/rigor/sig_gen/writer.rb +166 -35
- data/lib/rigor/sig_gen.rb +3 -0
- data/lib/rigor/signature_path_audit.rb +1 -1
- data/lib/rigor/source/node_walker.rb +0 -3
- data/lib/rigor/source/parameter_envelope.rb +72 -0
- data/lib/rigor/source.rb +1 -0
- data/lib/rigor/type/combinator.rb +112 -12
- data/lib/rigor/type/difference.rb +1 -0
- data/lib/rigor/type/hash_shape.rb +1 -1
- data/lib/rigor/type/refined.rb +1 -0
- data/lib/rigor/version.rb +1 -1
- data/lib/rigor.rb +1 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/effects.rb +1 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +9 -5
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +13 -4
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +0 -1
- 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 +239 -4
- 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/effects.rb +1 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +9 -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 +380 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +14 -6
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +281 -35
- data/plugins/rigor-activerecord/sig/active_record/relation.rbs +206 -31
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +25 -14
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +9 -2
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +171 -5
- data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +2 -0
- data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +1 -0
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/types.rb +1 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +10 -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.rb +72 -2
- data/plugins/rigor-graphql/sig/graphql.rbs +485 -0
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +2 -0
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +11 -7
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +35 -37
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +0 -1
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +2 -0
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +1 -0
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +9 -17
- 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 +217 -36
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/schedule_scan.rb +1 -0
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +9 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +0 -1
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +46 -1
- data/plugins/rigor-sorbet/sig/sorbet.rbs +277 -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/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 +14 -10
- data/sig/rigor/inference/optimistic_origin.rbs +10 -0
- data/sig/rigor/inference.rbs +6 -4
- 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 +2 -1
- data/sig/rigor/plugin/loader.rbs +3 -3
- data/sig/rigor/plugin/manifest.rbs +50 -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 +7 -6
- data/sig/rigor/scope.rbs +177 -20
- data/sig/rigor/sig_gen/skip_reason_catalog.rbs +14 -7
- data/sig/rigor/source.rbs +4 -4
- data/sig/rigor/testing.rbs +10 -4
- data/sig/rigor/type.rbs +6 -0
- data/sig/rigor.rbs +38 -20
- data/skills/rigor-ask/SKILL.md +8 -5
- 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 +12 -25
- 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 +46 -18
- data/skills/rigor-project-init/references/01-detect.md +13 -9
- data/skills/rigor-project-init/references/02-configure.md +40 -10
- 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-protection-uplift/SKILL.md +4 -6
- data/skills/rigor-rbs-setup/SKILL.md +4 -2
- data/skills/rigor-type-oracle/SKILL.md +4 -6
- data/skills/rigor-type-oracle/references/01-oracle-commands.md +12 -8
- data/skills/rigor-type-oracle/references/03-gap-protocol.md +0 -3
- data/skills/rigor-unused-adjudicate/SKILL.md +4 -2
- data/skills/rigor-upgrade/SKILL.md +13 -8
- metadata +132 -1
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "prism"
|
|
4
4
|
|
|
5
5
|
require_relative "../type"
|
|
6
|
+
require_relative "block_auto_splat"
|
|
6
7
|
require_relative "multi_target_binder"
|
|
7
8
|
|
|
8
9
|
module Rigor
|
|
@@ -22,12 +23,23 @@ module Rigor
|
|
|
22
23
|
# MultiTargetNode parameters (`|(a, b), c|`) are bound by delegating each destructuring slot to
|
|
23
24
|
# {Rigor::Inference::MultiTargetBinder}, so a Tuple-shaped expected element type projects element-wise
|
|
24
25
|
# into the inner locals (Slice 6 phase C sub-phase 2). Numbered parameters (`_1`, `_2`, ...) are bound
|
|
25
|
-
# from `Prism::NumberedParametersNode`
|
|
26
|
-
# `
|
|
26
|
+
# from `Prism::NumberedParametersNode` as the explicit list of that many required positionals, the
|
|
27
|
+
# highest `_N` the body references being the arity (CRuby's own reading: `proc { _2 }.parameters` is
|
|
28
|
+
# `[[:opt, :_1], [:opt, :_2]]`, and `lambda { _2 }.arity` is 2). So `h.each { _1; _2 }` auto-splats like
|
|
29
|
+
# `|k, v|`, while a body that uses only `_1` reads as `|a|` and does not (issue #1108).
|
|
27
30
|
#
|
|
28
31
|
# The `it` implicit parameter (Ruby 3.4+) is bound from `Prism::ItParametersNode`. It is the
|
|
29
32
|
# single-argument cousin of `_1`: the binder produces `{ it: expected_param_types[0] }` so the body's
|
|
30
|
-
# `Prism::ItLocalVariableReadNode` lookup sees the same type as the explicit `|x|` form would
|
|
33
|
+
# `Prism::ItLocalVariableReadNode` lookup sees the same type as the explicit `|x|` form would, and it
|
|
34
|
+
# never auto-splats.
|
|
35
|
+
#
|
|
36
|
+
# A block whose parameter list CRuby splats spreads the one yielded value across its positionals;
|
|
37
|
+
# {BlockAutoSplat} owns that rule and its carrier arms, and this binder only applies the table it
|
|
38
|
+
# answers. Every name the spread binds from an `Array[T]` slot — and every name a nested `|(g, h)|`
|
|
39
|
+
# destructure binds from one — is reported as optimistic, and {#bind_onto} records those through
|
|
40
|
+
# `Scope#with_optimistic_local` exactly as the statement-level `a, b = ints` does (issue #1093; the
|
|
41
|
+
# shared rule lives in {MultiTargetBinder}). A nested `|(g, h)|` destructures the one value the
|
|
42
|
+
# signature already placed, so it wraps like the statement form.
|
|
31
43
|
#
|
|
32
44
|
# Block-local declarations after `;` (e.g., `|x; y, z|`) are still skipped — they are explicitly
|
|
33
45
|
# block-local, so the outer scope MUST NOT observe them and the binder leaves them unbound.
|
|
@@ -38,14 +50,31 @@ module Rigor
|
|
|
38
50
|
# the binder cannot fill from this array (because the array is shorter than the parameter list, or
|
|
39
51
|
# because the slot is a kind we do not pull from the array) default to `Dynamic[Top]`.
|
|
40
52
|
def initialize(expected_param_types: [])
|
|
41
|
-
@
|
|
53
|
+
@declared_param_types = expected_param_types
|
|
54
|
+
reset_per_bind_state
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# The names the last {#bind} bound optimistically nil-free (see the class comment). Read-only: it is a
|
|
58
|
+
# shared frozen empty when the bind marked nothing.
|
|
59
|
+
attr_reader :optimistic
|
|
60
|
+
|
|
61
|
+
# Binds the block's parameters into `scope`: {#bind}'s types through `Scope#with_local`, then the
|
|
62
|
+
# optimistic mark for every name in {#optimistic}. It applies them through
|
|
63
|
+
# {MultiTargetBinder.apply_bindings} directly rather than through a `Result`, which every block entry
|
|
64
|
+
# built only to apply at once ([#1504](https://github.com/rigortype/rigor/issues/1504)).
|
|
65
|
+
def bind_onto(block_node, scope)
|
|
66
|
+
MultiTargetBinder.apply_bindings(scope, bind(block_node, scope: scope), @optimistic)
|
|
42
67
|
end
|
|
43
68
|
|
|
44
69
|
# @return ordered map from parameter name to bound type. Anonymous
|
|
45
70
|
# parameters are skipped; MultiTargetNode destructuring slots delegate to {MultiTargetBinder} and
|
|
46
71
|
# contribute every named local in declaration order. Numbered-parameter forms (`_1`, `_2`, ...) bind
|
|
47
72
|
# `:_1`, `:_2`, ... up to the maximum the block body refers to.
|
|
48
|
-
|
|
73
|
+
# @param scope — the scope the block is entered from, which answers a nested destructure's `to_ary`
|
|
74
|
+
# question ({MultiTargetBinder.bind_marked}).
|
|
75
|
+
def bind(block_node, scope: nil)
|
|
76
|
+
reset_per_bind_state
|
|
77
|
+
@scope = scope
|
|
49
78
|
params_root = block_node.parameters
|
|
50
79
|
return {} if params_root.nil?
|
|
51
80
|
|
|
@@ -63,14 +92,40 @@ module Rigor
|
|
|
63
92
|
|
|
64
93
|
private
|
|
65
94
|
|
|
95
|
+
NO_POSITIONS = [].freeze
|
|
96
|
+
NO_NAMES = [].freeze
|
|
97
|
+
private_constant :NO_POSITIONS, :NO_NAMES
|
|
98
|
+
|
|
99
|
+
# {#apply_auto_splat} rewrites the positional table for the block it is binding, so every {#bind} starts
|
|
100
|
+
# from the declared types again; a binder reused across blocks must not see the previous block's splat.
|
|
101
|
+
# The two lists start as shared frozen empties, since most blocks mark nothing ({#mark_optimistic}).
|
|
102
|
+
def reset_per_bind_state
|
|
103
|
+
@expected_param_types = @declared_param_types
|
|
104
|
+
@splat_rest_type = nil
|
|
105
|
+
@optimistic_positions = NO_POSITIONS
|
|
106
|
+
@optimistic = NO_NAMES
|
|
107
|
+
@scope = nil
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Records `name` as bound optimistically, allocating {#optimistic} on the first mark of a {#bind}.
|
|
111
|
+
def mark_optimistic(name)
|
|
112
|
+
@optimistic = [] if @optimistic.equal?(NO_NAMES)
|
|
113
|
+
@optimistic << name
|
|
114
|
+
end
|
|
115
|
+
|
|
66
116
|
# `|_1, _2|` numbered-parameter form. Prism exposes the implicit count through
|
|
67
117
|
# `NumberedParametersNode#maximum` (the highest `_N` referenced in the body); we materialise bindings
|
|
68
|
-
# for `:_1` through `:_maximum
|
|
69
|
-
#
|
|
118
|
+
# for `:_1` through `:_maximum`, auto-splatting exactly as the explicit list of that many required
|
|
119
|
+
# positionals would, so the body's `LocalVariableReadNode` lookups see the same types and marks.
|
|
70
120
|
def bind_numbered_parameters(numbered_node)
|
|
121
|
+
arity = numbered_node.maximum
|
|
122
|
+
apply_auto_splat { BlockAutoSplat::ParameterShape.of_arity(arity) }
|
|
123
|
+
|
|
71
124
|
bindings = {}
|
|
72
|
-
|
|
73
|
-
|
|
125
|
+
arity.times do |i|
|
|
126
|
+
name = :"_#{i + 1}"
|
|
127
|
+
bindings[name] = positional_type_at(i)
|
|
128
|
+
mark_optimistic(name) if @optimistic_positions.include?(i)
|
|
74
129
|
end
|
|
75
130
|
bindings
|
|
76
131
|
end
|
|
@@ -85,7 +140,7 @@ module Rigor
|
|
|
85
140
|
params_node = params_root.parameters
|
|
86
141
|
return {} if params_node.nil?
|
|
87
142
|
|
|
88
|
-
apply_auto_splat(params_node)
|
|
143
|
+
apply_auto_splat { BlockAutoSplat::ParameterShape.of(params_node) }
|
|
89
144
|
|
|
90
145
|
bindings = {}
|
|
91
146
|
bind_positionals(params_node, bindings, 0)
|
|
@@ -96,8 +151,8 @@ module Rigor
|
|
|
96
151
|
bindings
|
|
97
152
|
end
|
|
98
153
|
|
|
99
|
-
# Ruby blocks (NOT lambdas) auto-splat a single yielded
|
|
100
|
-
#
|
|
154
|
+
# Ruby blocks (NOT lambdas) auto-splat a single yielded array-ish value when the parameter list is
|
|
155
|
+
# one CRuby splats:
|
|
101
156
|
#
|
|
102
157
|
# { a: 1 }.each { |k, v| ... }
|
|
103
158
|
#
|
|
@@ -106,21 +161,24 @@ module Rigor
|
|
|
106
161
|
# the binder would assign `k = Tuple[K, V]` and `v = Dynamic[Top]`, and any call on
|
|
107
162
|
# `k.<method-not-on-Tuple>` would false-fire.
|
|
108
163
|
#
|
|
109
|
-
# The rule fires only when
|
|
110
|
-
#
|
|
111
|
-
#
|
|
112
|
-
#
|
|
113
|
-
#
|
|
114
|
-
|
|
164
|
+
# The rule fires only when the receiver yields exactly one value (`expected_param_types.size == 1`)
|
|
165
|
+
# and {BlockAutoSplat} answers a table for that value and `shape`. A multi-arg yield (e.g.
|
|
166
|
+
# `each_with_index`'s `(element, index)` pair) is NOT auto-splatted — matching Ruby semantics where a
|
|
167
|
+
# multi-arg yield to a `|a, b, c|` block fills the extra slot with nil rather than splatting any
|
|
168
|
+
# element. The block answers the parameter list's shape, built only past that test
|
|
169
|
+
# ([#1504](https://github.com/rigortype/rigor/issues/1504)).
|
|
170
|
+
def apply_auto_splat
|
|
115
171
|
return unless @expected_param_types.size == 1
|
|
116
172
|
|
|
117
|
-
|
|
118
|
-
return unless
|
|
173
|
+
shape = yield
|
|
174
|
+
return unless shape.splats?
|
|
119
175
|
|
|
120
|
-
|
|
121
|
-
return
|
|
176
|
+
table = BlockAutoSplat.for(shape, @expected_param_types[0])
|
|
177
|
+
return if table.nil?
|
|
122
178
|
|
|
123
|
-
@expected_param_types =
|
|
179
|
+
@expected_param_types = table.types
|
|
180
|
+
@optimistic_positions = table.optimistic_positions
|
|
181
|
+
@splat_rest_type = table.rest_type
|
|
124
182
|
end
|
|
125
183
|
|
|
126
184
|
def bind_positionals(params_node, bindings, cursor)
|
|
@@ -160,7 +218,8 @@ module Rigor
|
|
|
160
218
|
rest = params_node.rest
|
|
161
219
|
return unless rest.respond_to?(:name) && rest&.name
|
|
162
220
|
|
|
163
|
-
bindings[rest.name] =
|
|
221
|
+
bindings[rest.name] =
|
|
222
|
+
@splat_rest_type || Type::Combinator.nominal_of("Array", type_args: [Type::Combinator.untyped])
|
|
164
223
|
end
|
|
165
224
|
|
|
166
225
|
def bind_keywords(params_node, bindings)
|
|
@@ -199,9 +258,12 @@ module Rigor
|
|
|
199
258
|
case param
|
|
200
259
|
when Prism::RequiredParameterNode
|
|
201
260
|
bindings[param.name] = positional_type_at(cursor)
|
|
261
|
+
mark_optimistic(param.name) if @optimistic_positions.include?(cursor)
|
|
202
262
|
when Prism::MultiTargetNode
|
|
203
|
-
nested = MultiTargetBinder.
|
|
204
|
-
|
|
263
|
+
nested = MultiTargetBinder.bind_marked(param, positional_type_at(cursor),
|
|
264
|
+
optimistic: @optimistic_positions.include?(cursor), scope: @scope)
|
|
265
|
+
bindings.merge!(nested.types)
|
|
266
|
+
nested.optimistic.each { |name| mark_optimistic(name) }
|
|
205
267
|
end
|
|
206
268
|
end
|
|
207
269
|
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../type"
|
|
4
|
+
require_relative "block_call_timing"
|
|
5
|
+
require_relative "closure_escape_analyzer"
|
|
6
|
+
|
|
7
|
+
module Rigor
|
|
8
|
+
module Inference
|
|
9
|
+
# Whether a block-accepting call may run its block more than once, so a later run reads a captured binding an
|
|
10
|
+
# earlier run moved. Two passes ask it and share this one rule: the block-return pass
|
|
11
|
+
# (`ExpressionTyper#block_may_repeat?`), which lays the #587 (b) captured binding under such a block, and the
|
|
12
|
+
# statement pass (`StatementEvaluator#repeating_block_entry`, issue #1412), which lays the ADR-56 WD2.13
|
|
13
|
+
# content-mutation widening on its entry.
|
|
14
|
+
#
|
|
15
|
+
# The core iteration methods {ClosureEscapeAnalyzer} catalogues as non-escaping prove it — for a project class
|
|
16
|
+
# too, through its ancestry (`include Enumerable`); `tap` / `then` / `yield_self` are catalogued there too but
|
|
17
|
+
# run their block exactly once ({BlockCallTiming}).
|
|
18
|
+
#
|
|
19
|
+
# Issue #1234 — a receiver the analyzer cannot classify at all (`Dynamic`, a union, a project class whose
|
|
20
|
+
# ancestry it cannot follow) repeats when the method NAME is a catalogued iterator the project does not define
|
|
21
|
+
# on it ({ClosureEscapeAnalyzer.repeats_by_name?}): `items.all? { seen += 1; seen == 1 }` on an untyped `items`
|
|
22
|
+
# kept the first run's `seen == 1`, the predicate folded to `true`, and the condition on the result was
|
|
23
|
+
# reported as constant. This is a reading of `:unknown` for these two passes alone; escape analysis still
|
|
24
|
+
# treats it as unproven. Any other name, and a receiver classified `:escaping`, answers false, which keeps the
|
|
25
|
+
# entry scope: it is exact for a block run once (`m.synchronize { out = buf; buf = nil; out }` is `buf`'s value,
|
|
26
|
+
# and a cross-iteration binding would add the `nil` a second run never reads).
|
|
27
|
+
#
|
|
28
|
+
# A receiver that provably holds at most one element runs the block at most once however it iterates, so it
|
|
29
|
+
# answers false too: `done = false; [:only].each { break if done; done = true }` is `[:only]`, and the
|
|
30
|
+
# cross-iteration `done` would have typed it `Array[Symbol]?`.
|
|
31
|
+
module BlockRepetition
|
|
32
|
+
module_function
|
|
33
|
+
|
|
34
|
+
# `classification` is the receiver's {ClosureEscapeAnalyzer.classify} answer when the caller already holds it.
|
|
35
|
+
def may_repeat?(method_name:, receiver_type:, scope:, classification: nil)
|
|
36
|
+
return false if BlockCallTiming.candidate_name?(method_name)
|
|
37
|
+
return false if at_most_one_run?(method_name, receiver_type)
|
|
38
|
+
|
|
39
|
+
classification ||= ClosureEscapeAnalyzer.classify(
|
|
40
|
+
receiver_type: receiver_type, method_name: method_name, scope: scope
|
|
41
|
+
)
|
|
42
|
+
case classification
|
|
43
|
+
when :non_escaping then true
|
|
44
|
+
when :unknown
|
|
45
|
+
ClosureEscapeAnalyzer.repeats_by_name?(receiver_type: receiver_type, method_name: method_name, scope: scope)
|
|
46
|
+
else false
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def at_most_one_run?(method_name, receiver_type)
|
|
51
|
+
case receiver_type
|
|
52
|
+
when Type::Tuple then receiver_type.elements.size <= 1
|
|
53
|
+
when Type::HashShape then receiver_type.closed? && receiver_type.pairs.size <= 1
|
|
54
|
+
when Type::Constant then constant_at_most_one_run?(method_name, receiver_type.value)
|
|
55
|
+
else false
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# `1.times` and a one-element integer range iterate once.
|
|
60
|
+
def constant_at_most_one_run?(method_name, value)
|
|
61
|
+
case value
|
|
62
|
+
when Integer then method_name == :times && value <= 1
|
|
63
|
+
when Range
|
|
64
|
+
value.begin.is_a?(Integer) && value.end.is_a?(Integer) &&
|
|
65
|
+
value.end - value.begin + (value.exclude_end? ? 0 : 1) <= 1
|
|
66
|
+
else false
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -19,7 +19,8 @@ module Rigor
|
|
|
19
19
|
# The mechanism is parameterized over an `evaluate_body` callable so slice B can reuse it: given the
|
|
20
20
|
# current per-name bindings it returns the per-name exit bindings produced by one body evaluation from
|
|
21
21
|
# those bindings (names the body leaves unwritten in a given pass simply do not appear in the returned
|
|
22
|
-
# hash).
|
|
22
|
+
# hash). Slice C's content join reuses it too, with each "name" one evidence slot of a collection
|
|
23
|
+
# (`StatementEvaluator#join_content_to_fixpoint`) and a `bot` seed standing for "nothing stored yet".
|
|
23
24
|
module BodyFixpoint
|
|
24
25
|
# One body evaluation per iteration; ADR-55's shape (cap 3).
|
|
25
26
|
CAP = 3
|
|
@@ -49,7 +49,8 @@ module Rigor
|
|
|
49
49
|
RECURSION_FIXPOINT_CAP = :recursion_fixpoint_cap
|
|
50
50
|
# `BodyFixpoint#converge` (ADR-56 slice A — non-escaping block captured-local write-back) ran its
|
|
51
51
|
# 3-evaluation cap without the written local's join converging and collapsed that local to
|
|
52
|
-
# `Dynamic[top]` (the escaping-block floor). Shared by slice B's loop-body fixpoint
|
|
52
|
+
# `Dynamic[top]` (the escaping-block floor). Shared by slice B's loop-body fixpoint and by slice C's
|
|
53
|
+
# content-evidence fixpoint, where the collapsed name is one element / key / value slot of a collection join.
|
|
53
54
|
BLOCK_WRITEBACK_CAP = :block_writeback_cap
|
|
54
55
|
|
|
55
56
|
# ADR-57 return-memo profile counters (not cutoffs — see the module doc). All bumped by
|
|
@@ -20,6 +20,7 @@ module Rigor
|
|
|
20
20
|
class MethodCatalog
|
|
21
21
|
FOLDABLE_PURITIES = Set["leaf", "trivial", "leaf_when_numeric"].freeze
|
|
22
22
|
EMPTY_CATALOG = { "classes" => {} }.freeze
|
|
23
|
+
Ractor.make_shareable(EMPTY_CATALOG)
|
|
23
24
|
|
|
24
25
|
# Selectors that are classified `:leaf` by the C-body analysis (they read no global mutable state
|
|
25
26
|
# in the C sense) but whose result is NOT reproducible across Ruby processes, so they must never
|
|
@@ -37,7 +38,7 @@ module Rigor
|
|
|
37
38
|
|
|
38
39
|
# Shared root for the offline-generated catalogues. Resolving it here keeps the repo-relative
|
|
39
40
|
# `../../../../` hop in one place instead of copying it into every per-topic loader.
|
|
40
|
-
DATA_ROOT = File.expand_path("../../../../data/builtins/ruby_core", __dir__)
|
|
41
|
+
DATA_ROOT = File.expand_path("../../../../data/builtins/ruby_core", __dir__).freeze
|
|
41
42
|
private_constant :DATA_ROOT
|
|
42
43
|
|
|
43
44
|
# Build a catalog for a named topic, resolving its YAML path under {DATA_ROOT}. Equivalent to
|
|
@@ -18,7 +18,7 @@ module Rigor
|
|
|
18
18
|
:replace, :initialize, :initialize_copy, :clear, :<<, :concat, :insert,
|
|
19
19
|
:prepend, :force_encoding, :encode, :scrub, :unicode_normalize, :"[]=",
|
|
20
20
|
:upto, :each_byte, :each_char, :each_codepoint,
|
|
21
|
-
:each_grapheme_cluster, :each_line, :bytesplice,
|
|
21
|
+
:each_grapheme_cluster, :each_line, :bytesplice, :append_as_bytes,
|
|
22
22
|
# `crypt` is not a mutator but is blocked from folding for the same "do not bake a non-pure
|
|
23
23
|
# result into a Constant" reason: `rb_str_crypt` delegates to the platform `crypt(3)`, whose
|
|
24
24
|
# output (algorithm and digest) varies by libc / OS, so `"x".crypt("ab")` is not deterministic
|