rigortype 0.3.7 → 0.3.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/data/capability_roles/capability_roles.rbs +36 -0
- data/data/gem_overlay/activesupport/core_ext.rbs +109 -13
- data/docs/handbook/02-everyday-types.md +17 -14
- data/docs/handbook/03-narrowing.md +37 -4
- data/docs/handbook/05-methods-and-blocks.md +1 -1
- data/docs/handbook/06-classes.md +2 -2
- data/docs/handbook/07-rbs-and-extended.md +14 -1
- data/docs/handbook/11-sig-gen.md +96 -15
- data/docs/handbook/README.md +1 -1
- data/docs/handbook/appendix-elixir.md +2 -2
- data/docs/handbook/appendix-go.md +2 -2
- data/docs/handbook/appendix-java-csharp.md +2 -2
- data/docs/handbook/appendix-mypy.md +2 -2
- data/docs/handbook/appendix-phpstan.md +1 -1
- data/docs/handbook/appendix-rust.md +1 -1
- data/docs/handbook/appendix-type-theory.md +4 -4
- data/docs/handbook/appendix-typescript.md +1 -1
- data/docs/llms.txt +2 -0
- data/docs/manual/02-cli-reference.md +39 -4
- data/docs/manual/03-configuration.md +11 -0
- data/docs/manual/04-diagnostics.md +12 -1
- data/docs/manual/07-plugins.md +15 -5
- data/docs/manual/08-skills.md +23 -2
- data/docs/manual/11-ci.md +9 -0
- data/docs/manual/15-type-protection-coverage.md +8 -0
- data/docs/manual/16-rbs-extended-annotations.md +6 -1
- data/docs/manual/18-removing-dead-code.md +10 -8
- data/docs/manual/plugins/rigor-actionpack.md +18 -0
- data/docs/manual/plugins/rigor-activerecord.md +28 -0
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +32 -2
- data/docs/manual/plugins/rigor-rbs-inline.md +42 -1
- data/lib/rigor/analysis/baseline.rb +2 -2
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/dead_version_guard_arms.rb +1 -5
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +10 -2
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +15 -6
- data/lib/rigor/analysis/check_rules/rule_ids.rb +1 -1
- data/lib/rigor/analysis/check_rules/rule_walk.rb +39 -4
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +1 -1
- data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +0 -1
- data/lib/rigor/analysis/check_rules.rb +200 -32
- data/lib/rigor/analysis/crash_signature.rb +69 -13
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +1 -1
- data/lib/rigor/analysis/dependency_source_inference/builder.rb +0 -2
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +0 -2
- data/lib/rigor/analysis/dependency_source_inference/index.rb +5 -5
- data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +1 -2
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +4 -4
- data/lib/rigor/analysis/effects_cache_probe.rb +3 -4
- data/lib/rigor/analysis/erb_template_detector.rb +1 -2
- data/lib/rigor/analysis/fact_store.rb +6 -1
- data/lib/rigor/analysis/incremental.rb +16 -0
- data/lib/rigor/analysis/incremental_session.rb +100 -29
- data/lib/rigor/analysis/plugin_fact_fingerprint.rb +0 -1
- data/lib/rigor/analysis/reachability/graph.rb +3 -5
- data/lib/rigor/analysis/reachability/plugin_roots.rb +6 -5
- data/lib/rigor/analysis/reachability/project_files.rb +2 -2
- data/lib/rigor/analysis/reachability/scan.rb +5 -5
- data/lib/rigor/analysis/reachability/scan_cache.rb +2 -2
- data/lib/rigor/analysis/reachability/signature_scan.rb +2 -2
- data/lib/rigor/analysis/result.rb +1 -3
- data/lib/rigor/analysis/rule_catalog.rb +4 -1
- data/lib/rigor/analysis/run_cache_key.rb +1 -1
- data/lib/rigor/analysis/run_cache_probe.rb +3 -5
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +6 -8
- data/lib/rigor/analysis/runner/declaration_position.rb +1 -2
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +316 -40
- data/lib/rigor/analysis/runner/effect_annotation_residual_pass.rb +2 -3
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +9 -10
- data/lib/rigor/analysis/runner/pool_coordinator.rb +430 -77
- data/lib/rigor/analysis/runner/project_pre_passes.rb +12 -6
- data/lib/rigor/analysis/runner/run_snapshots.rb +13 -3
- data/lib/rigor/analysis/runner.rb +200 -43
- data/lib/rigor/analysis/worker_session.rb +36 -12
- data/lib/rigor/bleeding_edge.rb +12 -24
- data/lib/rigor/builtins/hkt_builtins.rb +2 -2
- data/lib/rigor/builtins/imported_refinements.rb +166 -30
- data/lib/rigor/builtins/predefined_constant_refinements.rb +5 -7
- data/lib/rigor/builtins/regex_refinement.rb +4 -4
- data/lib/rigor/builtins/static_return_refinements.rb +5 -6
- data/lib/rigor/cache/annotation_location.rb +70 -0
- data/lib/rigor/cache/descriptor.rb +58 -20
- data/lib/rigor/cache/engine_source.rb +4 -4
- data/lib/rigor/cache/file_digest.rb +9 -1
- data/lib/rigor/cache/incremental_snapshot.rb +40 -6
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +0 -3
- data/lib/rigor/cache/rbs_class_type_param_names.rb +0 -3
- data/lib/rigor/cache/rbs_constant_table.rb +0 -3
- data/lib/rigor/cache/rbs_descriptor.rb +79 -11
- data/lib/rigor/cache/rbs_environment.rb +8 -4
- data/lib/rigor/cache/rbs_environment_marshal_patch.rb +39 -0
- data/lib/rigor/cache/rbs_known_class_names.rb +0 -3
- data/lib/rigor/cache/store.rb +85 -33
- data/lib/rigor/cli/annotate_command.rb +5 -6
- data/lib/rigor/cli/check_command.rb +57 -10
- data/lib/rigor/cli/check_invocation.rb +6 -11
- data/lib/rigor/cli/check_runner_factory.rb +1 -5
- data/lib/rigor/cli/coverage_command.rb +1 -1
- data/lib/rigor/cli/coverage_mutation.rb +12 -3
- data/lib/rigor/cli/coverage_scan.rb +1 -5
- data/lib/rigor/cli/diff_command.rb +1 -1
- data/lib/rigor/cli/doc_links.rb +3 -3
- data/lib/rigor/cli/docs_command.rb +2 -2
- data/lib/rigor/cli/doctor_command.rb +85 -38
- data/lib/rigor/cli/effects_command.rb +2 -2
- data/lib/rigor/cli/effects_diff_renderer.rb +3 -3
- data/lib/rigor/cli/effects_snapshot_command.rb +1 -1
- data/lib/rigor/cli/explain_command.rb +34 -1
- data/lib/rigor/cli/fused_protection_report.rb +7 -1
- data/lib/rigor/cli/lsp_command.rb +1 -1
- data/lib/rigor/cli/mcp_command.rb +1 -1
- data/lib/rigor/cli/measurement_integrity_warning.rb +4 -5
- data/lib/rigor/cli/mutation_fork_scan.rb +6 -6
- data/lib/rigor/cli/mutation_protection_report.rb +7 -1
- data/lib/rigor/cli/plugin_command.rb +1 -1
- data/lib/rigor/cli/plugins_command.rb +2 -1
- data/lib/rigor/cli/prism_colorizer.rb +2 -2
- data/lib/rigor/cli/protection_fork_scan.rb +6 -6
- data/lib/rigor/cli/show_bleedingedge_command.rb +1 -1
- data/lib/rigor/cli/sig_gen_command.rb +31 -2
- data/lib/rigor/cli/skill_command.rb +1 -1
- data/lib/rigor/cli/skill_deep_probe.rb +4 -4
- data/lib/rigor/cli/skill_describe.rb +36 -35
- data/lib/rigor/cli/trace_command.rb +4 -4
- data/lib/rigor/cli/trace_renderer.rb +5 -6
- data/lib/rigor/cli/triage_command.rb +1 -1
- data/lib/rigor/cli/type_of_command.rb +10 -6
- data/lib/rigor/cli/type_scan_command.rb +4 -4
- data/lib/rigor/cli/unused_command.rb +11 -3
- data/lib/rigor/cli/upgrade_command.rb +1 -1
- data/lib/rigor/cli.rb +68 -6
- data/lib/rigor/config_audit.rb +30 -5
- data/lib/rigor/configuration/severity_profile.rb +6 -6
- data/lib/rigor/configuration.rb +43 -4
- data/lib/rigor/effects/attribution.rb +1 -3
- data/lib/rigor/effects/config_envelopes.rb +6 -8
- data/lib/rigor/effects/definition_lines.rb +25 -6
- data/lib/rigor/effects/effect_table.rb +0 -1
- data/lib/rigor/effects/entry_points.rb +0 -2
- data/lib/rigor/effects/envelope_check.rb +8 -8
- data/lib/rigor/effects/envelope_index.rb +5 -8
- data/lib/rigor/effects/framework_units.rb +4 -6
- data/lib/rigor/effects/identity.rb +4 -6
- data/lib/rigor/effects/inline_anchor.rb +7 -7
- data/lib/rigor/effects/label_intent.rb +3 -4
- data/lib/rigor/effects/liskov_check.rb +8 -8
- data/lib/rigor/effects/method_key.rb +1 -1
- data/lib/rigor/effects/plugin_facts.rb +4 -6
- data/lib/rigor/effects/propagator.rb +2 -3
- data/lib/rigor/effects/scanner.rb +1 -1
- data/lib/rigor/effects/signature_sources.rb +3 -5
- data/lib/rigor/effects/snapshot.rb +10 -10
- data/lib/rigor/effects/snapshot_diff.rb +1 -1
- data/lib/rigor/effects/unit_scan.rb +10 -10
- data/lib/rigor/effects/unknown_label_check.rb +3 -8
- data/lib/rigor/effects/unknown_label_report.rb +3 -4
- data/lib/rigor/environment/bundle_sig_discovery.rb +6 -6
- data/lib/rigor/environment/class_registry.rb +3 -1
- data/lib/rigor/environment/failure_slot.rb +28 -0
- data/lib/rigor/environment/installed_gem_set.rb +85 -0
- data/lib/rigor/environment/lockfile_resolver.rb +51 -4
- data/lib/rigor/environment/missing_gem_constant_index.rb +4 -4
- data/lib/rigor/environment/rbs_collection_discovery.rb +5 -5
- data/lib/rigor/environment/rbs_coverage_report.rb +5 -5
- data/lib/rigor/environment/rbs_hierarchy.rb +3 -1
- data/lib/rigor/environment/rbs_loader.rb +613 -113
- data/lib/rigor/environment.rb +189 -27
- data/lib/rigor/flow_contribution/merger.rb +0 -2
- data/lib/rigor/flow_contribution.rb +11 -13
- data/lib/rigor/inference/acceptance.rb +153 -8
- data/lib/rigor/inference/block_parameter_binder.rb +2 -3
- data/lib/rigor/inference/body_fixpoint.rb +5 -5
- data/lib/rigor/inference/budget_trace.rb +1 -5
- data/lib/rigor/inference/captured_locals.rb +2 -3
- data/lib/rigor/inference/closure_escape_analyzer.rb +2 -4
- data/lib/rigor/inference/coverage_scanner.rb +4 -6
- data/lib/rigor/inference/dynamic_origin.rb +1 -1
- data/lib/rigor/inference/element_read_widening.rb +168 -0
- data/lib/rigor/inference/expression_typer.rb +763 -143
- data/lib/rigor/inference/fork_map.rb +5 -7
- data/lib/rigor/inference/hkt_reducer.rb +2 -3
- data/lib/rigor/inference/hkt_registry.rb +19 -10
- data/lib/rigor/inference/hkt_sugar_translator.rb +15 -21
- data/lib/rigor/inference/index_write_widening.rb +1 -5
- data/lib/rigor/inference/macro_block_self_type.rb +1 -4
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +2 -9
- data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +305 -19
- data/lib/rigor/inference/method_dispatcher/data_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/json_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +7 -1
- data/lib/rigor/inference/method_dispatcher/math_folding.rb +41 -3
- data/lib/rigor/inference/method_dispatcher/method_folding.rb +2 -5
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +61 -47
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +82 -0
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +165 -31
- data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +25 -4
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +2 -8
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +1 -2
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +4 -5
- data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +85 -4
- data/lib/rigor/inference/method_dispatcher/time_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/universal_object_dispatch.rb +1 -2
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher.rb +12 -13
- data/lib/rigor/inference/method_parameter_binder.rb +4 -6
- data/lib/rigor/inference/multi_target_binder.rb +1 -3
- data/lib/rigor/inference/mutation_rejoin.rb +168 -0
- data/lib/rigor/inference/mutation_widening.rb +100 -51
- data/lib/rigor/inference/narrowing.rb +299 -46
- data/lib/rigor/inference/optimistic_origin.rb +1 -7
- data/lib/rigor/inference/origin_lookup.rb +2 -3
- data/lib/rigor/inference/parameter_inference_collector.rb +5 -6
- data/lib/rigor/inference/pre_eval_constants.rb +6 -5
- data/lib/rigor/inference/precision_scanner.rb +3 -4
- data/lib/rigor/inference/project_patched_methods.rb +2 -2
- data/lib/rigor/inference/project_patched_scanner.rb +3 -3
- data/lib/rigor/inference/protection_scanner.rb +1 -2
- data/lib/rigor/inference/range_constant.rb +57 -0
- data/lib/rigor/inference/rbs_type_translator.rb +49 -11
- data/lib/rigor/inference/receiver_alias.rb +3 -3
- data/lib/rigor/inference/refinement_mutation.rb +72 -0
- data/lib/rigor/inference/scope_indexer.rb +688 -151
- data/lib/rigor/inference/statement_evaluator.rb +221 -50
- data/lib/rigor/inference/string_mutation.rb +60 -0
- data/lib/rigor/inference/struct_fold_safety.rb +6 -7
- data/lib/rigor/inference/synthetic_method_index.rb +1 -2
- data/lib/rigor/inference/synthetic_method_scanner.rb +4 -6
- data/lib/rigor/inference/version_guard.rb +28 -21
- data/lib/rigor/inference/void_origin.rb +3 -3
- data/lib/rigor/inference/void_tail_summary.rb +2 -4
- data/lib/rigor/language_server/buffer_table.rb +4 -4
- data/lib/rigor/language_server/completion_provider.rb +1 -1
- data/lib/rigor/language_server/debouncer.rb +1 -1
- data/lib/rigor/language_server/diagnostic_publisher.rb +4 -4
- data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
- data/lib/rigor/language_server/folding_range_provider.rb +1 -1
- data/lib/rigor/language_server/hover_provider.rb +1 -1
- data/lib/rigor/language_server/hover_renderer.rb +2 -2
- data/lib/rigor/language_server/incremental_sync.rb +6 -6
- data/lib/rigor/language_server/project_context.rb +2 -5
- data/lib/rigor/language_server/publish_batcher.rb +2 -2
- data/lib/rigor/language_server/selection_range_provider.rb +2 -2
- data/lib/rigor/language_server/server.rb +9 -9
- data/lib/rigor/language_server/signature_help_provider.rb +1 -1
- data/lib/rigor/language_server/uri.rb +1 -1
- data/lib/rigor/plugin/base.rb +90 -21
- data/lib/rigor/plugin/bundled_catalog.rb +167 -0
- data/lib/rigor/plugin/effect_attribution.rb +7 -7
- data/lib/rigor/plugin/effect_entry_points.rb +3 -3
- data/lib/rigor/plugin/fact_store.rb +6 -6
- data/lib/rigor/plugin/io_boundary.rb +93 -8
- data/lib/rigor/plugin/isolation.rb +29 -6
- data/lib/rigor/plugin/loader.rb +31 -12
- data/lib/rigor/plugin/macro/heredoc_template.rb +1 -1
- data/lib/rigor/plugin/macro/trait_registry.rb +1 -1
- data/lib/rigor/plugin/manifest.rb +23 -1
- data/lib/rigor/plugin/registry.rb +67 -14
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +12 -1
- data/lib/rigor/plugin/trust_policy.rb +2 -4
- data/lib/rigor/plugin/type_node_resolver.rb +3 -3
- data/lib/rigor/plugin_gap_advisory.rb +96 -0
- data/lib/rigor/project_environment.rb +138 -0
- data/lib/rigor/protection/analysis_guard.rb +93 -14
- data/lib/rigor/protection/closure_kill_oracle.rb +67 -23
- data/lib/rigor/protection/dependency_closure.rb +5 -8
- data/lib/rigor/protection/diagnostic_oracle.rb +2 -2
- data/lib/rigor/protection/discovery_seed.rb +11 -11
- data/lib/rigor/protection/kill_signature.rb +2 -4
- data/lib/rigor/protection/measurement_integrity.rb +1 -3
- data/lib/rigor/protection/mutation_cache.rb +6 -9
- data/lib/rigor/protection/mutation_scanner.rb +12 -15
- data/lib/rigor/protection/mutator.rb +2 -1
- data/lib/rigor/protection/test_suite_oracle.rb +5 -5
- data/lib/rigor/rbs_extended/conformance_checker.rb +4 -3
- data/lib/rigor/rbs_extended/envelope_scanner.rb +12 -13
- data/lib/rigor/rbs_extended/hkt_directives.rb +16 -1
- data/lib/rigor/rbs_extended/reporter.rb +122 -16
- data/lib/rigor/rbs_extended.rb +67 -22
- data/lib/rigor/reflection/constant_path.rb +126 -0
- data/lib/rigor/reflection.rb +26 -10
- data/lib/rigor/runtime/jit.rb +6 -8
- data/lib/rigor/scope/discovery_index.rb +30 -0
- data/lib/rigor/scope.rb +203 -4
- data/lib/rigor/sig_gen/generator.rb +181 -102
- data/lib/rigor/sig_gen/layout_index.rb +3 -4
- data/lib/rigor/sig_gen/meta_class_shape.rb +3 -5
- data/lib/rigor/sig_gen/observation_collector.rb +17 -15
- data/lib/rigor/sig_gen/path_mapper.rb +4 -6
- data/lib/rigor/sig_gen/rbs_validity.rb +4 -4
- data/lib/rigor/sig_gen/renderer.rb +17 -11
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +111 -0
- data/lib/rigor/sig_gen/superclass_spelling.rb +27 -0
- data/lib/rigor/sig_gen/type_elaborator.rb +1 -3
- data/lib/rigor/sig_gen/writer.rb +23 -6
- data/lib/rigor/signature_path_audit.rb +153 -6
- data/lib/rigor/source/literals.rb +0 -23
- data/lib/rigor/source/node_children.rb +0 -2
- data/lib/rigor/source/node_locator.rb +5 -11
- data/lib/rigor/source/node_walker.rb +2 -5
- data/lib/rigor/triage/catalogue.rb +1 -3
- data/lib/rigor/triage.rb +3 -5
- data/lib/rigor/type/accepts_result.rb +24 -6
- data/lib/rigor/type/combinator.rb +68 -5
- data/lib/rigor/type/data_class.rb +2 -2
- data/lib/rigor/type/data_instance.rb +4 -4
- data/lib/rigor/type/float_range.rb +128 -0
- data/lib/rigor/type/hash_shape.rb +5 -5
- data/lib/rigor/type/integer_range.rb +13 -8
- data/lib/rigor/type/nominal.rb +8 -2
- data/lib/rigor/type/refined.rb +3 -3
- data/lib/rigor/type/struct_class.rb +3 -3
- data/lib/rigor/type/struct_instance.rb +4 -4
- data/lib/rigor/type.rb +1 -0
- data/lib/rigor/type_node/generic.rb +1 -1
- data/lib/rigor/type_node/range_literal.rb +25 -0
- data/lib/rigor/type_node/resolver_chain.rb +1 -1
- data/lib/rigor/type_node.rb +1 -0
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +0 -4
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +0 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +0 -2
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +1 -0
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +0 -4
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +3 -5
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +1 -4
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +1 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +33 -30
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +0 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -3
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +28 -2
- data/plugins/rigor-actionpack/sig/action_controller.rbs +71 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +0 -4
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +0 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +0 -2
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/recurring_scan.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +1 -0
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +3 -4
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +1 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +1 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +42 -7
- data/plugins/rigor-activerecord/sig/active_record/framework.rbs +123 -0
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +1 -0
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +9 -2
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +119 -14
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +1 -0
- data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +1 -0
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +9 -7
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +7 -3
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +1 -0
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +8 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +11 -7
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -11
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +9 -4
- data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +1 -0
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +0 -5
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +8 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +36 -4
- data/plugins/rigor-ffi-rzmq/lib/rigor/plugin/ffi_rzmq.rb +1 -0
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +8 -6
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +6 -3
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +1 -0
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +2 -1
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +0 -3
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +1 -0
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +0 -5
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/authorization_scan.rb +2 -2
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +0 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +0 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +1 -0
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +0 -12
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +1 -3
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +0 -1
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +1 -0
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/acronyms.rb +5 -5
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +1 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +3 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/grape_api_discoverer.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +9 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +2 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +1 -0
- data/plugins/rigor-railties/lib/rigor/plugin/railties.rb +1 -0
- data/plugins/rigor-rbnacl/lib/rigor/plugin/rbnacl.rb +13 -1
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +128 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +0 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +0 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +1 -5
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +2 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +1 -0
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +0 -3
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +1 -0
- data/plugins/rigor-sassc/lib/rigor/plugin/sassc.rb +1 -0
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +1 -9
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +1 -0
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +0 -4
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/effects.rb +1 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/schedule_scan.rb +1 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +0 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +0 -2
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +1 -0
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +1 -0
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +2 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +1 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +3 -9
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +4 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +1 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +4 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +7 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +5 -5
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +1 -0
- data/sig/rigor/analysis/reachability/scan_cache.rbs +12 -0
- data/sig/rigor/cache.rbs +2 -3
- data/sig/rigor/environment.rbs +11 -0
- data/sig/rigor/inference.rbs +3 -10
- data/sig/rigor/plugin/io_boundary.rbs +4 -0
- data/sig/rigor/plugin/manifest.rbs +2 -1
- data/sig/rigor/reflection.rbs +3 -1
- data/sig/rigor/scope.rbs +24 -3
- data/sig/rigor/sig_gen/skip_reason_catalog.rbs +14 -0
- data/sig/rigor/type.rbs +27 -1
- data/sig/rigor.rbs +1 -0
- data/skills/rigor-ask/SKILL.md +8 -6
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +13 -2
- data/skills/rigor-project-init/SKILL.md +6 -3
- data/skills/rigor-project-init/references/02-configure.md +10 -6
- data/skills/rigor-project-init/references/06-agent-contract.md +67 -0
- data/skills/rigor-type-oracle/SKILL.md +228 -0
- data/skills/rigor-type-oracle/references/01-oracle-commands.md +261 -0
- data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +52 -0
- data/skills/rigor-type-oracle/references/03-gap-protocol.md +128 -0
- data/skills/rigor-unused-adjudicate/SKILL.md +8 -5
- metadata +28 -3
- data/lib/rigor/cli/probe_environment.rb +0 -85
- data/sig/rigor/inference/builtins/numeric_catalog.rbs +0 -3
|
@@ -4,9 +4,11 @@ require "prism"
|
|
|
4
4
|
|
|
5
5
|
require_relative "../configuration"
|
|
6
6
|
require_relative "../environment"
|
|
7
|
+
require_relative "../project_environment"
|
|
7
8
|
require_relative "../scope"
|
|
8
9
|
require_relative "../reflection"
|
|
9
10
|
require_relative "../type"
|
|
11
|
+
require_relative "../source/constant_path"
|
|
10
12
|
require_relative "../source/literals"
|
|
11
13
|
require_relative "../source/node_children"
|
|
12
14
|
require_relative "../inference/def_return_typer"
|
|
@@ -24,28 +26,38 @@ module Rigor
|
|
|
24
26
|
# body's last expression to derive an inferred return, looks up the project's existing RBS declaration (if
|
|
25
27
|
# any), and emits one {MethodCandidate} per def.
|
|
26
28
|
#
|
|
27
|
-
# The
|
|
28
|
-
# -
|
|
29
|
-
# defs are
|
|
30
|
-
# - Parameter
|
|
31
|
-
# `--params=observed`
|
|
32
|
-
#
|
|
29
|
+
# The scope, as it stands after the slices that widened the MVP:
|
|
30
|
+
# - Instance and singleton methods inside a nameable `class` / `module` body are considered. Top-level /
|
|
31
|
+
# DSL-block defs have no nameable receiver and are not candidates.
|
|
32
|
+
# - Parameter types are `untyped` per ADR-14 § "Robustness principle compliance" clause 2 unless
|
|
33
|
+
# `--params=observed` supplies call-site observations; the parameter LIST always mirrors the def's runtime
|
|
34
|
+
# shape (required / optional / rest / trailing / keyword / keyword-rest / forwarding / block). Issue #778
|
|
35
|
+
# retired the slice-1 gate that skipped every shape beyond required positionals as
|
|
36
|
+
# `sig.skipped.complex-shape`: the body typer binds every parameter to `untyped` when no RBS declares the
|
|
37
|
+
# method, so the inferred return is the same clause-1 answer for every shape, and the renderer the
|
|
38
|
+
# `initialize` stub already used spells them all.
|
|
33
39
|
# - A `Dynamic[top]` inferred return becomes `sig.skipped.untyped-return` — emitting `untyped` would obscure
|
|
34
40
|
# rather than help.
|
|
35
41
|
# - Tighter-return detection compares the RBS-erased spellings only when the existing declared return
|
|
36
42
|
# strictly accepts the inferred one (acceptance check under the engine's current `:gradual` mode; ADR-14
|
|
37
43
|
# reserves the eventual `:strict` mode).
|
|
44
|
+
# - A declared `void` return is never compared as a value type. It is the author's statement that the
|
|
45
|
+
# return is not part of the contract, which no inference can synthesize, so the method classifies
|
|
46
|
+
# `equivalent` carrying `void` itself as the declared spelling (#836; see {#declares_void?}).
|
|
47
|
+
# - A proposal that erases to an RBS literal never tightens an existing declaration: the declared type is
|
|
48
|
+
# the author's abstraction over the body and the literal is what it hides (#837; see
|
|
49
|
+
# {#pins_literal_over_declaration?}). A method with no declaration is unaffected — clause 1 still emits
|
|
50
|
+
# the strictest carrier the body proves.
|
|
38
51
|
class Generator # rubocop:disable Metrics/ClassLength
|
|
39
52
|
# Methods the generator rendered into RBS that `rbs` itself rejects. Populated by {#build_candidate}; each
|
|
40
53
|
# one is a Rigor rendering DEFECT, not a property of the user's code, so the CLI reports them as such.
|
|
41
54
|
UnrenderableMethod = Data.define(:path, :class_name, :method_name, :rbs, :error)
|
|
42
55
|
|
|
43
|
-
# @return
|
|
56
|
+
# @return empty on a healthy run; read after {#run}.
|
|
44
57
|
attr_reader :unrenderable, :unresolvable_superclasses
|
|
45
58
|
|
|
46
|
-
# @param
|
|
47
|
-
# @param
|
|
48
|
-
# @param observations [Hash{[String, Symbol] => Array<Array<Rigor::Type>>}]
|
|
59
|
+
# @param paths — files / directories to scan.
|
|
60
|
+
# @param observations — => Array<Array<Rigor::Type>>}]
|
|
49
61
|
# ADR-14 slice 3 — per-target-method arg-tuple observations
|
|
50
62
|
# produced by {ObservationCollector}. An empty Hash (the default)
|
|
51
63
|
# means "no observations available; emit `untyped` for every
|
|
@@ -80,10 +92,9 @@ module Rigor
|
|
|
80
92
|
map.transform_values { |entries| entries.map { |entry| ObservedCall.from(entry) } }
|
|
81
93
|
end
|
|
82
94
|
|
|
83
|
-
# @return [Array<MethodCandidate>]
|
|
84
95
|
def run
|
|
85
|
-
@environment = build_environment
|
|
86
96
|
resolved = resolve_paths(@paths)
|
|
97
|
+
@environment = build_environment(resolved)
|
|
87
98
|
candidates = resolved.flat_map { |path| analyse_file(path, @environment) }
|
|
88
99
|
demote_overridden_base_methods(
|
|
89
100
|
demote_unresolvable_superclasses(resolve_superclass_spellings(candidates))
|
|
@@ -307,11 +318,13 @@ module Rigor
|
|
|
307
318
|
)
|
|
308
319
|
end
|
|
309
320
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
321
|
+
# Issue #821 — the SAME type universe `rigor check` analyses against: the project's `sig/`, the plugins,
|
|
322
|
+
# the bundle's per-gem signatures and the `rbs collection`. Built with two keywords only, the generator
|
|
323
|
+
# could not see a gem-declared superclass, and the skip guard above (`record_unresolvable_superclass`)
|
|
324
|
+
# then declined to emit every class descending from one — every Rails model, on a project whose
|
|
325
|
+
# collection was installed and whose `check` read it.
|
|
326
|
+
def build_environment(source_files = [])
|
|
327
|
+
ProjectEnvironment.build(configuration: @configuration, source_files: source_files)
|
|
315
328
|
end
|
|
316
329
|
|
|
317
330
|
def resolve_paths(args)
|
|
@@ -409,14 +422,22 @@ module Rigor
|
|
|
409
422
|
end
|
|
410
423
|
end
|
|
411
424
|
|
|
425
|
+
# [#722](https://github.com/rigortype/rigor/issues/722) residue 3 — the qualified name is built by
|
|
426
|
+
# `Source::ConstantPath.declaration_prefix`, the same reader the engine's declaration walks use, so a
|
|
427
|
+
# ROOTED header re-anchors here too. Appending the rendered name to the enclosing prefix wrote
|
|
428
|
+
# `class ::Foo` inside `module MyApp` out as `MyApp::Foo` — sig-gen's own copy of #708, and the one
|
|
429
|
+
# copy that persists its answer into a file the user keeps.
|
|
430
|
+
#
|
|
431
|
+
# `prefix` stays the nesting the header is WRITTEN in for {#record_superclass}: `::` re-anchors the
|
|
432
|
+
# declaration, not the superclass expression beside it, which Ruby still evaluates in the enclosing cref.
|
|
412
433
|
def descend_into_namespace?(node, prefix, out)
|
|
413
|
-
|
|
414
|
-
return false unless
|
|
434
|
+
child_prefix = Source::ConstantPath.declaration_prefix(prefix, node.constant_path)
|
|
435
|
+
return false unless child_prefix
|
|
415
436
|
|
|
416
|
-
full =
|
|
437
|
+
full = child_prefix.join("::")
|
|
417
438
|
@namespace_kinds[full] = node.is_a?(Prism::ClassNode) ? :class : :module
|
|
418
439
|
record_superclass(node, full, prefix)
|
|
419
|
-
walk_namespace_body(node,
|
|
440
|
+
walk_namespace_body(node, child_prefix, out)
|
|
420
441
|
true
|
|
421
442
|
end
|
|
422
443
|
|
|
@@ -650,8 +671,8 @@ module Rigor
|
|
|
650
671
|
end
|
|
651
672
|
|
|
652
673
|
# Emits `def initialize: (<shape>) -> void`. The return is always `void` because Ruby's `initialize`
|
|
653
|
-
# return value is never meaningful. The parameter list mirrors the runtime shape
|
|
654
|
-
#
|
|
674
|
+
# return value is never meaningful. The parameter list mirrors the runtime shape through the same
|
|
675
|
+
# {#render_param_list} every other def renders with.
|
|
655
676
|
#
|
|
656
677
|
# When `--params=observed` populates `@observations` for `[class_name, :initialize]` (via the
|
|
657
678
|
# `ObservationCollector`'s `.new` → `:initialize` routing), positional and keyword arg types come from the
|
|
@@ -659,7 +680,7 @@ module Rigor
|
|
|
659
680
|
# clause 2.
|
|
660
681
|
def initialize_stub_candidate(path, def_node, class_name)
|
|
661
682
|
params = def_node.parameters
|
|
662
|
-
rbs = "def initialize: (#{
|
|
683
|
+
rbs = "def initialize: (#{render_param_list(params, class_name, :initialize)})" \
|
|
663
684
|
"#{block_signature_suffix(params)} -> void"
|
|
664
685
|
build_candidate(
|
|
665
686
|
path: path, class_name: class_name, method_name: :initialize,
|
|
@@ -668,57 +689,81 @@ module Rigor
|
|
|
668
689
|
)
|
|
669
690
|
end
|
|
670
691
|
|
|
671
|
-
def
|
|
692
|
+
# The RBS parameter list of a def, mirroring its runtime shape position by position: `untyped` per
|
|
693
|
+
# required positional, `?untyped` per optional, `*untyped` for a rest, one `untyped` per trailing
|
|
694
|
+
# positional after the rest, `name: untyped` / `?name: untyped` per keyword, `**untyped` for a keyword
|
|
695
|
+
# rest, and `*untyped, **untyped` for `...` forwarding (its block half is {#block_signature_suffix}'s).
|
|
696
|
+
# `**nil` declares that no keywords are accepted, which RBS cannot spell, so it renders nothing.
|
|
697
|
+
#
|
|
698
|
+
# Per ADR-5 clause 2 every position is `untyped` unless `--params=observed` supplied call-site
|
|
699
|
+
# observations, in which case each leading positional and each keyword carries the union of the types the
|
|
700
|
+
# arity-compatible observations passed there ({#arity_matched_observations}). The rest, the trailing
|
|
701
|
+
# positionals and the keyword rest stay `untyped`: an observation does not say which of its arguments the
|
|
702
|
+
# splat absorbed. Before #778 only `initialize` rendered through this path and every other def with a
|
|
703
|
+
# shape beyond required positionals was skipped as `sig.skipped.complex-shape`.
|
|
704
|
+
def render_param_list(params, class_name, method_name)
|
|
672
705
|
return "" unless params.is_a?(Prism::ParametersNode)
|
|
673
706
|
|
|
674
|
-
observations =
|
|
675
|
-
offset = 0
|
|
707
|
+
observations = arity_matched_observations(class_name, method_name, params)
|
|
676
708
|
parts = []
|
|
677
|
-
|
|
678
|
-
params.requireds.
|
|
679
|
-
|
|
680
|
-
end
|
|
681
|
-
offset += params.requireds.size
|
|
682
|
-
|
|
683
|
-
params.optionals.each_with_index do |_, i|
|
|
684
|
-
parts << initialize_positional_type(observations, offset + i, "?")
|
|
685
|
-
end
|
|
686
|
-
|
|
709
|
+
params.requireds.each_index { |i| parts << positional_type(observations, i, "") }
|
|
710
|
+
offset = params.requireds.size
|
|
711
|
+
params.optionals.each_index { |i| parts << positional_type(observations, offset + i, "?") }
|
|
687
712
|
parts << "*untyped" if params.rest
|
|
713
|
+
parts.concat(Array.new(params.posts.size, "untyped"))
|
|
688
714
|
params.keywords.each { |kw| parts << render_keyword_param(kw, observations) }
|
|
689
|
-
parts
|
|
715
|
+
parts.concat(keyword_rest_parts(params))
|
|
690
716
|
parts.join(", ")
|
|
691
717
|
end
|
|
692
718
|
|
|
719
|
+
def keyword_rest_parts(params)
|
|
720
|
+
case params.keyword_rest
|
|
721
|
+
when Prism::ForwardingParameterNode
|
|
722
|
+
# `...` forwards positionals as well as keywords; a rest already rendered covers the former.
|
|
723
|
+
params.rest ? ["**untyped"] : ["*untyped", "**untyped"]
|
|
724
|
+
when Prism::KeywordRestParameterNode then ["**untyped"]
|
|
725
|
+
else []
|
|
726
|
+
end
|
|
727
|
+
end
|
|
728
|
+
|
|
693
729
|
# The RBS block suffix for a `def` that takes a `&block` parameter, e.g. ` ?{ (*untyped) -> untyped }`.
|
|
694
730
|
# A block belongs AFTER the parameter parens in RBS (`(params) ?{ block } -> ret`), not inside them —
|
|
695
731
|
# emitting it as a comma-joined member produced `(**untyped, ?{ (?) -> void })`, which RBS rejects
|
|
696
732
|
# (`optional keyword argument type is expected`) and which then collapsed the whole env build. sig-gen
|
|
697
733
|
# never observes the block's own signature, so it is rendered maximally lenient (ADR-5): an optional
|
|
698
|
-
# block (`?{`, since a `&block` need not be passed) taking `*untyped` and returning `untyped`.
|
|
699
|
-
# "" when the method takes no block.
|
|
734
|
+
# block (`?{`, since a `&block` need not be passed) taking `*untyped` and returning `untyped`. `...`
|
|
735
|
+
# forwards a block too and gets the same suffix. Returns "" when the method takes no block.
|
|
700
736
|
def block_signature_suffix(params)
|
|
701
737
|
return "" unless params.is_a?(Prism::ParametersNode)
|
|
702
|
-
return ""
|
|
738
|
+
return "" unless params.block || params.keyword_rest.is_a?(Prism::ForwardingParameterNode)
|
|
703
739
|
|
|
704
740
|
" ?{ (*untyped) -> untyped }"
|
|
705
741
|
end
|
|
706
742
|
|
|
707
|
-
#
|
|
708
|
-
#
|
|
709
|
-
# overload the
|
|
710
|
-
|
|
743
|
+
# Observations under `[class_name, method_name]` whose positional arity the def accepts: at least its
|
|
744
|
+
# required count (leading plus trailing), and, unless a rest or `...` absorbs the surplus, at most
|
|
745
|
+
# required plus optional. An arity outside that window describes a different overload the signature
|
|
746
|
+
# cannot express, so it says nothing about these positions. #778 widened the window for ordinary defs
|
|
747
|
+
# from the exact required count — `def optional(text = "x")` called as `optional` AND as `optional("y")`
|
|
748
|
+
# now credits both call sites.
|
|
749
|
+
def arity_matched_observations(class_name, method_name, params)
|
|
711
750
|
return [] if @observations.empty?
|
|
712
751
|
|
|
713
|
-
list = @observations[[class_name,
|
|
714
|
-
min = params.requireds.size
|
|
715
|
-
max = min + params.optionals.size
|
|
716
|
-
list.select { |obs|
|
|
752
|
+
list = @observations[[class_name, method_name]] || []
|
|
753
|
+
min = params.requireds.size + params.posts.size
|
|
754
|
+
max = unbounded_positionals?(params) ? Float::INFINITY : min + params.optionals.size
|
|
755
|
+
list.select { |obs| obs.positional.size.between?(min, max) }
|
|
756
|
+
end
|
|
757
|
+
|
|
758
|
+
def unbounded_positionals?(params)
|
|
759
|
+
!params.rest.nil? || params.keyword_rest.is_a?(Prism::ForwardingParameterNode)
|
|
717
760
|
end
|
|
718
761
|
|
|
719
|
-
|
|
762
|
+
# A bare union is a valid positional type in RBS (`(String | Integer, ?String | Integer)`), so unlike the
|
|
763
|
+
# return position it is not parenthesised.
|
|
764
|
+
def positional_type(observations, index, prefix)
|
|
720
765
|
types = observations.filter_map { |obs| obs.positional[index] }
|
|
721
|
-
"#{prefix}#{
|
|
766
|
+
"#{prefix}#{union_erase(types)}"
|
|
722
767
|
end
|
|
723
768
|
|
|
724
769
|
def render_keyword_param(keyword, observations)
|
|
@@ -746,10 +791,6 @@ module Rigor
|
|
|
746
791
|
return nil if initialize_excludes?(def_node, kind)
|
|
747
792
|
return initialize_stub_candidate(path, def_node, class_name) if non_trivial_initialize?(def_node, kind)
|
|
748
793
|
|
|
749
|
-
unless simple_parameter_shape?(def_node.parameters)
|
|
750
|
-
return skipped(path, def_node, class_name, kind, :complex_shape)
|
|
751
|
-
end
|
|
752
|
-
|
|
753
794
|
inferred = infer_return_type(def_node, scope_index)
|
|
754
795
|
return skipped(path, def_node, class_name, kind, :untyped_return) if inferred.nil? || dynamic_top?(inferred)
|
|
755
796
|
|
|
@@ -763,20 +804,6 @@ module Rigor
|
|
|
763
804
|
end
|
|
764
805
|
end
|
|
765
806
|
|
|
766
|
-
# Required positionals only; the MVP's body-typing path gives well-defined returns for that shape.
|
|
767
|
-
# Optional / rest / keyword / block parameters route through the `sig.skipped.complex-shape` reason until
|
|
768
|
-
# slices 3+ widen the param policy.
|
|
769
|
-
def simple_parameter_shape?(params)
|
|
770
|
-
return true if params.nil?
|
|
771
|
-
return false unless params.is_a?(Prism::ParametersNode)
|
|
772
|
-
|
|
773
|
-
params.optionals.empty? &&
|
|
774
|
-
params.rest.nil? &&
|
|
775
|
-
params.keywords.empty? &&
|
|
776
|
-
params.keyword_rest.nil? &&
|
|
777
|
-
params.block.nil?
|
|
778
|
-
end
|
|
779
|
-
|
|
780
807
|
# Mirrors the `def.return-type-mismatch` rule's body-type extraction: type the implicit-return expression
|
|
781
808
|
# under the scope the indexer associated with the body. The parameter bindings (typed `untyped` per the
|
|
782
809
|
# indexer's default) come from `with_local` inside `StatementEvaluator`; the result is the carrier the
|
|
@@ -826,7 +853,14 @@ module Rigor
|
|
|
826
853
|
)
|
|
827
854
|
end
|
|
828
855
|
|
|
856
|
+
# The RBS spelling carried for a `void`-declared method, so `--diff` shows the author's own word rather
|
|
857
|
+
# than the `top` the translator would erase it to.
|
|
858
|
+
VOID_RETURN_RBS = "void"
|
|
859
|
+
private_constant :VOID_RETURN_RBS
|
|
860
|
+
|
|
829
861
|
def compare_against_declared(path, def_node, class_name, kind, inferred, method_def)
|
|
862
|
+
return equivalent(path, def_node, class_name, kind, inferred, VOID_RETURN_RBS) if declares_void?(method_def)
|
|
863
|
+
|
|
830
864
|
declared = build_declared_return(method_def)
|
|
831
865
|
declared_rbs = declared&.erase_to_rbs
|
|
832
866
|
inferred_rbs = inferred.erase_to_rbs
|
|
@@ -835,7 +869,7 @@ module Rigor
|
|
|
835
869
|
return equivalent(path, def_node, class_name, kind, inferred, declared_rbs)
|
|
836
870
|
end
|
|
837
871
|
|
|
838
|
-
unless tighter?(declared, inferred) && !
|
|
872
|
+
unless tighter?(declared, inferred) && !literal_decline?(inferred, def_node)
|
|
839
873
|
return equivalent(path, def_node, class_name, kind, inferred, declared_rbs)
|
|
840
874
|
end
|
|
841
875
|
|
|
@@ -851,6 +885,28 @@ module Rigor
|
|
|
851
885
|
)
|
|
852
886
|
end
|
|
853
887
|
|
|
888
|
+
# Issue #836 — a declared `void` is return INTENT, never a wide value type waiting to be narrowed, so it
|
|
889
|
+
# is not compared against the body at all.
|
|
890
|
+
#
|
|
891
|
+
# `void` says the return value is not part of the method's contract. No synthesis can produce it: a type
|
|
892
|
+
# built from a body is always the type of the body's last expression, so `void` exists only on the
|
|
893
|
+
# CHECKING side, against a declaration the author wrote. That puts it in the same position ADR-107 gives
|
|
894
|
+
# a parameter type — authored intent inference cannot derive — and proposing the body's value for it is
|
|
895
|
+
# a category error rather than a false positive to tune.
|
|
896
|
+
#
|
|
897
|
+
# Mechanically the misreading came from the translator: `docs/type-specification/special-types.md`
|
|
898
|
+
# § `void` records that the engine maps RBS `void` to `top`, `Type::Top` accepts everything, so
|
|
899
|
+
# {#tighter?} answered "yes" for every `void`-declared method whose body happens to return a typed
|
|
900
|
+
# value. Seven of the fifteen tighter-returns in Rigor's own `sig/` were this shape, and the ADR-107 G3
|
|
901
|
+
# provenance gate inherited the misclassification with them.
|
|
902
|
+
#
|
|
903
|
+
# ANY overload declaring `void` is enough. One proposal is rendered for the whole method, so an overload
|
|
904
|
+
# set that mixes `void` with a value return still has an author saying "not part of the contract" about
|
|
905
|
+
# the return sig-gen would rewrite.
|
|
906
|
+
def declares_void?(method_def)
|
|
907
|
+
method_def.method_types.any? { |mt| mt.type.return_type.is_a?(RBS::Types::Bases::Void) }
|
|
908
|
+
end
|
|
909
|
+
|
|
854
910
|
def build_declared_return(method_def)
|
|
855
911
|
translated = method_def.method_types.filter_map { |mt| translate_method_type_return(mt) }
|
|
856
912
|
return nil if translated.empty?
|
|
@@ -933,6 +989,48 @@ module Rigor
|
|
|
933
989
|
inferred.is_a?(Type::Tuple) || inferred.is_a?(Type::HashShape)
|
|
934
990
|
end
|
|
935
991
|
|
|
992
|
+
# The two reasons a `Type::Constant` the body proves is not the method's contract. Both say the same
|
|
993
|
+
# thing from opposite ends: the precision is real about this body and says nothing about the promise
|
|
994
|
+
# the method makes to its callers.
|
|
995
|
+
def literal_decline?(inferred, def_node)
|
|
996
|
+
computed_literal_tightening?(inferred, def_node) || pins_literal_over_declaration?(inferred)
|
|
997
|
+
end
|
|
998
|
+
|
|
999
|
+
# Issue #837 — a proposal that erases to an RBS LITERAL type never tightens an existing declaration.
|
|
1000
|
+
#
|
|
1001
|
+
# `Type::Top#describe` really does return `"top"`, but `describe` is the surface every `Rigor::Type::*`
|
|
1002
|
+
# class implements and every one of them declares `String`. The declared nominal is the author's
|
|
1003
|
+
# abstraction over the body, and the literal is the implementation detail that abstraction deliberately
|
|
1004
|
+
# hides — the same reading #836 gave a declared `void`. ADR-107 § Decision puts both on the intent
|
|
1005
|
+
# side: no synthesis produces an abstraction, because a type built from a body is always the type of
|
|
1006
|
+
# the body's last expression, so the choice to be wider than the body only ever exists in a declaration
|
|
1007
|
+
# someone wrote.
|
|
1008
|
+
#
|
|
1009
|
+
# The generator already answered this way whenever the declaration happened to be a UNION.
|
|
1010
|
+
# `Configuration.discover` declares `String?` against a body proving `".rigor.dist.yml" |
|
|
1011
|
+
# ".rigor.yml" | nil` and {#loses_declared_union_member?} refuses it, because no literal covers the
|
|
1012
|
+
# declared `String`. Whether the author wrote `String` or `String?` is not a decision about literals,
|
|
1013
|
+
# so the two shapes now answer alike.
|
|
1014
|
+
#
|
|
1015
|
+
# Scoped by the ERASURE, not by the carrier. `Type::Constant` also carries values RBS has no literal
|
|
1016
|
+
# spelling for (`Float`, `Regexp`, `Set`, `Pathname`, `Date`, …) and those erase to the class name, so
|
|
1017
|
+
# `def pi: () -> Numeric` against a body of `3.14` still proposes the ordinary nominal `Float`. A union
|
|
1018
|
+
# is refused when ANY member is a literal: a mixed `("a" | Float)` pins `"a"` just as a bare one does.
|
|
1019
|
+
# A literal nested inside a shape carrier (`[1, 2]`, a `HashShape` value) is a different question,
|
|
1020
|
+
# already answered for the collection declarations that matter by {#narrows_collection_to_shape?}.
|
|
1021
|
+
def pins_literal_over_declaration?(inferred)
|
|
1022
|
+
members = inferred.is_a?(Type::Union) ? inferred.members : [inferred]
|
|
1023
|
+
members.any? { |member| rbs_literal?(member) }
|
|
1024
|
+
end
|
|
1025
|
+
|
|
1026
|
+
# `Type::Constant#erase_to_rbs` spells the values RBS writes as literal types (`true` / `false` /
|
|
1027
|
+
# `nil`, an Integer, a Symbol, a String) as that literal and every other carrier as its value's class
|
|
1028
|
+
# name. Asking which of the two branches it took keeps the list of literal-spellable classes from
|
|
1029
|
+
# forking a second copy into this file.
|
|
1030
|
+
def rbs_literal?(type)
|
|
1031
|
+
type.is_a?(Type::Constant) && type.erase_to_rbs != type.value.class.name
|
|
1032
|
+
end
|
|
1033
|
+
|
|
936
1034
|
# Heuristic added after the third-round self-dogfood: `FallbackTracer#size` body is `@events.size`, where
|
|
937
1035
|
# `@events` is initialised to `[]` and never assigned again at the class-ivar pre-pass level. The
|
|
938
1036
|
# `Type::Tuple[]` (size 0) folds `.size` to `Constant<0>` — the carrier knows the empty-tuple cardinality
|
|
@@ -940,6 +1038,11 @@ module Rigor
|
|
|
940
1038
|
# signal is "the body's last expression is NOT a directly-authored literal but the inferred type IS a
|
|
941
1039
|
# Constant"; in that case the precision came from inference over an internal computation, not the
|
|
942
1040
|
# author's contract, so refuse to tighten.
|
|
1041
|
+
#
|
|
1042
|
+
# Since #837 the literal-ERASING half of this is refused whichever expression produced it. What stays
|
|
1043
|
+
# this guard's own is the `Constant` that erases to a class name: `def average = @total / 2.0` folds to
|
|
1044
|
+
# `Constant<2.5>` and would propose the perfectly ordinary `Float`, which is still the fold's answer
|
|
1045
|
+
# about one body rather than the method's contract.
|
|
943
1046
|
def computed_literal_tightening?(inferred, def_node)
|
|
944
1047
|
return false unless inferred.is_a?(Type::Constant)
|
|
945
1048
|
|
|
@@ -991,8 +1094,8 @@ module Rigor
|
|
|
991
1094
|
end
|
|
992
1095
|
|
|
993
1096
|
def render_rbs_line(def_node, inferred, class_name, kind)
|
|
994
|
-
|
|
995
|
-
head =
|
|
1097
|
+
params = def_node.parameters
|
|
1098
|
+
head = "(#{render_param_list(params, class_name, def_node.name)})#{block_signature_suffix(params)}"
|
|
996
1099
|
prefix = method_def_prefix(class_name, def_node.name, kind)
|
|
997
1100
|
"#{prefix}#{def_node.name}: #{head} -> #{paren_wrap_union(elaborated_rbs(inferred))}"
|
|
998
1101
|
end
|
|
@@ -1028,30 +1131,6 @@ module Rigor
|
|
|
1028
1131
|
false
|
|
1029
1132
|
end
|
|
1030
1133
|
|
|
1031
|
-
def required_arity(def_node)
|
|
1032
|
-
params = def_node.parameters
|
|
1033
|
-
params.is_a?(Prism::ParametersNode) ? params.requireds.size : 0
|
|
1034
|
-
end
|
|
1035
|
-
|
|
1036
|
-
# Per ADR-5 clause 2 the default is `untyped` for every position. Observed-policy callers
|
|
1037
|
-
# (`--params=observed`) pass an `observations:` map at construction time; the generator unions
|
|
1038
|
-
# per-position arg types whose tuple arity matches the def's required-positional count. Observations from
|
|
1039
|
-
# arities other than the def's count are discarded — they describe a different overload the MVP does not
|
|
1040
|
-
# emit.
|
|
1041
|
-
def render_param_list(class_name, method_name, arity)
|
|
1042
|
-
tuples = matching_observations(class_name, method_name, arity)
|
|
1043
|
-
return Array.new(arity, "untyped").join(", ") if tuples.empty?
|
|
1044
|
-
|
|
1045
|
-
Array.new(arity) { |i| union_erase(tuples.map { |obs| obs.positional[i] }) }.join(", ")
|
|
1046
|
-
end
|
|
1047
|
-
|
|
1048
|
-
def matching_observations(class_name, method_name, arity)
|
|
1049
|
-
return [] if @observations.empty?
|
|
1050
|
-
|
|
1051
|
-
list = @observations[[class_name, method_name]] || []
|
|
1052
|
-
list.select { |obs| obs.positional.size == arity }
|
|
1053
|
-
end
|
|
1054
|
-
|
|
1055
1134
|
def union_erase(types)
|
|
1056
1135
|
return "untyped" if types.empty?
|
|
1057
1136
|
return elaborated_rbs(types.first) if types.size == 1
|
|
@@ -1096,9 +1175,9 @@ module Rigor
|
|
|
1096
1175
|
|
|
1097
1176
|
case node
|
|
1098
1177
|
when Prism::ClassNode, Prism::ModuleNode
|
|
1099
|
-
|
|
1100
|
-
if
|
|
1101
|
-
walk_attr_calls(node.body,
|
|
1178
|
+
child_prefix = Source::ConstantPath.declaration_prefix(prefix, node.constant_path)
|
|
1179
|
+
if child_prefix
|
|
1180
|
+
walk_attr_calls(node.body, child_prefix, false, ctx) if node.body
|
|
1102
1181
|
return
|
|
1103
1182
|
end
|
|
1104
1183
|
when Prism::SingletonClassNode
|
|
@@ -1180,9 +1259,9 @@ module Rigor
|
|
|
1180
1259
|
|
|
1181
1260
|
case node
|
|
1182
1261
|
when Prism::ClassNode, Prism::ModuleNode
|
|
1183
|
-
|
|
1184
|
-
if
|
|
1185
|
-
collect_init_ivar_obs(node.body,
|
|
1262
|
+
child_prefix = Source::ConstantPath.declaration_prefix(prefix, node.constant_path)
|
|
1263
|
+
if child_prefix
|
|
1264
|
+
collect_init_ivar_obs(node.body, child_prefix, result) if node.body
|
|
1186
1265
|
return
|
|
1187
1266
|
end
|
|
1188
1267
|
when Prism::DefNode
|
|
@@ -21,20 +21,19 @@ module Rigor
|
|
|
21
21
|
# in multiple files for additive member contributions, but the writer only needs one canonical target per
|
|
22
22
|
# class.
|
|
23
23
|
class LayoutIndex
|
|
24
|
-
# @param signature_paths
|
|
24
|
+
# @param signature_paths —
|
|
25
25
|
# the `.rigor.yml`-configured signature directories.
|
|
26
26
|
# When `nil` or empty, falls back to `<project_root>/sig`
|
|
27
27
|
# if it exists (matching `Environment.for_project`'s
|
|
28
28
|
# auto-detection convention).
|
|
29
|
-
# @param project_root [String, Pathname]
|
|
30
29
|
def initialize(signature_paths:, project_root: Dir.pwd)
|
|
31
30
|
@signature_paths = resolve_paths(signature_paths, project_root)
|
|
32
31
|
@index = nil
|
|
33
32
|
end
|
|
34
33
|
|
|
35
|
-
# @param class_name
|
|
34
|
+
# @param class_name — fully-qualified Ruby class
|
|
36
35
|
# name (e.g. `"Rigor::Type::Top"`).
|
|
37
|
-
# @return
|
|
36
|
+
# @return absolute path of the sig file
|
|
38
37
|
# that already declares this class, or `nil` when no
|
|
39
38
|
# existing declaration is found.
|
|
40
39
|
def file_for(class_name)
|
|
@@ -29,11 +29,9 @@ module Rigor
|
|
|
29
29
|
|
|
30
30
|
module_function
|
|
31
31
|
|
|
32
|
-
# @param
|
|
33
|
-
# @param
|
|
34
|
-
# @param
|
|
35
|
-
# @param keyword_init [Boolean] the `Struct.new(..., keyword_init: true)` flag; ignored for `:data`.
|
|
36
|
-
# @return [Shape]
|
|
32
|
+
# @param members — ordered member names from the ADR-48 layout.
|
|
33
|
+
# @param member_types — erased RBS spellings; a member with no entry renders `untyped`.
|
|
34
|
+
# @param keyword_init — the `Struct.new(..., keyword_init: true)` flag; ignored for `:data`.
|
|
37
35
|
def of(kind:, members:, member_types: {}, keyword_init: false)
|
|
38
36
|
types = members.to_h { |member| [member, member_types[member] || "untyped"] }
|
|
39
37
|
accessors = kind == :struct ? struct_accessors(members, types) : readers(members, types)
|
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
require "prism"
|
|
4
4
|
|
|
5
5
|
require_relative "../environment"
|
|
6
|
+
require_relative "../project_environment"
|
|
6
7
|
require_relative "../scope"
|
|
7
8
|
require_relative "../type"
|
|
9
|
+
require_relative "../source/constant_path"
|
|
8
10
|
require_relative "../source/literals"
|
|
9
11
|
require_relative "../source/node_children"
|
|
10
12
|
require_relative "../inference/scope_indexer"
|
|
@@ -18,7 +20,7 @@ module Rigor
|
|
|
18
20
|
# for every `Prism::CallNode` whose receiver types as a `Type::Nominal`. The {Generator} consumes the
|
|
19
21
|
# resulting map to render `--params=observed` RBS:
|
|
20
22
|
#
|
|
21
|
-
# @return
|
|
23
|
+
# @return => Array<Array<Rigor::Type>>}]
|
|
22
24
|
#
|
|
23
25
|
# ADR-5 clause 2 compliance: the observed union is the MOST PERMISSIVE parameter contract the existing
|
|
24
26
|
# callers prove sufficient — by construction it accepts every type any caller has already passed. The
|
|
@@ -32,10 +34,9 @@ module Rigor
|
|
|
32
34
|
# the collector cannot attribute them to a specific class.
|
|
33
35
|
# - Zero-argument calls give no observation; methods are matched by `(class_name, method_name)` only.
|
|
34
36
|
class ObservationCollector # rubocop:disable Metrics/ClassLength
|
|
35
|
-
# @param
|
|
36
|
-
# @param paths [Array<String>] observe paths (files /
|
|
37
|
+
# @param paths — observe paths (files /
|
|
37
38
|
# directories).
|
|
38
|
-
# @param source_paths
|
|
39
|
+
# @param source_paths — source-tree paths
|
|
39
40
|
# (defaults to `configuration.paths`) pre-walked to
|
|
40
41
|
# register every project-defined class so that calls
|
|
41
42
|
# like `Foo.new.bar(x)` in the observe tree resolve
|
|
@@ -51,10 +52,11 @@ module Rigor
|
|
|
51
52
|
def collect
|
|
52
53
|
return {} if @paths.empty?
|
|
53
54
|
|
|
54
|
-
|
|
55
|
+
resolved = resolve_paths(@paths)
|
|
56
|
+
environment = build_environment(resolved)
|
|
55
57
|
discovered_classes = preindex_source_classes
|
|
56
58
|
observations = Hash.new { |h, k| h[k] = [] }
|
|
57
|
-
|
|
59
|
+
resolved.each do |path|
|
|
58
60
|
collect_from_file(path, environment, discovered_classes, observations)
|
|
59
61
|
end
|
|
60
62
|
observations.transform_values(&:freeze).freeze
|
|
@@ -62,11 +64,11 @@ module Rigor
|
|
|
62
64
|
|
|
63
65
|
private
|
|
64
66
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
)
|
|
67
|
+
# Issue #821 — same universe as the generator and as `rigor check`; see
|
|
68
|
+
# {Generator#build_environment}. An observation collected against a narrower environment types its
|
|
69
|
+
# argument differently from the run that will consume it.
|
|
70
|
+
def build_environment(source_files = [])
|
|
71
|
+
ProjectEnvironment.build(configuration: @configuration, source_files: source_files)
|
|
70
72
|
end
|
|
71
73
|
|
|
72
74
|
def resolve_paths(args)
|
|
@@ -118,11 +120,11 @@ module Rigor
|
|
|
118
120
|
return unless node.is_a?(Prism::Node)
|
|
119
121
|
|
|
120
122
|
if node.is_a?(Prism::ClassNode) || node.is_a?(Prism::ModuleNode)
|
|
121
|
-
|
|
122
|
-
if
|
|
123
|
-
full =
|
|
123
|
+
child_prefix = Source::ConstantPath.declaration_prefix(prefix, node.constant_path)
|
|
124
|
+
if child_prefix
|
|
125
|
+
full = child_prefix.join("::")
|
|
124
126
|
accumulator[full] = Type::Combinator.singleton_of(full)
|
|
125
|
-
walk_class_decls(node.body,
|
|
127
|
+
walk_class_decls(node.body, child_prefix, accumulator) if node.body
|
|
126
128
|
return
|
|
127
129
|
end
|
|
128
130
|
end
|
|
@@ -21,9 +21,8 @@ module Rigor
|
|
|
21
21
|
# When the source path is not under any configured source root (e.g. files supplied directly on the CLI
|
|
22
22
|
# from outside `lib/`), the full relative path is preserved under the sig root.
|
|
23
23
|
class PathMapper
|
|
24
|
-
# @param
|
|
25
|
-
# @param
|
|
26
|
-
# @param layout_index [LayoutIndex, nil] optional class
|
|
24
|
+
# @param project_root — (defaults to `Dir.pwd`)
|
|
25
|
+
# @param layout_index — optional class
|
|
27
26
|
# → existing sig file index; routes the target to the
|
|
28
27
|
# consolidated file when the class is already declared.
|
|
29
28
|
def initialize(configuration:, project_root: Dir.pwd, layout_index: nil)
|
|
@@ -32,12 +31,11 @@ module Rigor
|
|
|
32
31
|
@layout_index = layout_index
|
|
33
32
|
end
|
|
34
33
|
|
|
35
|
-
# @param
|
|
36
|
-
# @param class_name [String, nil] fully-qualified Ruby
|
|
34
|
+
# @param class_name — fully-qualified Ruby
|
|
37
35
|
# class name. When supplied and matched by the
|
|
38
36
|
# `LayoutIndex`, the consolidated sig file's path is
|
|
39
37
|
# returned instead of the 1:1 mirror.
|
|
40
|
-
# @return
|
|
38
|
+
# @return absolute path of the target `.rbs`
|
|
41
39
|
# file for the candidate.
|
|
42
40
|
def target_for(source_path, class_name: nil)
|
|
43
41
|
existing = existing_target_for(class_name)
|
|
@@ -23,16 +23,16 @@ module Rigor
|
|
|
23
23
|
|
|
24
24
|
module_function
|
|
25
25
|
|
|
26
|
-
# @param line
|
|
27
|
-
# @return
|
|
26
|
+
# @param line — a rendered RBS method line, e.g. `def self.parse: (String) -> Integer`.
|
|
27
|
+
# @return the parse error's first line, or nil when the line is valid.
|
|
28
28
|
def method_line_error(line)
|
|
29
29
|
return nil if line.nil?
|
|
30
30
|
|
|
31
31
|
source_error("class #{PROBE_CLASS}\n #{line}\nend\n")
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
# @param source
|
|
35
|
-
# @return
|
|
34
|
+
# @param source — a complete `.rbs` file's text.
|
|
35
|
+
# @return the parse error's first line, or nil when the file is valid.
|
|
36
36
|
def source_error(source)
|
|
37
37
|
::RBS::Parser.parse_signature(::RBS::Buffer.new(name: "(rigor sig-gen)", content: source))
|
|
38
38
|
nil
|