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
|
@@ -7,6 +7,7 @@ require_relative "nominal"
|
|
|
7
7
|
require_relative "singleton"
|
|
8
8
|
require_relative "constant"
|
|
9
9
|
require_relative "integer_range"
|
|
10
|
+
require_relative "float_range"
|
|
10
11
|
require_relative "tuple"
|
|
11
12
|
require_relative "hash_shape"
|
|
12
13
|
require_relative "data_class"
|
|
@@ -60,7 +61,7 @@ module Rigor
|
|
|
60
61
|
# list of Rigor::Type values that carry the receiver's generic instantiation (`Array[Integer]` is
|
|
61
62
|
# `Nominal["Array", [Nominal["Integer"]]]`). Omitting the keyword produces the raw form
|
|
62
63
|
# `Nominal["Array"]`, which is structurally distinct from any applied form.
|
|
63
|
-
def nominal_of(class_name_or_object, type_args:
|
|
64
|
+
def nominal_of(class_name_or_object, type_args: Nominal::EMPTY_TYPE_ARGS)
|
|
64
65
|
Nominal.new(resolve_class_name(class_name_or_object), type_args)
|
|
65
66
|
end
|
|
66
67
|
|
|
@@ -68,8 +69,16 @@ module Rigor
|
|
|
68
69
|
Singleton.new(resolve_class_name(class_name_or_object))
|
|
69
70
|
end
|
|
70
71
|
|
|
72
|
+
# #775 — `nil`, `true` and `false` are interned: a Constant is an immutable value, and these three
|
|
73
|
+
# are built on every optional translation, nil check and predicate fold (~200k of the ~210k Constant
|
|
74
|
+
# constructions on the lib self-check), so one shared instance each is unobservable and free.
|
|
71
75
|
def constant_of(value)
|
|
72
|
-
|
|
76
|
+
case value
|
|
77
|
+
when nil then NIL_CONSTANT
|
|
78
|
+
when true then TRUE_CONSTANT
|
|
79
|
+
when false then FALSE_CONSTANT
|
|
80
|
+
else Constant.new(value)
|
|
81
|
+
end
|
|
73
82
|
end
|
|
74
83
|
|
|
75
84
|
# Widens every value-pinned (`Constant`) constituent of `type` to its nominal base (`Constant[1]` ->
|
|
@@ -87,9 +96,11 @@ module Rigor
|
|
|
87
96
|
# rather than flooring to `Dynamic[top]` (ADR-56).
|
|
88
97
|
widen_value_pinned(type.base)
|
|
89
98
|
when IntegerRange
|
|
90
|
-
# `
|
|
99
|
+
# `Integer[1..6]` is likewise a value-narrowed `Integer` (it erases to `Integer` in RBS); widen it
|
|
91
100
|
# so a bounded-int accumulator converges (ADR-56).
|
|
92
101
|
nominal_of("Integer")
|
|
102
|
+
when FloatRange
|
|
103
|
+
nominal_of("Float")
|
|
93
104
|
when Union
|
|
94
105
|
union(*type.members.map { |member| widen_value_pinned(member) })
|
|
95
106
|
else
|
|
@@ -131,6 +142,23 @@ module Rigor
|
|
|
131
142
|
IntegerRange.new(IntegerRange::NEG_INFINITY, IntegerRange::POS_INFINITY)
|
|
132
143
|
end
|
|
133
144
|
|
|
145
|
+
# ADR-109 WD4 — `Float[min..max]` / `Float[min...max]`. Bounds are non-NaN Floats; the infinities
|
|
146
|
+
# are ordinary bounds. Raises on an empty range (the payload builder declines before reaching
|
|
147
|
+
# here).
|
|
148
|
+
def float_range(min, max, exclude_end: false)
|
|
149
|
+
FloatRange.new(min, max, exclude_end: exclude_end)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Every Float except NaN: `Float[-Float::INFINITY..]`.
|
|
153
|
+
def non_nan_float
|
|
154
|
+
FloatRange.new(-Float::INFINITY, Float::INFINITY)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Every Float except NaN and the infinities: `Float[-Float::MAX..Float::MAX]`.
|
|
158
|
+
def finite_float
|
|
159
|
+
FloatRange.new(-Float::MAX, Float::MAX)
|
|
160
|
+
end
|
|
161
|
+
|
|
134
162
|
# Point-removal refinement carrier (ADR-3 OQ3 Option C). Use `non_empty_string` / `non_zero_int` /
|
|
135
163
|
# `non_empty_array` / `non_empty_hash` for the imported built-in shapes; raw `difference(base,
|
|
136
164
|
# removed)` for ad-hoc refinements an `RBS::Extended` annotation introduces.
|
|
@@ -382,6 +410,13 @@ module Rigor
|
|
|
382
410
|
# Normalized union. Flattens nested Unions, deduplicates structurally equal members, drops Bot, and
|
|
383
411
|
# collapses 0/1-member results.
|
|
384
412
|
def union(*types)
|
|
413
|
+
# #775 — the same carrier on both sides of a join is already its own union. With the closed-alias
|
|
414
|
+
# translation memo every `Rigor::Type::t` reader shares one 21-member Union, so a control-flow join of
|
|
415
|
+
# an untouched binding would otherwise re-flatten and re-unique 42 members to rebuild an equal object.
|
|
416
|
+
# `rigor trace` still sees the merge (the tracer records degenerate merges).
|
|
417
|
+
first = types.first
|
|
418
|
+
return first if types.size == 2 && first.equal?(types[1]) && !Inference::FlowTracer.active?
|
|
419
|
+
|
|
385
420
|
result = collapse_union(normalized_union_members(types))
|
|
386
421
|
if Inference::BudgetTrace.enabled? && result.is_a?(Union)
|
|
387
422
|
Inference::BudgetTrace.observe(Inference::BudgetTrace::UNION_ARITY, result.members.size)
|
|
@@ -790,12 +825,111 @@ module Rigor
|
|
|
790
825
|
|
|
791
826
|
return [top] if flattened.any?(Top)
|
|
792
827
|
|
|
793
|
-
unique_members(flattened)
|
|
828
|
+
absorb_contained_members(unique_members(flattened))
|
|
829
|
+
end
|
|
830
|
+
|
|
831
|
+
# Drops every member another member already contains, so the join after a guard names one set
|
|
832
|
+
# instead of several readings of it. The normative relation is
|
|
833
|
+
# docs/type-specification/normalization.md § "Member absorption"; {absorbed_by?} is that list.
|
|
834
|
+
#
|
|
835
|
+
# Only a `FloatRange`, `Tuple` or `HashShape` member can be dropped, so the O(n²) scan is
|
|
836
|
+
# skipped for every union that carries none of them — this runs on the hot path of every join.
|
|
837
|
+
#
|
|
838
|
+
# The `!absorbed_by?(other, member)` re-check costs one predicate call per pair that absorbed
|
|
839
|
+
# at all, and it is what makes "both arms dropped" unrepresentable should a future clause make
|
|
840
|
+
# the relation symmetric on a pair of distinct members.
|
|
841
|
+
def absorb_contained_members(members)
|
|
842
|
+
return members unless members.any? { |m| absorbable_member?(m) }
|
|
843
|
+
|
|
844
|
+
members.reject do |member|
|
|
845
|
+
absorbable_member?(member) &&
|
|
846
|
+
members.any? do |other|
|
|
847
|
+
!other.equal?(member) && absorbed_by?(member, other) && !absorbed_by?(other, member)
|
|
848
|
+
end
|
|
849
|
+
end
|
|
850
|
+
end
|
|
851
|
+
|
|
852
|
+
def absorbable_member?(type)
|
|
853
|
+
type.is_a?(FloatRange) || type.is_a?(Tuple) || type.is_a?(HashShape)
|
|
854
|
+
end
|
|
855
|
+
|
|
856
|
+
# `narrower`'s inhabitants are a subset of `wider`'s under a rule the union already applies to
|
|
857
|
+
# a direct member. The structural clauses only lift that same relation element-wise over a
|
|
858
|
+
# fixed spine; none of them introduces an absorption the flat union does not already perform,
|
|
859
|
+
# which is why a value-pinned element never collapses (normalization.md keeps `1 | Integer`,
|
|
860
|
+
# so `[1, String] | [Integer, String]` keeps both arms) and an `IntegerRange` or `Refined`
|
|
861
|
+
# element never does either.
|
|
862
|
+
def absorbed_by?(narrower, wider)
|
|
863
|
+
return true if wider.is_a?(Top) || narrower.is_a?(Bot)
|
|
864
|
+
return true if listed_in_union?(narrower, wider)
|
|
865
|
+
|
|
866
|
+
case narrower
|
|
867
|
+
when FloatRange then float_range_absorbed_by?(narrower, wider)
|
|
868
|
+
when Tuple then wider.is_a?(Tuple) && tuple_absorbed_by?(narrower, wider)
|
|
869
|
+
when HashShape then wider.is_a?(HashShape) && hash_shape_absorbed_by?(narrower, wider)
|
|
870
|
+
when Union then union_absorbed_by?(narrower, wider)
|
|
871
|
+
else false
|
|
872
|
+
end
|
|
873
|
+
end
|
|
874
|
+
|
|
875
|
+
# Flatten-and-dedupe read one level down: the member is already one of the arms `wider` lists.
|
|
876
|
+
def listed_in_union?(narrower, wider)
|
|
877
|
+
wider.is_a?(Union) && wider.members.any? { |member| element_absorbed_or_equal?(narrower, member) }
|
|
878
|
+
end
|
|
879
|
+
|
|
880
|
+
def union_absorbed_by?(narrower, wider)
|
|
881
|
+
narrower.members.all? { |member| element_absorbed_or_equal?(member, wider) }
|
|
882
|
+
end
|
|
883
|
+
|
|
884
|
+
def element_absorbed_or_equal?(narrower, wider)
|
|
885
|
+
narrower.equal?(wider) || narrower == wider || absorbed_by?(narrower, wider)
|
|
886
|
+
end
|
|
887
|
+
|
|
888
|
+
# ADR-109 WD5 — a `FloatRange` is absorbed by a bare `Nominal[Float]` or by a `FloatRange` that
|
|
889
|
+
# contains it. The truthy edge of `x > c` is a range and the falsy edge keeps `Float`, so the
|
|
890
|
+
# join after every Float guard would otherwise carry both and every later guard would narrow
|
|
891
|
+
# member by member into a growing union (`Float[...1.0] | Float[0.0...1.0]`) that names one set.
|
|
892
|
+
# `IntegerRange` keeps its pre-ADR-109 behaviour (`Integer | Integer[0..5]` stays as written)
|
|
893
|
+
# because both of its edges narrow.
|
|
894
|
+
def float_range_absorbed_by?(range, other)
|
|
895
|
+
case other
|
|
896
|
+
when Nominal then other.class_name == "Float" && other.type_args.empty?
|
|
897
|
+
when FloatRange then other != range && other.accepts(range).yes?
|
|
898
|
+
else false
|
|
899
|
+
end
|
|
900
|
+
end
|
|
901
|
+
|
|
902
|
+
# Differing arity is never absorbed: `[A]` and `[A, B]` have disjoint inhabitants, so neither
|
|
903
|
+
# arm is a reading of the other.
|
|
904
|
+
def tuple_absorbed_by?(narrower, wider)
|
|
905
|
+
return false unless narrower.elements.size == wider.elements.size
|
|
906
|
+
|
|
907
|
+
narrower.elements.each_with_index.all? do |element, index|
|
|
908
|
+
element_absorbed_or_equal?(element, wider.elements[index])
|
|
909
|
+
end
|
|
910
|
+
end
|
|
911
|
+
|
|
912
|
+
def hash_shape_absorbed_by?(narrower, wider)
|
|
913
|
+
return false unless hash_shape_spine_equal?(narrower, wider)
|
|
914
|
+
|
|
915
|
+
narrower.pairs.all? { |key, value| element_absorbed_or_equal?(value, wider.pairs[key]) }
|
|
916
|
+
end
|
|
917
|
+
|
|
918
|
+
# The spine is everything but the value types: the key set and the openness / optionality /
|
|
919
|
+
# read-only policy. Two shapes that disagree on any of it describe differently-shaped hashes,
|
|
920
|
+
# and an element-wise reading of their values would not be a containment.
|
|
921
|
+
def hash_shape_spine_equal?(narrower, wider)
|
|
922
|
+
narrower.pairs.size == wider.pairs.size &&
|
|
923
|
+
narrower.extra_keys == wider.extra_keys &&
|
|
924
|
+
narrower.required_keys == wider.required_keys &&
|
|
925
|
+
narrower.optional_keys == wider.optional_keys &&
|
|
926
|
+
narrower.read_only_keys == wider.read_only_keys &&
|
|
927
|
+
narrower.pairs.each_key.all? { |key| wider.pairs.key?(key) }
|
|
794
928
|
end
|
|
795
929
|
|
|
796
930
|
def unique_members(types)
|
|
797
931
|
types.each_with_object([]) do |type, unique|
|
|
798
|
-
unique << type unless unique.any? { |member| member == type }
|
|
932
|
+
unique << type unless unique.any? { |member| member.equal?(type) || member == type }
|
|
799
933
|
end
|
|
800
934
|
end
|
|
801
935
|
|
|
@@ -864,6 +998,11 @@ module Rigor
|
|
|
864
998
|
|
|
865
999
|
# Eager-allocated at load time; see `untyped` method comment above.
|
|
866
1000
|
@untyped = Dynamic.new(Top.instance)
|
|
1001
|
+
|
|
1002
|
+
NIL_CONSTANT = Constant.new(nil)
|
|
1003
|
+
TRUE_CONSTANT = Constant.new(true)
|
|
1004
|
+
FALSE_CONSTANT = Constant.new(false)
|
|
1005
|
+
private_constant :NIL_CONSTANT, :TRUE_CONSTANT, :FALSE_CONSTANT
|
|
867
1006
|
end
|
|
868
1007
|
end
|
|
869
1008
|
end
|
|
@@ -24,8 +24,8 @@ module Rigor
|
|
|
24
24
|
class DataClass
|
|
25
25
|
attr_reader :members, :class_name
|
|
26
26
|
|
|
27
|
-
# @param members
|
|
28
|
-
# @param class_name
|
|
27
|
+
# @param members — ordered member names.
|
|
28
|
+
# @param class_name — the bound class name, or nil for
|
|
29
29
|
# the anonymous `Data.define(...)` result.
|
|
30
30
|
def initialize(members, class_name = nil)
|
|
31
31
|
unless members.is_a?(Array) && members.all?(Symbol)
|
|
@@ -27,9 +27,9 @@ module Rigor
|
|
|
27
27
|
class DataInstance
|
|
28
28
|
attr_reader :members, :class_name
|
|
29
29
|
|
|
30
|
-
# @param members
|
|
30
|
+
# @param members — ordered member -> type
|
|
31
31
|
# map. Every declared member is present (Data instances are total).
|
|
32
|
-
# @param class_name
|
|
32
|
+
# @param class_name — the tagging class name, or nil for
|
|
33
33
|
# an instance of an anonymous `Data.define(...)` class.
|
|
34
34
|
def initialize(members, class_name = nil)
|
|
35
35
|
unless members.is_a?(Hash) && members.each_key.all?(Symbol)
|
|
@@ -44,12 +44,12 @@ module Rigor
|
|
|
44
44
|
freeze
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
# @return
|
|
47
|
+
# @return ordered member names.
|
|
48
48
|
def member_names
|
|
49
49
|
members.keys
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
-
# @return
|
|
52
|
+
# @return the member's value type, or nil when the
|
|
53
53
|
# name is not a declared member.
|
|
54
54
|
def member_type(name)
|
|
55
55
|
members[name]
|
|
@@ -70,6 +70,7 @@ module Rigor
|
|
|
70
70
|
"Array" => ->(removed) { removed.is_a?(Tuple) && removed.elements.empty? },
|
|
71
71
|
"Hash" => ->(removed) { removed.is_a?(HashShape) && removed.pairs.empty? }
|
|
72
72
|
}.freeze
|
|
73
|
+
Ractor.make_shareable(EMPTY_WITNESS_PREDICATES)
|
|
73
74
|
private_constant :EMPTY_WITNESS_PREDICATES
|
|
74
75
|
|
|
75
76
|
def top
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../trinary"
|
|
4
|
+
require_relative "acceptance_router"
|
|
5
|
+
require_relative "plain_lattice"
|
|
6
|
+
|
|
7
|
+
module Rigor
|
|
8
|
+
module Type
|
|
9
|
+
# A bounded float range carrier: every `Float` that the Ruby range literal it displays as would
|
|
10
|
+
# `cover?` (ADR-109 WD4). Bounds are doubles; `-Float::INFINITY` and `Float::INFINITY` are ordinary
|
|
11
|
+
# bounds, never sentinels, because Ruby orders them. The range may exclude its end (`0.0...1.0`)
|
|
12
|
+
# and never its beginning, because Ruby's literal has no exclusive begin.
|
|
13
|
+
#
|
|
14
|
+
# No bounded range contains NaN: `(a..b).cover?(Float::NAN)` is false for every `a` and `b`, so
|
|
15
|
+
# the range from `-Float::INFINITY` to `Float::INFINITY` is "every Float except NaN"
|
|
16
|
+
# (`non-nan-float`), not `Float`. The whole of `Float` (`nil..nil` in Ruby, which does cover NaN)
|
|
17
|
+
# is never a carrier; the payload builder normalises it to `Nominal[Float]`.
|
|
18
|
+
#
|
|
19
|
+
# Two spellings bound the same set when their ends are neighbouring doubles: `0.0...1.0` and
|
|
20
|
+
# `0.0..1.0.prev_float` cover the same floats. Equality, hashing and containment run on the
|
|
21
|
+
# canonical closed form (`canonical_max`); `describe` keeps the written form.
|
|
22
|
+
#
|
|
23
|
+
# Erasure to RBS is always "Float".
|
|
24
|
+
class FloatRange
|
|
25
|
+
attr_reader :min, :max
|
|
26
|
+
|
|
27
|
+
def initialize(min, max, exclude_end: false)
|
|
28
|
+
validate_bound!(min, "min")
|
|
29
|
+
validate_bound!(max, "max")
|
|
30
|
+
# `-0.0` and `0.0` are one point in the order (`-0.0 == 0.0`, `(-0.0..0.0).cover?(0.0)`); keep
|
|
31
|
+
# the one spelling so the display cannot suggest two ranges.
|
|
32
|
+
@min = min.zero? ? 0.0 : min
|
|
33
|
+
@max = max.zero? ? 0.0 : max
|
|
34
|
+
@exclude_end = exclude_end == true
|
|
35
|
+
if @min > canonical_max
|
|
36
|
+
raise ArgumentError, "FloatRange #{Range.new(@min, @max, @exclude_end).inspect} is empty"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
freeze
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def exclude_end?
|
|
43
|
+
@exclude_end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# The greatest double the range contains. `Float::INFINITY.prev_float` is `Float::MAX`, so an
|
|
47
|
+
# exclusive infinite end reads as "finite above".
|
|
48
|
+
def canonical_max
|
|
49
|
+
@exclude_end ? max.prev_float : max
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Every Float except NaN.
|
|
53
|
+
def universal?
|
|
54
|
+
min == -Float::INFINITY && canonical_max == Float::INFINITY
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Ruby's own predicate is the definition: the carrier covers `value` exactly when the range it
|
|
58
|
+
# displays as does.
|
|
59
|
+
def covers?(value)
|
|
60
|
+
return false unless value.is_a?(Float)
|
|
61
|
+
|
|
62
|
+
Range.new(min, max, @exclude_end).cover?(value)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Keyed by the canonical closed bounds so a written `-Float::MAX...Float::INFINITY` reads as the
|
|
66
|
+
# set it is.
|
|
67
|
+
ALIAS_NAMES = Ractor.make_shareable({
|
|
68
|
+
[-Float::INFINITY, Float::INFINITY] => "non-nan-float",
|
|
69
|
+
[-Float::MAX, Float::MAX] => "finite-float"
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
def describe(_verbosity = :short)
|
|
73
|
+
ALIAS_NAMES[[min, canonical_max]] || generic_description
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# The written form: an infinite bound is left out where Ruby's literal can (beginless, endless),
|
|
77
|
+
# spelled `Float::INFINITY` where it cannot (`...Float::INFINITY` is "finite above"), and the two
|
|
78
|
+
# extreme finite doubles read as the constants a Rubyist would write.
|
|
79
|
+
def generic_description
|
|
80
|
+
op = @exclude_end ? "..." : ".."
|
|
81
|
+
lo = min == -Float::INFINITY ? "" : float_literal(min)
|
|
82
|
+
hi = max == Float::INFINITY && !@exclude_end ? "" : float_literal(max)
|
|
83
|
+
"Float[#{lo}#{op}#{hi}]"
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def erase_to_rbs
|
|
87
|
+
"Float"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
include Rigor::Type::PlainLattice
|
|
91
|
+
|
|
92
|
+
include Rigor::Type::AcceptanceRouter
|
|
93
|
+
|
|
94
|
+
# Hand-written rather than `value_fields`: two carriers are the same type when they cover the
|
|
95
|
+
# same doubles, whatever end they were written with.
|
|
96
|
+
def ==(other)
|
|
97
|
+
other.is_a?(FloatRange) && min == other.min && canonical_max == other.canonical_max
|
|
98
|
+
end
|
|
99
|
+
alias eql? ==
|
|
100
|
+
|
|
101
|
+
def hash
|
|
102
|
+
[self.class, min, canonical_max].hash
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def inspect
|
|
106
|
+
"#<Rigor::Type::FloatRange #{describe(:short)}>"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
private
|
|
110
|
+
|
|
111
|
+
def float_literal(value)
|
|
112
|
+
case value
|
|
113
|
+
when Float::INFINITY then "Float::INFINITY"
|
|
114
|
+
when -Float::INFINITY then "-Float::INFINITY"
|
|
115
|
+
when Float::MAX then "Float::MAX"
|
|
116
|
+
when -Float::MAX then "-Float::MAX"
|
|
117
|
+
else value.inspect
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def validate_bound!(bound, label)
|
|
122
|
+
return if bound.is_a?(Float) && !bound.nan?
|
|
123
|
+
|
|
124
|
+
raise ArgumentError, "FloatRange #{label} must be a non-NaN Float, got #{bound.inspect}"
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
@@ -34,21 +34,21 @@ module Rigor
|
|
|
34
34
|
|
|
35
35
|
attr_reader :pairs, :required_keys, :optional_keys, :read_only_keys, :extra_keys
|
|
36
36
|
|
|
37
|
-
# @param pairs
|
|
37
|
+
# @param pairs — ordered map of
|
|
38
38
|
# keys to declared types. Keys MUST be Symbol or String;
|
|
39
39
|
# values MUST be Rigor::Type instances. The hash is duped and
|
|
40
40
|
# frozen at construction; callers MUST NOT mutate the input
|
|
41
41
|
# afterwards (mutation does not affect the carrier, but the
|
|
42
42
|
# carrier is a value object).
|
|
43
|
-
# @param required_keys
|
|
43
|
+
# @param required_keys — keys that MUST
|
|
44
44
|
# be present. When omitted, every non-optional key is required.
|
|
45
45
|
# When supplied without optional_keys, every remaining known key
|
|
46
46
|
# is treated as optional.
|
|
47
|
-
# @param optional_keys
|
|
47
|
+
# @param optional_keys — keys that MAY
|
|
48
48
|
# be absent. Optional absence is not a stored nil.
|
|
49
|
-
# @param read_only_keys
|
|
49
|
+
# @param read_only_keys — entries that cannot
|
|
50
50
|
# be written through this shape view.
|
|
51
|
-
# @param extra_keys
|
|
51
|
+
# @param extra_keys — :closed rejects keys outside pairs;
|
|
52
52
|
# :open permits them.
|
|
53
53
|
def initialize(pairs = nil, **keywords)
|
|
54
54
|
pairs, policy = split_constructor_args(pairs, keywords)
|
|
@@ -60,7 +60,7 @@ module Rigor
|
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
def describe(verbosity = :short)
|
|
63
|
-
return "{}" if pairs.empty?
|
|
63
|
+
return "{}" if pairs.empty? && closed?
|
|
64
64
|
|
|
65
65
|
rendered = pairs.map { |k, v| render_entry(k, v, verbosity) }
|
|
66
66
|
rendered << "..." if open?
|
|
@@ -8,10 +8,11 @@ require_relative "plain_lattice"
|
|
|
8
8
|
module Rigor
|
|
9
9
|
module Type
|
|
10
10
|
# A bounded integer range carrier. Each bound is either an `Integer` or one of the symbolic
|
|
11
|
-
# infinities `:neg_infinity` / `:pos_infinity`.
|
|
12
|
-
#
|
|
13
|
-
# `
|
|
14
|
-
#
|
|
11
|
+
# infinities `:neg_infinity` / `:pos_infinity`. Displayed with the Ruby range literal that
|
|
12
|
+
# `Range#cover?` would accept the same integers for (`Integer[1..10]`, `Integer[0..]`,
|
|
13
|
+
# `Integer[..-1]`; ADR-109). The named aliases `positive-int` (1..), `non-negative-int` (0..),
|
|
14
|
+
# `negative-int` (..-1), `non-positive-int` (..0) all surface through this single carrier and are
|
|
15
|
+
# recovered in `describe` for human-friendly output.
|
|
15
16
|
#
|
|
16
17
|
# Constraints on construction:
|
|
17
18
|
# - both bounds must be either `Integer` or one of the two infinity sentinels;
|
|
@@ -76,8 +77,10 @@ module Rigor
|
|
|
76
77
|
Float::INFINITY
|
|
77
78
|
end
|
|
78
79
|
|
|
80
|
+
# The universal range reads as the class it erases to: a range with no bound carries no fact
|
|
81
|
+
# a Rubyist would spell.
|
|
79
82
|
ALIAS_NAMES = Ractor.make_shareable({
|
|
80
|
-
[NEG_INFINITY, POS_INFINITY] => "
|
|
83
|
+
[NEG_INFINITY, POS_INFINITY] => "Integer",
|
|
81
84
|
[1, POS_INFINITY] => "positive-int",
|
|
82
85
|
[0, POS_INFINITY] => "non-negative-int",
|
|
83
86
|
[NEG_INFINITY, -1] => "negative-int",
|
|
@@ -88,11 +91,13 @@ module Rigor
|
|
|
88
91
|
ALIAS_NAMES[[min, max]] || generic_description
|
|
89
92
|
end
|
|
90
93
|
|
|
94
|
+
# Always the closed form: for integers `a...b` and `a..b-1` are the same set, and the closed
|
|
95
|
+
# spelling is the one the grammar reads back without a canonicalisation step.
|
|
91
96
|
def generic_description
|
|
92
|
-
return "
|
|
93
|
-
return "
|
|
97
|
+
return "Integer[#{min}..]" if max == POS_INFINITY
|
|
98
|
+
return "Integer[..#{max}]" if min == NEG_INFINITY
|
|
94
99
|
|
|
95
|
-
"
|
|
100
|
+
"Integer[#{min}..#{max}]"
|
|
96
101
|
end
|
|
97
102
|
|
|
98
103
|
def erase_to_rbs
|
data/lib/rigor/type/nominal.rb
CHANGED
|
@@ -25,13 +25,19 @@ module Rigor
|
|
|
25
25
|
class Nominal
|
|
26
26
|
attr_reader :class_name, :type_args
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
# The shared empty argument list. The raw form `Nominal["Array"]` is by far the most constructed
|
|
29
|
+
# type (~600k on the lib self-check); a fresh `[]` default plus its defensive `dup` cost two
|
|
30
|
+
# allocations per construction for an array nobody can observe.
|
|
31
|
+
EMPTY_TYPE_ARGS = [].freeze
|
|
32
|
+
|
|
33
|
+
def initialize(class_name, type_args = EMPTY_TYPE_ARGS)
|
|
29
34
|
raise ArgumentError, "class_name must be a String, got #{class_name.class}" unless class_name.is_a?(String)
|
|
30
35
|
raise ArgumentError, "class_name must not be empty" if class_name.empty?
|
|
31
36
|
raise ArgumentError, "type_args must be an Array, got #{type_args.class}" unless type_args.is_a?(Array)
|
|
32
37
|
|
|
33
38
|
@class_name = class_name.freeze
|
|
34
|
-
|
|
39
|
+
# A frozen array is already immutable, so sharing it is unobservable; only a mutable one is copied.
|
|
40
|
+
@type_args = type_args.frozen? ? type_args : type_args.dup.freeze
|
|
35
41
|
freeze
|
|
36
42
|
end
|
|
37
43
|
|
data/lib/rigor/type/refined.rb
CHANGED
|
@@ -135,8 +135,8 @@ module Rigor
|
|
|
135
135
|
NUMERIC_LITERAL_PREFIX = /\A[+-]?\d/
|
|
136
136
|
private_constant :NUMERIC_LITERAL_PREFIX
|
|
137
137
|
|
|
138
|
-
# @param value
|
|
139
|
-
# @return
|
|
138
|
+
# @param value — typically a `Constant#value`
|
|
139
|
+
# @return true when `value` is a String that is a
|
|
140
140
|
# single, complete Ruby numeric literal. Total over
|
|
141
141
|
# arbitrary input — never raises (Prism reports malformed
|
|
142
142
|
# input through `errors`, it does not throw).
|
|
@@ -176,6 +176,7 @@ module Rigor
|
|
|
176
176
|
# recovered by inspecting an arbitrary string.
|
|
177
177
|
literal_string: ->(v) { v.is_a?(String) }
|
|
178
178
|
}.freeze
|
|
179
|
+
Ractor.make_shareable(PREDICATES)
|
|
179
180
|
|
|
180
181
|
# Maps `[base_class_name, predicate_id]` pairs to their kebab-case canonical name. Registered
|
|
181
182
|
# shapes print through `describe`; unregistered combinations fall back to the operator form.
|
|
@@ -216,7 +217,7 @@ module Rigor
|
|
|
216
217
|
}.freeze
|
|
217
218
|
private_constant :COMPLEMENT_PAIRS
|
|
218
219
|
|
|
219
|
-
# @return
|
|
220
|
+
# @return the registered complement predicate
|
|
220
221
|
# id, or nil when no pair is registered for this predicate.
|
|
221
222
|
def complement_predicate_id
|
|
222
223
|
COMPLEMENT_PAIRS[predicate_id]
|
|
@@ -26,10 +26,10 @@ module Rigor
|
|
|
26
26
|
class StructClass
|
|
27
27
|
attr_reader :members, :class_name, :keyword_init
|
|
28
28
|
|
|
29
|
-
# @param members
|
|
30
|
-
# @param class_name
|
|
29
|
+
# @param members — ordered member names.
|
|
30
|
+
# @param class_name — the bound class name, or nil for
|
|
31
31
|
# the anonymous `Struct.new(...)` result.
|
|
32
|
-
# @param keyword_init
|
|
32
|
+
# @param keyword_init — the `keyword_init:` flag.
|
|
33
33
|
def initialize(members, class_name = nil, keyword_init: false)
|
|
34
34
|
unless members.is_a?(Array) && members.all?(Symbol)
|
|
35
35
|
raise ArgumentError, "members must be an Array of Symbols, got #{members.inspect}"
|
|
@@ -29,9 +29,9 @@ module Rigor
|
|
|
29
29
|
class StructInstance
|
|
30
30
|
attr_reader :members, :class_name
|
|
31
31
|
|
|
32
|
-
# @param members
|
|
32
|
+
# @param members — ordered member -> type
|
|
33
33
|
# map. Every declared member is present (Struct instances are total).
|
|
34
|
-
# @param class_name
|
|
34
|
+
# @param class_name — the tagging class name, or nil for
|
|
35
35
|
# an instance of an anonymous `Struct.new(...)` class.
|
|
36
36
|
def initialize(members, class_name = nil)
|
|
37
37
|
unless members.is_a?(Hash) && members.each_key.all?(Symbol)
|
|
@@ -46,12 +46,12 @@ module Rigor
|
|
|
46
46
|
freeze
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
# @return
|
|
49
|
+
# @return ordered member names.
|
|
50
50
|
def member_names
|
|
51
51
|
members.keys
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
-
# @return
|
|
54
|
+
# @return the member's value type, or nil when the
|
|
55
55
|
# name is not a declared member.
|
|
56
56
|
def member_type(name)
|
|
57
57
|
members[name]
|
data/lib/rigor/type.rb
CHANGED
|
@@ -17,6 +17,7 @@ require_relative "type/nominal"
|
|
|
17
17
|
require_relative "type/singleton"
|
|
18
18
|
require_relative "type/constant"
|
|
19
19
|
require_relative "type/integer_range"
|
|
20
|
+
require_relative "type/float_range"
|
|
20
21
|
require_relative "type/tuple"
|
|
21
22
|
require_relative "type/hash_shape"
|
|
22
23
|
require_relative "type/data_class"
|
|
@@ -48,7 +48,7 @@ module Rigor
|
|
|
48
48
|
# stays additive — every earlier-shape Generic remains valid.
|
|
49
49
|
def valid_arg?(arg)
|
|
50
50
|
arg.is_a?(Identifier) || arg.is_a?(Generic) || arg.is_a?(IntegerLiteral) ||
|
|
51
|
-
arg.is_a?(SymbolLiteral) || arg.is_a?(StringLiteral) ||
|
|
51
|
+
arg.is_a?(SymbolLiteral) || arg.is_a?(StringLiteral) || arg.is_a?(RangeLiteral) ||
|
|
52
52
|
arg.is_a?(IndexedAccess) || arg.is_a?(Union)
|
|
53
53
|
end
|
|
54
54
|
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rigor
|
|
4
|
+
module TypeNode
|
|
5
|
+
# Range-literal AST node: a Ruby `Range` literal in a type-arg position, spelled as Ruby spells
|
|
6
|
+
# it (`1..10`, `1...10`, `1..`, `..10`, `nil..nil`). ADR-109 makes it the bound of the numeric
|
|
7
|
+
# range refinements, `Integer[1..10]`; under any other head the resolver lifts it to a
|
|
8
|
+
# `Constant<Range>` so a plugin resolver may consume it like the other leaf literals.
|
|
9
|
+
#
|
|
10
|
+
# The value is the `Range` object itself, which already carries `begin`, `end` and
|
|
11
|
+
# `exclude_end?`; there is no second representation to keep in step. A missing endpoint is
|
|
12
|
+
# `nil`, as in Ruby.
|
|
13
|
+
class RangeLiteral < Data.define(:value)
|
|
14
|
+
def initialize(value:)
|
|
15
|
+
unless value.is_a?(Range)
|
|
16
|
+
raise ArgumentError,
|
|
17
|
+
"TypeNode::RangeLiteral value must be a Range, " \
|
|
18
|
+
"got #{value.inspect}"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
super
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
data/lib/rigor/type_node.rb
CHANGED
|
@@ -11,6 +11,7 @@ end
|
|
|
11
11
|
|
|
12
12
|
require_relative "type_node/identifier"
|
|
13
13
|
require_relative "type_node/integer_literal"
|
|
14
|
+
require_relative "type_node/range_literal"
|
|
14
15
|
require_relative "type_node/symbol_literal"
|
|
15
16
|
require_relative "type_node/string_literal"
|
|
16
17
|
require_relative "type_node/generic"
|
data/lib/rigor/version.rb
CHANGED
data/lib/rigor.rb
CHANGED
|
@@ -10,6 +10,7 @@ require_relative "rigor/environment"
|
|
|
10
10
|
require_relative "rigor/rbs_extended"
|
|
11
11
|
require_relative "rigor/testing"
|
|
12
12
|
require_relative "rigor/inference/budget_trace"
|
|
13
|
+
require_relative "rigor/inference/external_ancestor_resolution"
|
|
13
14
|
require_relative "rigor/inference/dynamic_origin"
|
|
14
15
|
require_relative "rigor/inference/fallback"
|
|
15
16
|
require_relative "rigor/inference/fallback_tracer"
|
|
@@ -34,10 +34,6 @@ module Rigor
|
|
|
34
34
|
# The broadcast violations for a single call node, or `[]` when the node is not a
|
|
35
35
|
# `broadcast_to` / `ActionCable.server.broadcast` call this plugin recognises. ADR-37: the
|
|
36
36
|
# engine owns the walk.
|
|
37
|
-
#
|
|
38
|
-
# @param call_node [Prism::Node]
|
|
39
|
-
# @param channel_index [ChannelIndex]
|
|
40
|
-
# @return [Array<Violation>]
|
|
41
37
|
def violations_for(call_node:, channel_index:)
|
|
42
38
|
return [] unless call_node.is_a?(Prism::CallNode)
|
|
43
39
|
|