rigortype 0.2.7 → 0.2.8
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/docs/manual/04-diagnostics.md +7 -4
- data/docs/manual/06-baseline.md +5 -2
- data/docs/manual/15-type-protection-coverage.md +6 -4
- data/lib/rigor/analysis/baseline.rb +56 -96
- data/lib/rigor/analysis/buffer_binding.rb +13 -20
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +29 -48
- data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +35 -54
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +23 -37
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +16 -23
- data/lib/rigor/analysis/check_rules/rule_walk.rb +48 -71
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +19 -28
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +48 -67
- data/lib/rigor/analysis/check_rules.rb +174 -274
- data/lib/rigor/analysis/dependency_recorder.rb +26 -38
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +13 -25
- data/lib/rigor/analysis/dependency_source_inference/builder.rb +17 -30
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +15 -26
- data/lib/rigor/analysis/dependency_source_inference/index.rb +45 -76
- data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +23 -40
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +50 -83
- data/lib/rigor/analysis/dependency_source_inference.rb +6 -10
- data/lib/rigor/analysis/diagnostic.rb +48 -75
- data/lib/rigor/analysis/erb_template_detector.rb +13 -18
- data/lib/rigor/analysis/fact_store.rb +12 -22
- data/lib/rigor/analysis/incremental.rb +47 -63
- data/lib/rigor/analysis/incremental_session.rb +74 -100
- data/lib/rigor/analysis/project_scan.rb +12 -23
- data/lib/rigor/analysis/result.rb +3 -5
- data/lib/rigor/analysis/rule_catalog.rb +67 -95
- data/lib/rigor/analysis/run_stats.rb +38 -61
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +101 -160
- data/lib/rigor/analysis/runner/pool_coordinator.rb +121 -188
- data/lib/rigor/analysis/runner/project_pre_passes.rb +62 -96
- data/lib/rigor/analysis/runner/run_snapshots.rb +12 -18
- data/lib/rigor/analysis/runner.rb +220 -333
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +30 -43
- data/lib/rigor/analysis/worker_session.rb +64 -102
- data/lib/rigor/ast/type_node.rb +6 -8
- data/lib/rigor/ast.rb +6 -10
- data/lib/rigor/bleeding_edge.rb +27 -35
- data/lib/rigor/builtins/hkt_builtins.rb +7 -14
- data/lib/rigor/builtins/imported_refinements.rb +106 -149
- data/lib/rigor/builtins/predefined_constant_refinements.rb +51 -65
- data/lib/rigor/builtins/regex_refinement.rb +32 -43
- data/lib/rigor/builtins/static_return_refinements.rb +57 -81
- data/lib/rigor/cache/descriptor.rb +58 -94
- data/lib/rigor/cache/incremental_snapshot.rb +32 -48
- data/lib/rigor/cache/rbs_cache_producer.rb +10 -15
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +10 -16
- data/lib/rigor/cache/rbs_class_type_param_names.rb +10 -16
- data/lib/rigor/cache/rbs_constant_table.rb +8 -13
- data/lib/rigor/cache/rbs_descriptor.rb +8 -13
- data/lib/rigor/cache/rbs_environment.rb +11 -19
- data/lib/rigor/cache/rbs_environment_marshal_patch.rb +11 -19
- data/lib/rigor/cache/rbs_known_class_names.rb +8 -12
- data/lib/rigor/cache/store.rb +96 -151
- data/lib/rigor/cli/annotate_command.rb +51 -88
- data/lib/rigor/cli/baseline_command.rb +10 -17
- data/lib/rigor/cli/check_command.rb +121 -199
- data/lib/rigor/cli/check_runner_factory.rb +8 -14
- data/lib/rigor/cli/ci_detector.rb +9 -14
- data/lib/rigor/cli/command.rb +8 -14
- data/lib/rigor/cli/coverage_command.rb +19 -26
- data/lib/rigor/cli/coverage_mutation.rb +14 -19
- data/lib/rigor/cli/coverage_report.rb +0 -2
- data/lib/rigor/cli/coverage_scan.rb +7 -11
- data/lib/rigor/cli/diagnostic_formats.rb +43 -62
- data/lib/rigor/cli/diff_command.rb +10 -20
- data/lib/rigor/cli/docs_command.rb +26 -40
- data/lib/rigor/cli/doctor_command.rb +8 -9
- data/lib/rigor/cli/explain_command.rb +4 -7
- data/lib/rigor/cli/fused_protection_renderer.rb +4 -5
- data/lib/rigor/cli/fused_protection_report.rb +6 -8
- data/lib/rigor/cli/lsp_command.rb +11 -19
- data/lib/rigor/cli/mcp_command.rb +4 -6
- data/lib/rigor/cli/mutation_protection_renderer.rb +3 -4
- data/lib/rigor/cli/mutation_protection_report.rb +6 -9
- data/lib/rigor/cli/options.rb +11 -19
- data/lib/rigor/cli/plugin_command.rb +18 -30
- data/lib/rigor/cli/plugins_command.rb +29 -51
- data/lib/rigor/cli/plugins_renderer.rb +12 -20
- data/lib/rigor/cli/prism_colorizer.rb +13 -19
- data/lib/rigor/cli/protection_renderer.rb +5 -7
- data/lib/rigor/cli/protection_report.rb +27 -17
- data/lib/rigor/cli/renderable.rb +4 -6
- data/lib/rigor/cli/show_bleedingedge_command.rb +5 -8
- data/lib/rigor/cli/sig_gen_command.rb +14 -26
- data/lib/rigor/cli/skill_command.rb +30 -47
- data/lib/rigor/cli/skill_describe.rb +40 -64
- data/lib/rigor/cli/trace_command.rb +9 -16
- data/lib/rigor/cli/trace_renderer.rb +35 -51
- data/lib/rigor/cli/triage_command.rb +6 -10
- data/lib/rigor/cli/triage_renderer.rb +1 -2
- data/lib/rigor/cli/type_of_command.rb +14 -23
- data/lib/rigor/cli/type_of_renderer.rb +3 -5
- data/lib/rigor/cli/type_scan_command.rb +6 -10
- data/lib/rigor/cli/type_scan_renderer.rb +3 -5
- data/lib/rigor/cli/type_scan_report.rb +2 -3
- data/lib/rigor/cli/upgrade_command.rb +2 -3
- data/lib/rigor/cli.rb +16 -28
- data/lib/rigor/config_audit.rb +35 -44
- data/lib/rigor/configuration/dependencies.rb +41 -70
- data/lib/rigor/configuration/severity_profile.rb +28 -42
- data/lib/rigor/configuration.rb +150 -241
- data/lib/rigor/environment/bundle_sig_discovery.rb +74 -118
- data/lib/rigor/environment/class_registry.rb +19 -26
- data/lib/rigor/environment/constant_type_cache_holder.rb +14 -21
- data/lib/rigor/environment/hkt_registry_holder.rb +6 -12
- data/lib/rigor/environment/lockfile_resolver.rb +31 -47
- data/lib/rigor/environment/rbs_collection_discovery.rb +39 -63
- data/lib/rigor/environment/rbs_coverage_report.rb +24 -42
- data/lib/rigor/environment/rbs_loader.rb +420 -518
- data/lib/rigor/environment/reflection.rb +28 -53
- data/lib/rigor/environment/reporters.rb +13 -24
- data/lib/rigor/environment.rb +176 -291
- data/lib/rigor/flow_contribution/conflict.rb +16 -27
- data/lib/rigor/flow_contribution/element.rb +7 -12
- data/lib/rigor/flow_contribution/fact.rb +33 -57
- data/lib/rigor/flow_contribution/merge_result.rb +6 -9
- data/lib/rigor/flow_contribution/merger.rb +32 -47
- data/lib/rigor/flow_contribution.rb +37 -55
- data/lib/rigor/inference/acceptance.rb +133 -219
- data/lib/rigor/inference/block_parameter_binder.rb +52 -82
- data/lib/rigor/inference/body_fixpoint.rb +22 -30
- data/lib/rigor/inference/budget_trace.rb +43 -63
- data/lib/rigor/inference/builtins/array_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/comparable_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/complex_catalog.rb +13 -19
- data/lib/rigor/inference/builtins/date_catalog.rb +38 -67
- data/lib/rigor/inference/builtins/encoding_catalog.rb +22 -36
- data/lib/rigor/inference/builtins/enumerable_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/exception_catalog.rb +38 -57
- data/lib/rigor/inference/builtins/hash_catalog.rb +9 -14
- data/lib/rigor/inference/builtins/method_catalog.rb +29 -48
- data/lib/rigor/inference/builtins/numeric_catalog.rb +13 -18
- data/lib/rigor/inference/builtins/pathname_catalog.rb +8 -13
- data/lib/rigor/inference/builtins/proc_catalog.rb +38 -62
- data/lib/rigor/inference/builtins/random_catalog.rb +21 -32
- data/lib/rigor/inference/builtins/range_catalog.rb +12 -21
- data/lib/rigor/inference/builtins/rational_catalog.rb +9 -15
- data/lib/rigor/inference/builtins/re_catalog.rb +29 -48
- data/lib/rigor/inference/builtins/set_catalog.rb +18 -27
- data/lib/rigor/inference/builtins/string_catalog.rb +12 -19
- data/lib/rigor/inference/builtins/struct_catalog.rb +18 -30
- data/lib/rigor/inference/builtins/time_catalog.rb +28 -44
- data/lib/rigor/inference/closure_escape_analyzer.rb +44 -67
- data/lib/rigor/inference/coverage_scanner.rb +13 -18
- data/lib/rigor/inference/def_return_typer.rb +8 -14
- data/lib/rigor/inference/dynamic_origin.rb +23 -20
- data/lib/rigor/inference/expression_typer.rb +774 -1152
- data/lib/rigor/inference/fallback.rb +8 -12
- data/lib/rigor/inference/fallback_tracer.rb +4 -10
- data/lib/rigor/inference/flow_tracer.rb +25 -36
- data/lib/rigor/inference/hkt_body.rb +45 -68
- data/lib/rigor/inference/hkt_body_parser.rb +33 -52
- data/lib/rigor/inference/hkt_reducer.rb +38 -59
- data/lib/rigor/inference/hkt_registry.rb +50 -76
- data/lib/rigor/inference/indexed_narrowing.rb +55 -81
- data/lib/rigor/inference/macro_block_self_type.rb +21 -34
- data/lib/rigor/inference/method_dispatcher/array_to_h_folding.rb +11 -18
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +49 -83
- data/lib/rigor/inference/method_dispatcher/call_context.rb +16 -23
- data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +13 -22
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +307 -454
- data/lib/rigor/inference/method_dispatcher/data_folding.rb +24 -34
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +22 -37
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +52 -81
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +51 -78
- data/lib/rigor/inference/method_dispatcher/literal_string_folding.rb +60 -97
- data/lib/rigor/inference/method_dispatcher/math_folding.rb +23 -34
- data/lib/rigor/inference/method_dispatcher/member_shape_projection.rb +18 -26
- data/lib/rigor/inference/method_dispatcher/method_folding.rb +37 -71
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +114 -182
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +122 -193
- data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +15 -24
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +64 -93
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +31 -45
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +6 -9
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +356 -511
- data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +22 -32
- data/lib/rigor/inference/method_dispatcher/singleton_folding.rb +15 -21
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +66 -82
- data/lib/rigor/inference/method_dispatcher/time_folding.rb +10 -15
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +9 -13
- data/lib/rigor/inference/method_dispatcher.rb +378 -524
- data/lib/rigor/inference/method_parameter_binder.rb +81 -114
- data/lib/rigor/inference/multi_target_binder.rb +51 -68
- data/lib/rigor/inference/mutation_widening.rb +115 -158
- data/lib/rigor/inference/narrowing.rb +509 -727
- data/lib/rigor/inference/origin_lookup.rb +38 -0
- data/lib/rigor/inference/parameter_inference_collector.rb +100 -100
- data/lib/rigor/inference/precision_scanner.rb +26 -35
- data/lib/rigor/inference/project_patched_methods.rb +20 -32
- data/lib/rigor/inference/project_patched_scanner.rb +23 -37
- data/lib/rigor/inference/protection_scanner.rb +16 -18
- data/lib/rigor/inference/rbs_type_translator.rb +49 -66
- data/lib/rigor/inference/scope_indexer.rb +473 -817
- data/lib/rigor/inference/statement_evaluator.rb +706 -1111
- data/lib/rigor/inference/struct_fold_safety.rb +34 -48
- data/lib/rigor/inference/synthetic_method.rb +9 -16
- data/lib/rigor/inference/synthetic_method_index.rb +20 -35
- data/lib/rigor/inference/synthetic_method_scanner.rb +63 -103
- data/lib/rigor/language_server/buffer_resolution.rb +6 -9
- data/lib/rigor/language_server/buffer_table.rb +11 -18
- data/lib/rigor/language_server/completion_provider.rb +69 -116
- data/lib/rigor/language_server/debouncer.rb +16 -25
- data/lib/rigor/language_server/diagnostic_publisher.rb +26 -40
- data/lib/rigor/language_server/document_symbol_provider.rb +14 -19
- data/lib/rigor/language_server/folding_range_provider.rb +11 -19
- data/lib/rigor/language_server/hover_provider.rb +8 -11
- data/lib/rigor/language_server/hover_renderer.rb +56 -93
- data/lib/rigor/language_server/loop.rb +14 -19
- data/lib/rigor/language_server/project_context.rb +46 -74
- data/lib/rigor/language_server/selection_range_provider.rb +9 -12
- data/lib/rigor/language_server/server.rb +55 -83
- data/lib/rigor/language_server/signature_help_provider.rb +29 -46
- data/lib/rigor/language_server/synchronized_writer.rb +4 -7
- data/lib/rigor/language_server/uri.rb +8 -13
- data/lib/rigor/language_server.rb +4 -6
- data/lib/rigor/mcp/loop.rb +2 -3
- data/lib/rigor/mcp/server.rb +4 -7
- data/lib/rigor/mcp.rb +3 -6
- data/lib/rigor/plugin/access_denied_error.rb +5 -8
- data/lib/rigor/plugin/additional_initializer.rb +21 -31
- data/lib/rigor/plugin/base.rb +335 -518
- data/lib/rigor/plugin/blueprint.rb +14 -23
- data/lib/rigor/plugin/box.rb +18 -29
- data/lib/rigor/plugin/fact_store.rb +16 -26
- data/lib/rigor/plugin/inflector.rb +37 -53
- data/lib/rigor/plugin/io_boundary.rb +33 -56
- data/lib/rigor/plugin/isolation.rb +42 -55
- data/lib/rigor/plugin/load_error.rb +10 -15
- data/lib/rigor/plugin/loader.rb +30 -49
- data/lib/rigor/plugin/macro/block_as_method.rb +20 -32
- data/lib/rigor/plugin/macro/heredoc_template.rb +35 -58
- data/lib/rigor/plugin/macro/nested_class_template.rb +22 -36
- data/lib/rigor/plugin/macro/trait_registry.rb +34 -51
- data/lib/rigor/plugin/macro.rb +10 -15
- data/lib/rigor/plugin/manifest.rb +85 -144
- data/lib/rigor/plugin/node_context.rb +14 -22
- data/lib/rigor/plugin/node_rule_walk.rb +49 -74
- data/lib/rigor/plugin/protocol_contract.rb +25 -39
- data/lib/rigor/plugin/registry.rb +132 -205
- data/lib/rigor/plugin/services.rb +21 -33
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +11 -19
- data/lib/rigor/plugin/trust_policy.rb +24 -38
- data/lib/rigor/plugin/type_node_resolver.rb +15 -24
- data/lib/rigor/protection/diagnostic_oracle.rb +11 -13
- data/lib/rigor/protection/mutation_scanner.rb +27 -35
- data/lib/rigor/protection/mutator.rb +50 -70
- data/lib/rigor/protection/test_suite_oracle.rb +20 -27
- data/lib/rigor/rbs_extended/conformance_checker.rb +48 -68
- data/lib/rigor/rbs_extended/hkt_directives.rb +28 -54
- data/lib/rigor/rbs_extended/reporter.rb +24 -40
- data/lib/rigor/rbs_extended.rb +107 -197
- data/lib/rigor/reflection.rb +68 -86
- data/lib/rigor/scope/discovery_index.rb +14 -19
- data/lib/rigor/scope.rb +255 -310
- data/lib/rigor/sig_gen/classification.rb +6 -10
- data/lib/rigor/sig_gen/generator.rb +197 -323
- data/lib/rigor/sig_gen/layout_index.rb +12 -20
- data/lib/rigor/sig_gen/method_candidate.rb +12 -17
- data/lib/rigor/sig_gen/observation_collector.rb +38 -70
- data/lib/rigor/sig_gen/observed_call.rb +13 -23
- data/lib/rigor/sig_gen/path_mapper.rb +17 -29
- data/lib/rigor/sig_gen/renderer.rb +7 -13
- data/lib/rigor/sig_gen/type_elaborator.rb +15 -28
- data/lib/rigor/sig_gen/write_result.rb +8 -16
- data/lib/rigor/sig_gen/writer.rb +95 -174
- data/lib/rigor/sig_gen.rb +3 -6
- data/lib/rigor/signature_path_audit.rb +24 -30
- data/lib/rigor/source/constant_path.rb +10 -14
- data/lib/rigor/source/literals.rb +31 -45
- data/lib/rigor/source/node_locator.rb +9 -11
- data/lib/rigor/source/node_walker.rb +9 -13
- data/lib/rigor/source.rb +3 -4
- data/lib/rigor/testing.rb +16 -20
- data/lib/rigor/triage/catalogue.rb +38 -62
- data/lib/rigor/triage.rb +31 -52
- data/lib/rigor/trinary.rb +9 -13
- data/lib/rigor/type/acceptance_router.rb +4 -6
- data/lib/rigor/type/accepts_result.rb +10 -14
- data/lib/rigor/type/app.rb +19 -27
- data/lib/rigor/type/bot.rb +4 -6
- data/lib/rigor/type/bound_method.rb +10 -15
- data/lib/rigor/type/combinator.rb +165 -257
- data/lib/rigor/type/constant.rb +23 -34
- data/lib/rigor/type/data_class.rb +10 -15
- data/lib/rigor/type/data_instance.rb +14 -20
- data/lib/rigor/type/difference.rb +21 -32
- data/lib/rigor/type/dynamic.rb +3 -5
- data/lib/rigor/type/hash_shape.rb +32 -18
- data/lib/rigor/type/integer_range.rb +11 -16
- data/lib/rigor/type/intersection.rb +27 -42
- data/lib/rigor/type/nominal.rb +10 -15
- data/lib/rigor/type/plain_lattice.rb +9 -13
- data/lib/rigor/type/refined.rb +67 -114
- data/lib/rigor/type/singleton.rb +4 -6
- data/lib/rigor/type/struct_class.rb +11 -16
- data/lib/rigor/type/struct_instance.rb +15 -21
- data/lib/rigor/type/tuple.rb +14 -19
- data/lib/rigor/type/union.rb +30 -42
- data/lib/rigor/type_node/generic.rb +14 -26
- data/lib/rigor/type_node/identifier.rb +12 -19
- data/lib/rigor/type_node.rb +3 -12
- data/lib/rigor/value_semantics.rb +16 -21
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +18 -30
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +16 -29
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +12 -23
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +22 -39
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +26 -46
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +51 -87
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +10 -17
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +26 -39
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +118 -176
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +30 -51
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +57 -92
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +71 -108
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +13 -22
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +15 -25
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +8 -13
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +16 -24
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +30 -47
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +79 -129
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +36 -57
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +27 -41
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +16 -24
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +148 -235
- data/plugins/rigor-activerecord/lib/rigor-activerecord.rb +3 -5
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +8 -14
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +9 -15
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +4 -7
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +23 -41
- data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +3 -5
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +6 -10
- data/plugins/rigor-activesupport-core-ext/lib/rigor-activesupport-core-ext.rb +8 -11
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +30 -45
- data/plugins/rigor-devise/lib/rigor-devise.rb +3 -5
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +43 -69
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +26 -35
- data/plugins/rigor-dry-schema/lib/rigor-dry-schema.rb +3 -5
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +30 -47
- data/plugins/rigor-dry-struct/lib/rigor-dry-struct.rb +3 -5
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +67 -113
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +29 -46
- data/plugins/rigor-dry-types/lib/rigor-dry-types.rb +3 -5
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -20
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +14 -23
- data/plugins/rigor-dry-validation/lib/rigor-dry-validation.rb +2 -3
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +22 -37
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +28 -46
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +13 -17
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +30 -47
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +52 -80
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +21 -31
- data/plugins/rigor-graphql/lib/rigor-graphql.rb +3 -5
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +11 -17
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +20 -34
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +45 -75
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +22 -36
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +22 -41
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +17 -32
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +6 -12
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +4 -8
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +17 -32
- data/plugins/rigor-rails/lib/rigor-rails.rb +11 -18
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +58 -92
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +20 -34
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +20 -31
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +49 -82
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +55 -92
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +51 -90
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +17 -30
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +38 -70
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +42 -74
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +280 -497
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +54 -89
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +32 -54
- data/plugins/rigor-rbs-inline/lib/rigor-rbs-inline.rb +8 -13
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +9 -16
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +24 -39
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +13 -22
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +34 -56
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/scope_walker.rb +22 -42
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +43 -75
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +27 -39
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/http_status_codes.rb +14 -19
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +20 -34
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +28 -47
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +21 -37
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +13 -22
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +18 -31
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +6 -10
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +14 -29
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +23 -41
- data/plugins/rigor-sinatra/lib/rigor-sinatra.rb +3 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +23 -38
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +57 -96
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +22 -35
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +41 -69
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/method_signature.rb +6 -10
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +24 -41
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +29 -50
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +55 -88
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +159 -262
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +21 -29
- data/plugins/rigor-statesman/lib/rigor-statesman.rb +3 -5
- data/plugins/rigor-typescript-utility-types/lib/rigor/plugin/typescript_utility_types.rb +23 -37
- data/plugins/rigor-typescript-utility-types/lib/rigor-typescript-utility-types.rb +4 -6
- data/sig/rigor/scope.rbs +6 -0
- metadata +2 -1
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# `Date` and `DateTime` live in CRuby's bundled `date` gem, which
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
# keeps the wiring self-contained: a consumer that pulls in the
|
|
9
|
-
# constant-folding rule book gets the Date constants for free.
|
|
3
|
+
# `Date` and `DateTime` live in CRuby's bundled `date` gem, which is stdlib rather than core — so the
|
|
4
|
+
# constants are not visible until `date` is required. The dispatcher's `CATALOG_BY_CLASS` table
|
|
5
|
+
# references `Date` and `DateTime` at load time, so requiring the gem here (alongside the loader file
|
|
6
|
+
# that exports the catalog) keeps the wiring self-contained: a consumer that pulls in the constant-folding
|
|
7
|
+
# rule book gets the Date constants for free.
|
|
10
8
|
require "date"
|
|
11
9
|
|
|
12
10
|
require_relative "method_catalog"
|
|
@@ -14,78 +12,51 @@ require_relative "method_catalog"
|
|
|
14
12
|
module Rigor
|
|
15
13
|
module Inference
|
|
16
14
|
module Builtins
|
|
17
|
-
# `Date` / `DateTime` catalog. Singleton — load once, consult
|
|
18
|
-
# during dispatch.
|
|
15
|
+
# `Date` / `DateTime` catalog. Singleton — load once, consult during dispatch.
|
|
19
16
|
#
|
|
20
|
-
# `Date` and `DateTime` both come from CRuby's bundled `date`
|
|
21
|
-
#
|
|
22
|
-
# `
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
# `strftime` / `iso8601` etc. The Ruby-side prelude
|
|
26
|
-
# (`lib/date.rb`) only contributes `Date#infinite?` and the
|
|
27
|
-
# nested `Date::Infinity` class; the bulk of the surface is
|
|
28
|
-
# in C.
|
|
17
|
+
# `Date` and `DateTime` both come from CRuby's bundled `date` gem (`references/ruby/ext/date/date_core.c`).
|
|
18
|
+
# A single `Init_date_core` function registers them, so the catalog carries both classes — `Date`
|
|
19
|
+
# plus the `DateTime` subclass whose own Init block extends with `hour` / `min` / `strftime` /
|
|
20
|
+
# `iso8601` etc. The Ruby-side prelude (`lib/date.rb`) only contributes `Date#infinite?` and the
|
|
21
|
+
# nested `Date::Infinity` class; the bulk of the surface is in C.
|
|
29
22
|
#
|
|
30
|
-
# Date / DateTime receivers are not lifted to a `Constant`
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
# `Nominal[Date]`). The catalog wiring therefore mostly
|
|
34
|
-
# governs:
|
|
23
|
+
# Date / DateTime receivers are not lifted to a `Constant` carrier today (there is no Date literal
|
|
24
|
+
# node — the closest is `Date.today` / `Date.parse(...)`, which produce `Nominal[Date]`). The
|
|
25
|
+
# catalog wiring therefore mostly governs:
|
|
35
26
|
#
|
|
36
|
-
# 1. The Integer-typed reader surface (`#year`, `#month`,
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
# (`mutates_self`) from being missed by a future
|
|
42
|
-
# `Constant<Date>` carrier, plus a defensive
|
|
43
|
-
# `:initialize_copy` entry for symmetry with the other
|
|
44
|
-
# catalogs.
|
|
27
|
+
# 1. The Integer-typed reader surface (`#year`, `#month`, `#day`, `#wday`, `#hour`, `#min`, `#sec`) —
|
|
28
|
+
# RBS-declared `Integer` is preserved through dispatch.
|
|
29
|
+
# 2. The blocklist below, which keeps mutator-style methods that the C-body classifier already
|
|
30
|
+
# flagged (`mutates_self`) from being missed by a future `Constant<Date>` carrier, plus a
|
|
31
|
+
# defensive `:initialize_copy` entry for symmetry with the other catalogs.
|
|
45
32
|
#
|
|
46
|
-
# The non-bang `#next_day` / `#prev_day` / `#next_month` /
|
|
47
|
-
# `#
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
#
|
|
52
|
-
# `:mutates_self` by the C-body regex, so they fall out of
|
|
53
|
-
# `MethodCatalog#safe_for_folding?` without an explicit
|
|
54
|
-
# blocklist entry; the entries below are defense-in-depth
|
|
55
|
-
# against indirect mutators the regex might miss in a future
|
|
56
|
-
# CRuby bump.
|
|
33
|
+
# The non-bang `#next_day` / `#prev_day` / `#next_month` / `#prev_month` / `#next_year` /
|
|
34
|
+
# `#prev_year` / `#>>` / `#<<` selectors all RETURN brand-new `Date` objects rather than mutating the
|
|
35
|
+
# receiver — they intentionally stay catalog-eligible. The two real mutators (`#initialize_copy`,
|
|
36
|
+
# `#marshal_load`) are already classified `:mutates_self` by the C-body regex, so they fall out of
|
|
37
|
+
# `MethodCatalog#safe_for_folding?` without an explicit blocklist entry; the entries below are
|
|
38
|
+
# defense-in-depth against indirect mutators the regex might miss in a future CRuby bump.
|
|
57
39
|
DATE_CATALOG = MethodCatalog.for_topic(
|
|
58
40
|
"date",
|
|
59
41
|
mutating_selectors: {
|
|
60
42
|
"Date" => Set[
|
|
61
|
-
# `d_lite_initialize_copy` is already classed
|
|
62
|
-
#
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
# String / Array / Range / Set / Time and to keep the
|
|
66
|
-
# blocklist self-documenting.
|
|
43
|
+
# `d_lite_initialize_copy` is already classed `:mutates_self` by the regex (it calls
|
|
44
|
+
# `rb_check_frozen` and rewrites the receiver's internal `dat` slots). Listed here for
|
|
45
|
+
# symmetry with String / Array / Range / Set / Time and to keep the blocklist
|
|
46
|
+
# self-documenting.
|
|
67
47
|
:initialize_copy,
|
|
68
|
-
# `d_lite_fill` is a `#ifndef NDEBUG` debug method that
|
|
69
|
-
#
|
|
70
|
-
#
|
|
71
|
-
#
|
|
72
|
-
# internal `dat` struct but use no helper the C-body
|
|
73
|
-
# regex recognises, so the classifier mis-flags it
|
|
74
|
-
# `:leaf`. Blocked so a future `Constant<Date>` carrier
|
|
75
|
-
# never folds it.
|
|
48
|
+
# `d_lite_fill` is a `#ifndef NDEBUG` debug method that warms the receiver's cached `simple` /
|
|
49
|
+
# `complex` fields via the `get_s_*` / `get_c_*` macros. The macros perform in-place writes on
|
|
50
|
+
# the receiver's internal `dat` struct but use no helper the C-body regex recognises, so the
|
|
51
|
+
# classifier mis-flags it `:leaf`. Blocked so a future `Constant<Date>` carrier never folds it.
|
|
76
52
|
:fill
|
|
77
53
|
],
|
|
78
54
|
"DateTime" => Set[
|
|
79
|
-
# `DateTime` inherits the bulk of its surface from
|
|
80
|
-
# `
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
# the
|
|
84
|
-
# Date side so that the inherited
|
|
85
|
-
# `Date#initialize_copy` (registered against
|
|
86
|
-
# `cDateTime` through subclassing) cannot fold through
|
|
87
|
-
# the catalog if a future `Constant<DateTime>` carrier
|
|
88
|
-
# ever lands.
|
|
55
|
+
# `DateTime` inherits the bulk of its surface from `Date`. The dedicated DateTime-side methods
|
|
56
|
+
# are all readers (`hour`, `min`, …) plus formatting converters (`strftime`, `iso8601`, …);
|
|
57
|
+
# none mutate the receiver. The single defensive entry mirrors the Date side so that the
|
|
58
|
+
# inherited `Date#initialize_copy` (registered against `cDateTime` through subclassing) cannot
|
|
59
|
+
# fold through the catalog if a future `Constant<DateTime>` carrier ever lands.
|
|
89
60
|
:initialize_copy
|
|
90
61
|
]
|
|
91
62
|
}
|
|
@@ -5,55 +5,41 @@ require_relative "method_catalog"
|
|
|
5
5
|
module Rigor
|
|
6
6
|
module Inference
|
|
7
7
|
module Builtins
|
|
8
|
-
# `Encoding` catalog. Singleton — load once, consult during
|
|
9
|
-
# dispatch.
|
|
8
|
+
# `Encoding` catalog. Singleton — load once, consult during dispatch.
|
|
10
9
|
#
|
|
11
|
-
# Encoding instances are deep-frozen value objects: once
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
# methods are pure. The C-body classifier therefore lands
|
|
15
|
-
# every instance method as `:leaf` correctly.
|
|
10
|
+
# Encoding instances are deep-frozen value objects: once registered, their `name` / `dummy?` /
|
|
11
|
+
# `ascii_compatible?` slots never change and the C bodies for the per-instance methods are pure.
|
|
12
|
+
# The C-body classifier therefore lands every instance method as `:leaf` correctly.
|
|
16
13
|
#
|
|
17
|
-
# The blocklist focuses on the *singleton* surface where the
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
# against the analyzer process's registry — what UTF-8's
|
|
23
|
-
# alias list is in the analyzer is not necessarily what it
|
|
24
|
-
# is in the analysed program.
|
|
14
|
+
# The blocklist focuses on the *singleton* surface where the hidden state is the process-wide
|
|
15
|
+
# encoding registry. Every method classified `:leaf` on the singleton actually reads (or, for the
|
|
16
|
+
# setters, writes) a global, so a hypothetical `Constant<Encoding>`-class receiver MUST NOT fold
|
|
17
|
+
# them against the analyzer process's registry — what UTF-8's alias list is in the analyzer is not
|
|
18
|
+
# necessarily what it is in the analysed program.
|
|
25
19
|
ENCODING_CATALOG = MethodCatalog.for_topic(
|
|
26
20
|
"encoding",
|
|
27
21
|
mutating_selectors: {
|
|
28
22
|
"Encoding" => Set[
|
|
29
|
-
# Defence-in-depth: mirrors range_catalog.rb /
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
# convention keeps the door closed against future
|
|
34
|
-
# CRuby changes that would leak a copy-mutator.
|
|
23
|
+
# Defence-in-depth: mirrors range_catalog.rb / complex_catalog.rb. Encoding does not currently
|
|
24
|
+
# expose a public `initialize_copy` (Encoding objects are deep-frozen and #dup is a no-op),
|
|
25
|
+
# but the convention keeps the door closed against future CRuby changes that would leak a
|
|
26
|
+
# copy-mutator.
|
|
35
27
|
:initialize_copy,
|
|
36
28
|
:hash,
|
|
37
29
|
:eql?,
|
|
38
|
-
# `Encoding.find(name)` walks the global encoding
|
|
39
|
-
# registry
|
|
40
|
-
#
|
|
41
|
-
# process-wide `default_external=` calls), so a
|
|
42
|
-
# constant-fold would lock in the analyzer's view.
|
|
30
|
+
# `Encoding.find(name)` walks the global encoding registry. Pure with respect to its argument
|
|
31
|
+
# but the registry itself can drift (load-order, locale, process-wide `default_external=`
|
|
32
|
+
# calls), so a constant-fold would lock in the analyzer's view.
|
|
43
33
|
:find,
|
|
44
|
-
# `Encoding.list` / `Encoding.aliases` /
|
|
45
|
-
#
|
|
46
|
-
# registry.
|
|
47
|
-
# are not guaranteed to match the analysed program's
|
|
48
|
-
# registry.
|
|
34
|
+
# `Encoding.list` / `Encoding.aliases` / `Encoding.name_list` enumerate the same global
|
|
35
|
+
# registry. Same reasoning as `find` — the values are not guaranteed to match the analysed
|
|
36
|
+
# program's registry.
|
|
49
37
|
:list,
|
|
50
38
|
:aliases,
|
|
51
39
|
:name_list,
|
|
52
|
-
# Global-default mutators. `MethodCatalog#blocked?`
|
|
53
|
-
#
|
|
54
|
-
#
|
|
55
|
-
# default-encoding slot read by `default_external` /
|
|
56
|
-
# `default_internal`.
|
|
40
|
+
# Global-default mutators. `MethodCatalog#blocked?` only auto-blocks `!`-suffixed selectors,
|
|
41
|
+
# so we MUST list these explicitly: each writes the process-wide default-encoding slot read by
|
|
42
|
+
# `default_external` / `default_internal`.
|
|
57
43
|
:default_external=,
|
|
58
44
|
:default_internal=
|
|
59
45
|
]
|
|
@@ -7,12 +7,10 @@ module Rigor
|
|
|
7
7
|
module Builtins
|
|
8
8
|
# `Enumerable` module catalog. Singleton — load once.
|
|
9
9
|
#
|
|
10
|
-
# `Enumerable` is a Ruby module, not a class, so the
|
|
11
|
-
#
|
|
12
|
-
# `MethodDispatcher::ConstantFolding
|
|
13
|
-
# (
|
|
14
|
-
# The data is wired into `MODULE_CATALOGS` in
|
|
15
|
-
# `MethodDispatcher::ConstantFolding` (ancestor-chain lookup).
|
|
10
|
+
# `Enumerable` is a Ruby module, not a class, so the catalog is NOT routed through
|
|
11
|
+
# `MethodDispatcher::ConstantFolding::CATALOG_BY_CLASS` (which dispatches on the receiver's concrete
|
|
12
|
+
# class). The data is wired into `MODULE_CATALOGS` in `MethodDispatcher::ConstantFolding`
|
|
13
|
+
# (ancestor-chain lookup).
|
|
16
14
|
ENUMERABLE_CATALOG = MethodCatalog.for_topic(
|
|
17
15
|
"enumerable",
|
|
18
16
|
mutating_selectors: {
|
|
@@ -5,80 +5,61 @@ require_relative "method_catalog"
|
|
|
5
5
|
module Rigor
|
|
6
6
|
module Inference
|
|
7
7
|
module Builtins
|
|
8
|
-
# `Exception` catalog. Singleton — load once, consult during
|
|
9
|
-
# dispatch.
|
|
8
|
+
# `Exception` catalog. Singleton — load once, consult during dispatch.
|
|
10
9
|
#
|
|
11
|
-
# Exception is the base of every Ruby error class (RuntimeError,
|
|
12
|
-
#
|
|
13
|
-
# `
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
# entries; subclass-specific methods (`KeyError#receiver`,
|
|
19
|
-
# `NameError#name`, …) intentionally miss the lookup until a
|
|
20
|
-
# later slice routes per-subclass class_names.
|
|
10
|
+
# Exception is the base of every Ruby error class (RuntimeError, StandardError, KeyError, …). The
|
|
11
|
+
# Init_Exception block in `references/ruby/error.c` registers the entire hierarchy in one pass, so
|
|
12
|
+
# the YAML carries 27 classes — but only the base `Exception` row is wired into `CATALOG_BY_CLASS`
|
|
13
|
+
# for v0.0.5. A `RuntimeError` receiver hits the Exception arm via `is_a?(Exception)` and the
|
|
14
|
+
# catalog answers with the base-class entries; subclass-specific methods (`KeyError#receiver`,
|
|
15
|
+
# `NameError#name`, …) intentionally miss the lookup until a later slice routes per-subclass
|
|
16
|
+
# class_names.
|
|
21
17
|
#
|
|
22
|
-
# The catalog tier here is *defence in depth* — every base
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
# missed an indirect side effect. The remaining `:leaf` method
|
|
28
|
-
# that DOES fold is `#cause`, a pure accessor.
|
|
18
|
+
# The catalog tier here is *defence in depth* — every base method that could plausibly fold has
|
|
19
|
+
# been weighed against the robustness principle (strict on returns) and either left `:dispatch` /
|
|
20
|
+
# `:mutates_self` (in which case the catalog already declines) or blocklisted because the static
|
|
21
|
+
# classifier missed an indirect side effect. The remaining `:leaf` method that DOES fold is
|
|
22
|
+
# `#cause`, a pure accessor.
|
|
29
23
|
EXCEPTION_CATALOG = MethodCatalog.for_topic(
|
|
30
24
|
"exception",
|
|
31
25
|
mutating_selectors: {
|
|
32
26
|
"Exception" => Set[
|
|
33
|
-
# `exc_initialize` writes `mesg` / `backtrace` ivars on
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
# its regex. Blocklisted so a hypothetical future
|
|
37
|
-
# `Constant<Exception>` carrier cannot fold an aliasing
|
|
27
|
+
# `exc_initialize` writes `mesg` / `backtrace` ivars on self via `rb_ivar_set` — the C-body
|
|
28
|
+
# classifier missed the indirect mutator because the helpers are not in its regex.
|
|
29
|
+
# Blocklisted so a hypothetical future `Constant<Exception>` carrier cannot fold an aliasing
|
|
38
30
|
# constructor through the catalog.
|
|
39
31
|
:initialize,
|
|
40
|
-
# `exc_exception` either returns self (no-arg) or calls
|
|
41
|
-
# `
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
# blocklist; the cost is one folded no-arg call.
|
|
32
|
+
# `exc_exception` either returns self (no-arg) or calls `rb_obj_clone` +
|
|
33
|
+
# `exc_initialize_internal` on the clone — the clone branch mutates fresh state through the
|
|
34
|
+
# same indirect helpers as `:initialize`. Conservative blocklist; the cost is one folded
|
|
35
|
+
# no-arg call.
|
|
45
36
|
:exception,
|
|
46
|
-
# `exc_detailed_message` formats with platform / locale
|
|
47
|
-
#
|
|
48
|
-
# the
|
|
49
|
-
# would freeze a value that depends on the calling
|
|
50
|
-
# process's stderr state.
|
|
37
|
+
# `exc_detailed_message` formats with platform / locale data (highlight markers depend on
|
|
38
|
+
# `$stderr.tty?` via the keyword arg default and `rb_io_tty_p`). Folding would freeze a value
|
|
39
|
+
# that depends on the calling process's stderr state.
|
|
51
40
|
:detailed_message,
|
|
52
|
-
# `exc_backtrace` reads the captured frame list, which
|
|
53
|
-
#
|
|
54
|
-
# the static fold tier cannot reproduce.
|
|
41
|
+
# `exc_backtrace` reads the captured frame list, which depends on where the exception was
|
|
42
|
+
# raised — context the static fold tier cannot reproduce.
|
|
55
43
|
:backtrace,
|
|
56
|
-
# Same rationale as `:backtrace`; `Thread::Backtrace::Location`
|
|
57
|
-
# objects are runtime artefacts.
|
|
44
|
+
# Same rationale as `:backtrace`; `Thread::Backtrace::Location` objects are runtime artefacts.
|
|
58
45
|
:backtrace_locations,
|
|
59
|
-
# `exc_set_backtrace` mutates the @backtrace ivar via
|
|
60
|
-
#
|
|
61
|
-
# missed.
|
|
46
|
+
# `exc_set_backtrace` mutates the @backtrace ivar via `rb_ivar_set` — another indirect
|
|
47
|
+
# mutator the classifier missed.
|
|
62
48
|
:set_backtrace,
|
|
63
|
-
# `initialize_copy` is blocklisted by convention so a
|
|
64
|
-
#
|
|
65
|
-
# cannot fold an aliasing copy through the catalog.
|
|
49
|
+
# `initialize_copy` is blocklisted by convention so a hypothetical future
|
|
50
|
+
# `Constant<Exception>` carrier cannot fold an aliasing copy through the catalog.
|
|
66
51
|
:initialize_copy,
|
|
67
|
-
# Defensive entries for the universal mutation surface.
|
|
68
|
-
#
|
|
69
|
-
#
|
|
70
|
-
# blocking both keeps the constant-fold tier honest.
|
|
52
|
+
# Defensive entries for the universal mutation surface. Object-identity hashing on a constant
|
|
53
|
+
# carrier is fine, but `eql?` on Exception delegates to `==` (dispatch); blocking both keeps
|
|
54
|
+
# the constant-fold tier honest.
|
|
71
55
|
:hash,
|
|
72
56
|
:eql?
|
|
73
57
|
],
|
|
74
|
-
# `Exception.to_tty?` (singleton) calls
|
|
75
|
-
#
|
|
76
|
-
#
|
|
77
|
-
#
|
|
78
|
-
#
|
|
79
|
-
# `CATALOG_BY_CLASS`, so this row is documentation-grade —
|
|
80
|
-
# it records the soundness rationale for any future slice
|
|
81
|
-
# that wires the singleton path through the catalog.
|
|
58
|
+
# `Exception.to_tty?` (singleton) calls `rb_io_tty_p($stderr)`; its return depends on the
|
|
59
|
+
# process's stderr state at runtime, never on compile-time arguments. The catalog tier today
|
|
60
|
+
# only consults `mutating_selectors` for instance-receiver dispatches via `CATALOG_BY_CLASS`, so
|
|
61
|
+
# this row is documentation-grade — it records the soundness rationale for any future slice that
|
|
62
|
+
# wires the singleton path through the catalog.
|
|
82
63
|
"Exception.singleton" => Set[
|
|
83
64
|
:to_tty?
|
|
84
65
|
]
|
|
@@ -7,27 +7,22 @@ module Rigor
|
|
|
7
7
|
module Builtins
|
|
8
8
|
# `Hash` catalog. Singleton — load once, consult during dispatch.
|
|
9
9
|
#
|
|
10
|
-
# Hash mirrors Array's mutation pattern: nearly every iteration
|
|
11
|
-
#
|
|
12
|
-
# callback
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
# captures every false-positive `:leaf` we have spotted in the
|
|
16
|
-
# generated YAML — bias toward conservatism so a missed fold is
|
|
17
|
-
# acceptable but a folded mutator/yielder is not.
|
|
10
|
+
# Hash mirrors Array's mutation pattern: nearly every iteration method yields through
|
|
11
|
+
# `rb_hash_foreach` plus a per-pair static callback (`each_value_i`, `keep_if_i`, …), and the C-body
|
|
12
|
+
# classifier does not follow into the callback so it lands as `:leaf` despite being block-dependent.
|
|
13
|
+
# The blocklist below captures every false-positive `:leaf` we have spotted in the generated YAML —
|
|
14
|
+
# bias toward conservatism so a missed fold is acceptable but a folded mutator/yielder is not.
|
|
18
15
|
HASH_CATALOG = MethodCatalog.for_topic(
|
|
19
16
|
"hash",
|
|
20
17
|
mutating_selectors: {
|
|
21
18
|
"Hash" => Set[
|
|
22
|
-
# Block-dependent iteration — yields via `rb_hash_foreach`
|
|
23
|
-
#
|
|
24
|
-
# not follow:
|
|
19
|
+
# Block-dependent iteration — yields via `rb_hash_foreach` plus a per-pair callback that the
|
|
20
|
+
# regex classifier does not follow:
|
|
25
21
|
:each, :each_pair, :each_key, :each_value,
|
|
26
22
|
:select, :filter, :reject,
|
|
27
23
|
:transform_values,
|
|
28
|
-
# Block-dependent merge — `rb_hash_merge` delegates into
|
|
29
|
-
#
|
|
30
|
-
# is given:
|
|
24
|
+
# Block-dependent merge — `rb_hash_merge` delegates into `rb_hash_update`, which yields per
|
|
25
|
+
# conflict when a block is given:
|
|
31
26
|
:merge
|
|
32
27
|
]
|
|
33
28
|
}
|
|
@@ -5,57 +5,44 @@ require "yaml"
|
|
|
5
5
|
module Rigor
|
|
6
6
|
module Inference
|
|
7
7
|
module Builtins
|
|
8
|
-
# Generic loader for offline-generated catalogs under
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# classifier marked `:leaf` but that actually mutate the
|
|
13
|
-
# receiver (false positives the C-body heuristic does not
|
|
14
|
-
# catch).
|
|
8
|
+
# Generic loader for offline-generated catalogs under `data/builtins/ruby_core/<topic>.yml`. One
|
|
9
|
+
# instance per topic (numeric, string, array, …); each owns the path to its own YAML and the
|
|
10
|
+
# per-class blocklist of selectors the static classifier marked `:leaf` but that actually mutate the
|
|
11
|
+
# receiver (false positives the C-body heuristic does not catch).
|
|
15
12
|
#
|
|
16
|
-
# `safe_for_folding?(class_name, selector, kind:)` returns true
|
|
17
|
-
# when:
|
|
13
|
+
# `safe_for_folding?(class_name, selector, kind:)` returns true when:
|
|
18
14
|
# 1. The catalog has an entry for `(class_name, selector, kind)`,
|
|
19
|
-
# 2. The entry's `purity` is one of `leaf` / `trivial` /
|
|
20
|
-
# `leaf_when_numeric`,
|
|
15
|
+
# 2. The entry's `purity` is one of `leaf` / `trivial` / `leaf_when_numeric`,
|
|
21
16
|
# 3. The selector is NOT in the per-class mutation blocklist.
|
|
22
17
|
#
|
|
23
|
-
# Missing catalog files (e.g. in a bare gem install where data
|
|
24
|
-
#
|
|
25
|
-
# back to its hand-rolled allow lists.
|
|
18
|
+
# Missing catalog files (e.g. in a bare gem install where data was opted out) degrade to `false` so
|
|
19
|
+
# the dispatcher falls back to its hand-rolled allow lists.
|
|
26
20
|
class MethodCatalog
|
|
27
21
|
FOLDABLE_PURITIES = Set["leaf", "trivial", "leaf_when_numeric"].freeze
|
|
28
22
|
EMPTY_CATALOG = { "classes" => {} }.freeze
|
|
29
23
|
|
|
30
|
-
# Selectors that are classified `:leaf` by the C-body analysis
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
# never be folded into a `Constant`:
|
|
24
|
+
# Selectors that are classified `:leaf` by the C-body analysis (they read no global mutable state
|
|
25
|
+
# in the C sense) but whose result is NOT reproducible across Ruby processes, so they must never
|
|
26
|
+
# be folded into a `Constant`:
|
|
34
27
|
#
|
|
35
|
-
# - `hash` — every core `#hash` (`String`/`Symbol`/`Integer
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
# process's value into the type and the on-disk cache.
|
|
28
|
+
# - `hash` — every core `#hash` (`String`/`Symbol`/`Integer`/`Float`/…) is salted with a
|
|
29
|
+
# per-process SipHash seed, so `"x".hash` differs in every process. Folding bakes one process's
|
|
30
|
+
# value into the type and the on-disk cache.
|
|
39
31
|
# - `object_id` / `__id__` — identity-allocated per process.
|
|
40
32
|
#
|
|
41
|
-
# This is a UNIVERSAL block (across every catalogued class)
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
# class. The deterministic siblings (`inspect`, `to_s`) are
|
|
45
|
-
# unaffected.
|
|
33
|
+
# This is a UNIVERSAL block (across every catalogued class) because `hash` / `object_id` are
|
|
34
|
+
# `Object`-level and present on every receiver; a per-class blocklist would silently miss a class.
|
|
35
|
+
# The deterministic siblings (`inspect`, `to_s`) are unaffected.
|
|
46
36
|
NON_REPRODUCIBLE_SELECTORS = Set[:hash, :object_id, :__id__].freeze
|
|
47
37
|
|
|
48
|
-
# Shared root for the offline-generated catalogues. Resolving it
|
|
49
|
-
#
|
|
50
|
-
# instead of copying it into every per-topic loader.
|
|
38
|
+
# Shared root for the offline-generated catalogues. Resolving it here keeps the repo-relative
|
|
39
|
+
# `../../../../` hop in one place instead of copying it into every per-topic loader.
|
|
51
40
|
DATA_ROOT = File.expand_path("../../../../data/builtins/ruby_core", __dir__)
|
|
52
41
|
private_constant :DATA_ROOT
|
|
53
42
|
|
|
54
|
-
# Build a catalog for a named topic, resolving its YAML path
|
|
55
|
-
#
|
|
56
|
-
#
|
|
57
|
-
# an explicit `File.expand_path` so the data-root hop stays
|
|
58
|
-
# centralised.
|
|
43
|
+
# Build a catalog for a named topic, resolving its YAML path under {DATA_ROOT}. Equivalent to
|
|
44
|
+
# `new(path: …)` for the common case where the file is `<topic>.yml`; prefer this over passing an
|
|
45
|
+
# explicit `File.expand_path` so the data-root hop stays centralised.
|
|
59
46
|
def self.for_topic(topic, mutating_selectors: {})
|
|
60
47
|
new(path: File.join(DATA_ROOT, "#{topic}.yml"), mutating_selectors: mutating_selectors)
|
|
61
48
|
end
|
|
@@ -63,14 +50,10 @@ module Rigor
|
|
|
63
50
|
def initialize(path:, mutating_selectors: {})
|
|
64
51
|
@path = path
|
|
65
52
|
@mutating_selectors = mutating_selectors.transform_values(&:freeze).freeze
|
|
66
|
-
# ADR-15 Phase 4b.x — eager-load so the instance is
|
|
67
|
-
#
|
|
68
|
-
#
|
|
69
|
-
#
|
|
70
|
-
# worker Ractor consults the catalog, raising
|
|
71
|
-
# `FrozenError`. The YAML parse is a once-per-process
|
|
72
|
-
# cost and the catalogs are constructed at module
|
|
73
|
-
# load time anyway, so eager init is free in
|
|
53
|
+
# ADR-15 Phase 4b.x — eager-load so the instance is safe to `Ractor.make_shareable`. Lazy init
|
|
54
|
+
# via `@catalog ||= load_catalog` would write to a potentially-frozen instance the first time a
|
|
55
|
+
# worker Ractor consults the catalog, raising `FrozenError`. The YAML parse is a once-per-process
|
|
56
|
+
# cost and the catalogs are constructed at module load time anyway, so eager init is free in
|
|
74
57
|
# practice.
|
|
75
58
|
@catalog = load_catalog
|
|
76
59
|
end
|
|
@@ -117,11 +100,9 @@ module Rigor
|
|
|
117
100
|
end
|
|
118
101
|
|
|
119
102
|
def blocked?(class_name, selector)
|
|
120
|
-
# Bang-suffixed selectors are mutating by Ruby convention
|
|
121
|
-
#
|
|
122
|
-
#
|
|
123
|
-
# losing a fold opportunity is acceptable; folding a
|
|
124
|
-
# mutator is not.
|
|
103
|
+
# Bang-suffixed selectors are mutating by Ruby convention (`upcase!`, `concat`, etc. are listed
|
|
104
|
+
# explicitly below; this catches the rest). We bias toward false negatives: losing a fold
|
|
105
|
+
# opportunity is acceptable; folding a mutator is not.
|
|
125
106
|
selector_str = selector.to_s
|
|
126
107
|
return true if selector_str.end_with?("!")
|
|
127
108
|
|
|
@@ -5,26 +5,21 @@ require_relative "method_catalog"
|
|
|
5
5
|
module Rigor
|
|
6
6
|
module Inference
|
|
7
7
|
module Builtins
|
|
8
|
-
# `Numeric` family catalog (Integer, Float, Rational, Complex,
|
|
9
|
-
#
|
|
8
|
+
# `Numeric` family catalog (Integer, Float, Rational, Complex, Numeric). Singleton — load once,
|
|
9
|
+
# consult during dispatch.
|
|
10
10
|
#
|
|
11
|
-
# The catalog is produced offline by `tool/extract_builtin_catalog.rb`
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
# classification (`leaf` / `trivial` / `leaf_when_numeric` are
|
|
17
|
-
# foldable; everything else is not).
|
|
11
|
+
# The catalog is produced offline by `tool/extract_builtin_catalog.rb` from the CRuby reference
|
|
12
|
+
# checkout under `references/ruby` plus the RBS core signatures under `references/rbs`. The loader
|
|
13
|
+
# is the runtime bridge: callers ask "is `Integer#+` safe to invoke during constant folding?" and
|
|
14
|
+
# the answer comes straight from the offline classification (`leaf` / `trivial` / `leaf_when_numeric`
|
|
15
|
+
# are foldable; everything else is not).
|
|
18
16
|
#
|
|
19
|
-
# No mutation blocklist is needed. The numeric classes expose no
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
# `method_entry` / `load_catalog` copy of `MethodCatalog`; folding
|
|
26
|
-
# it onto the shared loader also picks up alias resolution (e.g.
|
|
27
|
-
# `Integer#magnitude` → `abs`, `Integer#inspect` → `to_s`), which the
|
|
17
|
+
# No mutation blocklist is needed. The numeric classes expose no foldable bang or indirect-mutator
|
|
18
|
+
# method that the static C classifier mis-attributes (every `:leaf` numeric method is a pure value
|
|
19
|
+
# computation), so the generic `MethodCatalog` loader — shared with the eighteen other per-class
|
|
20
|
+
# catalogs — covers it directly. This previously hand-rolled its own `safe_for_folding?` /
|
|
21
|
+
# `method_entry` / `load_catalog` copy of `MethodCatalog`; folding it onto the shared loader also
|
|
22
|
+
# picks up alias resolution (e.g. `Integer#magnitude` → `abs`, `Integer#inspect` → `to_s`), which the
|
|
28
23
|
# old bespoke loader silently dropped.
|
|
29
24
|
NUMERIC_CATALOG = MethodCatalog.for_topic("numeric")
|
|
30
25
|
end
|
|
@@ -5,24 +5,19 @@ require_relative "method_catalog"
|
|
|
5
5
|
module Rigor
|
|
6
6
|
module Inference
|
|
7
7
|
module Builtins
|
|
8
|
-
# `Pathname` catalog. Singleton — load once, consult during
|
|
9
|
-
# dispatch.
|
|
8
|
+
# `Pathname` catalog. Singleton — load once, consult during dispatch.
|
|
10
9
|
#
|
|
11
|
-
# TODO(blocklist curation): read
|
|
12
|
-
# `
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
# helper that triggered the false positive (see
|
|
17
|
-
# `string_catalog.rb`, `array_catalog.rb`, `time_catalog.rb`
|
|
18
|
-
# for the canonical shape).
|
|
10
|
+
# TODO(blocklist curation): read `data/builtins/ruby_core/pathname.yml` and add per-method blocklist
|
|
11
|
+
# entries for any `:leaf` classifications that are actually mutators or otherwise unsafe to fold.
|
|
12
|
+
# Each entry SHOULD carry a one-line comment naming the indirect mutator helper that triggered the
|
|
13
|
+
# false positive (see `string_catalog.rb`, `array_catalog.rb`, `time_catalog.rb` for the canonical
|
|
14
|
+
# shape).
|
|
19
15
|
PATHNAME_CATALOG = MethodCatalog.for_topic(
|
|
20
16
|
"pathname",
|
|
21
17
|
mutating_selectors: {
|
|
22
18
|
"Pathname" => Set[
|
|
23
|
-
# initialize_copy is blocklisted by convention so a
|
|
24
|
-
#
|
|
25
|
-
# cannot fold an aliasing copy through the catalog.
|
|
19
|
+
# initialize_copy is blocklisted by convention so a hypothetical future `Constant<Pathname>`
|
|
20
|
+
# carrier cannot fold an aliasing copy through the catalog.
|
|
26
21
|
:initialize_copy
|
|
27
22
|
]
|
|
28
23
|
}
|