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
|
@@ -5,76 +5,55 @@ require_relative "../../type"
|
|
|
5
5
|
module Rigor
|
|
6
6
|
module Inference
|
|
7
7
|
module MethodDispatcher
|
|
8
|
-
# Dispatcher tier that lifts string-composition results into
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
# handles all-Constant cases) and {ShapeDispatch}; runs for:
|
|
8
|
+
# Dispatcher tier that lifts string-composition results into the `literal-string` carrier when every
|
|
9
|
+
# operand is itself literal-bearing. Sits between {ConstantFolding} (which handles all-Constant cases)
|
|
10
|
+
# and {ShapeDispatch}; runs for:
|
|
12
11
|
#
|
|
13
|
-
# - `String#+` / `String#*` / `String#<<` / `String#concat`
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
# - `
|
|
20
|
-
#
|
|
21
|
-
# literal-bearing.
|
|
22
|
-
# - `Kernel#format` / `Kernel#sprintf` (any receiver) and
|
|
23
|
-
# `String#%` (literal-bearing receiver) when every value
|
|
24
|
-
# argument is literal-bearing or a Type::Constant of any
|
|
25
|
-
# value.
|
|
12
|
+
# - `String#+` / `String#*` / `String#<<` / `String#concat` on string-typed receivers whose inputs
|
|
13
|
+
# the ConstantFolding tier could not fold to a precise `Constant<String>` (e.g. one operand is
|
|
14
|
+
# `literal-string` rather than `Constant<String>`, or the multiplication exceeds the constant-fold
|
|
15
|
+
# size cap).
|
|
16
|
+
# - `Array#join` on `Tuple[…]` receivers whose every element plus the separator argument (when given)
|
|
17
|
+
# is literal-bearing.
|
|
18
|
+
# - `Kernel#format` / `Kernel#sprintf` (any receiver) and `String#%` (literal-bearing receiver) when
|
|
19
|
+
# every value argument is literal-bearing or a Type::Constant of any value.
|
|
26
20
|
#
|
|
27
21
|
# Result rule:
|
|
28
22
|
#
|
|
29
23
|
# - `+`, `<<`, `concat`: receiver and argument MUST both be
|
|
30
|
-
# `Type::Combinator.literal_string_compatible?`. The result
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
# literal-string-compatible; the optional separator
|
|
41
|
-
# argument MUST also be literal-string-compatible.
|
|
42
|
-
# Result: `literal-string`. Empty `Tuple[]` lifts too —
|
|
43
|
-
# `[].join` is the empty string at runtime, which is
|
|
44
|
-
# literal-bearing trivially.
|
|
24
|
+
# `Type::Combinator.literal_string_compatible?`. The result is `literal-string`. `<<` and `concat`
|
|
25
|
+
# mutate the receiver at runtime; the analyzer does not track that mutation against the local's
|
|
26
|
+
# binding, but the call's *return value* is the receiver itself, and the receiver stays
|
|
27
|
+
# literal-bearing because every appended slice was literal-bearing too.
|
|
28
|
+
# - `*`: receiver MUST be literal-bearing; argument MUST be integer-typed. The result is
|
|
29
|
+
# `literal-string`.
|
|
30
|
+
# - `join`: receiver MUST be `Tuple[…]` with every element literal-string-compatible; the optional
|
|
31
|
+
# separator argument MUST also be literal-string-compatible. Result: `literal-string`. Empty
|
|
32
|
+
# `Tuple[]` lifts too — `[].join` is the empty string at runtime, which is literal-bearing
|
|
33
|
+
# trivially.
|
|
45
34
|
#
|
|
46
|
-
# Other receiver / argument shapes decline so the next tier
|
|
47
|
-
#
|
|
48
|
-
# the call site widens to the RBS-declared `Nominal[String]`
|
|
49
|
-
# as before.
|
|
35
|
+
# Other receiver / argument shapes decline so the next tier (ShapeDispatch / FileFolding /
|
|
36
|
+
# RbsDispatch) takes over and the call site widens to the RBS-declared `Nominal[String]` as before.
|
|
50
37
|
module LiteralStringFolding
|
|
51
38
|
module_function
|
|
52
39
|
|
|
53
40
|
CONCAT_METHODS = %i[+ << concat].freeze
|
|
54
41
|
FORMAT_METHODS = %i[format sprintf].freeze
|
|
55
|
-
# v0.1.1 Track 1 slice 5a — methods that, called with no
|
|
56
|
-
#
|
|
57
|
-
#
|
|
58
|
-
#
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
# value comes from source code and is always valid UTF-8,
|
|
63
|
-
# so the result is identical to the receiver. None of
|
|
64
|
-
# these preserve `non-empty-string`-ness (e.g. `" ".strip
|
|
65
|
-
# == ""`); the carrier collapses from `non-empty-literal-string`
|
|
66
|
-
# down to plain `literal-string`.
|
|
42
|
+
# v0.1.1 Track 1 slice 5a — methods that, called with no arguments on a literal-bearing receiver,
|
|
43
|
+
# return a value that is also literal-bearing. `#strip` / `#lstrip` / `#rstrip` / `#chomp` (no-arg)
|
|
44
|
+
# / `#chop` strip a known subset of characters from the ends, so the survivors are always a
|
|
45
|
+
# substring of an already-literal value. `#scrub` (no-arg) replaces invalid bytes; a literal-string
|
|
46
|
+
# value comes from source code and is always valid UTF-8, so the result is identical to the
|
|
47
|
+
# receiver. None of these preserve `non-empty-string`-ness (e.g. `" ".strip == ""`); the carrier
|
|
48
|
+
# collapses from `non-empty-literal-string` down to plain `literal-string`.
|
|
67
49
|
LITERAL_PRESERVING_METHODS = %i[strip lstrip rstrip chomp chop scrub].freeze
|
|
68
|
-
# Methods that preserve literal-bearing AND non-empty-string-ness.
|
|
69
|
-
#
|
|
70
|
-
#
|
|
71
|
-
# removing any, so a non-empty receiver stays non-empty.
|
|
50
|
+
# Methods that preserve literal-bearing AND non-empty-string-ness. Unlike `LITERAL_PRESERVING_METHODS`
|
|
51
|
+
# (strip/chomp/etc.) these do not reduce the string — they transform characters without removing
|
|
52
|
+
# any, so a non-empty receiver stays non-empty.
|
|
72
53
|
NON_EMPTY_LITERAL_PRESERVING_METHODS = %i[upcase downcase capitalize swapcase reverse].freeze
|
|
73
|
-
# v0.1.1 Track 1 slice 5c — width-padding methods. `center`
|
|
74
|
-
#
|
|
75
|
-
#
|
|
76
|
-
# and the (default or supplied) padding are both
|
|
77
|
-
# literal-bearing, the result is literal-bearing too.
|
|
54
|
+
# v0.1.1 Track 1 slice 5c — width-padding methods. `center` / `ljust` / `rjust` take a `width`
|
|
55
|
+
# Integer plus an optional literal padding `String`. When the receiver and the (default or
|
|
56
|
+
# supplied) padding are both literal-bearing, the result is literal-bearing too.
|
|
78
57
|
WIDTH_PADDING_METHODS = %i[center ljust rjust].freeze
|
|
79
58
|
private_constant :CONCAT_METHODS, :FORMAT_METHODS,
|
|
80
59
|
:LITERAL_PRESERVING_METHODS, :NON_EMPTY_LITERAL_PRESERVING_METHODS,
|
|
@@ -106,15 +85,11 @@ module Rigor
|
|
|
106
85
|
nil
|
|
107
86
|
end
|
|
108
87
|
|
|
109
|
-
# `String#center` / `#ljust` / `#rjust` — first argument is
|
|
110
|
-
# the
|
|
111
|
-
#
|
|
112
|
-
#
|
|
113
|
-
#
|
|
114
|
-
# passes through. Width is allowed to be any Integer
|
|
115
|
-
# because Ruby's runtime accepts negative widths and
|
|
116
|
-
# widths smaller than the receiver's length without
|
|
117
|
-
# raising.
|
|
88
|
+
# `String#center` / `#ljust` / `#rjust` — first argument is the target width (Integer-typed),
|
|
89
|
+
# optional second argument is the padding string (must be literal-bearing for the result to stay
|
|
90
|
+
# literal). The default padding (a space) is always literal so the no-second-arg form passes
|
|
91
|
+
# through. Width is allowed to be any Integer because Ruby's runtime accepts negative widths and
|
|
92
|
+
# widths smaller than the receiver's length without raising.
|
|
118
93
|
def fold_width_pad(args)
|
|
119
94
|
return nil unless [1, 2].include?(args.size)
|
|
120
95
|
return nil unless integer_typed?(args[0])
|
|
@@ -146,8 +121,8 @@ module Rigor
|
|
|
146
121
|
Type::Combinator.literal_string
|
|
147
122
|
end
|
|
148
123
|
|
|
149
|
-
# Returns `non_empty_literal_string` when the receiver is provably
|
|
150
|
-
#
|
|
124
|
+
# Returns `non_empty_literal_string` when the receiver is provably non-empty; otherwise collapses
|
|
125
|
+
# to plain `literal_string`.
|
|
151
126
|
def non_empty_literal_result(receiver)
|
|
152
127
|
if Type::Combinator.non_empty_string_compatible?(receiver)
|
|
153
128
|
Type::Combinator.non_empty_literal_string
|
|
@@ -156,12 +131,10 @@ module Rigor
|
|
|
156
131
|
end
|
|
157
132
|
end
|
|
158
133
|
|
|
159
|
-
# `[lit, lit].join(sep)` — receiver must be a Tuple
|
|
160
|
-
#
|
|
161
|
-
#
|
|
162
|
-
#
|
|
163
|
-
# here because the dispatcher only routes through this
|
|
164
|
-
# tier when the call resolves to a single named method.
|
|
134
|
+
# `[lit, lit].join(sep)` — receiver must be a Tuple whose every element is literal-bearing;
|
|
135
|
+
# separator (when given) must be literal-bearing too. Multi-arg forms / `Array#join(*args)` splat
|
|
136
|
+
# shapes don't reach here because the dispatcher only routes through this tier when the call
|
|
137
|
+
# resolves to a single named method.
|
|
165
138
|
def fold_array_join(receiver, args)
|
|
166
139
|
return nil unless receiver.is_a?(Type::Tuple)
|
|
167
140
|
return nil unless receiver.elements.all? { |el| Type::Combinator.literal_string_compatible?(el) }
|
|
@@ -171,15 +144,11 @@ module Rigor
|
|
|
171
144
|
Type::Combinator.literal_string
|
|
172
145
|
end
|
|
173
146
|
|
|
174
|
-
# `format("hello %s", lit)` / `sprintf(...)` — template
|
|
175
|
-
#
|
|
176
|
-
# (
|
|
177
|
-
#
|
|
178
|
-
#
|
|
179
|
-
# be literal-bearing — a Constant<Integer> first arg
|
|
180
|
-
# would not be a valid format template, so the
|
|
181
|
-
# `Type::Constant` allowance applies only to subsequent
|
|
182
|
-
# value args.
|
|
147
|
+
# `format("hello %s", lit)` / `sprintf(...)` — template plus every value argument must be
|
|
148
|
+
# literal-bearing ({Type::Combinator.literal_string_compatible?}) or a `Type::Constant` of any
|
|
149
|
+
# value (Constants are always provably literal). The template arg specifically must be
|
|
150
|
+
# literal-bearing — a Constant<Integer> first arg would not be a valid format template, so the
|
|
151
|
+
# `Type::Constant` allowance applies only to subsequent value args.
|
|
183
152
|
def fold_format(args)
|
|
184
153
|
return nil if args.empty?
|
|
185
154
|
return nil unless Type::Combinator.literal_string_compatible?(args.first)
|
|
@@ -188,18 +157,14 @@ module Rigor
|
|
|
188
157
|
Type::Combinator.literal_string
|
|
189
158
|
end
|
|
190
159
|
|
|
191
|
-
# `"foo %s" % "x"` / `"foo %s" % ["x", "y"]` — receiver
|
|
192
|
-
#
|
|
193
|
-
# the caller); arg is either:
|
|
160
|
+
# `"foo %s" % "x"` / `"foo %s" % ["x", "y"]` — receiver is the template (already verified
|
|
161
|
+
# literal-bearing by the caller); arg is either:
|
|
194
162
|
#
|
|
195
163
|
# - a single literal-bearing string / Constant value, or
|
|
196
|
-
# - a Tuple whose every element is literal-bearing or a
|
|
197
|
-
# Constant.
|
|
164
|
+
# - a Tuple whose every element is literal-bearing or a Constant.
|
|
198
165
|
#
|
|
199
|
-
# Hash-form `%` (e.g. `"%{name}" % {name: "x"}`) is not
|
|
200
|
-
#
|
|
201
|
-
# support this, but the v0.0.x catalogue declines and
|
|
202
|
-
# widens to Nominal[String].
|
|
166
|
+
# Hash-form `%` (e.g. `"%{name}" % {name: "x"}`) is not yet folded — the analyzer's HashShape
|
|
167
|
+
# carrier could support this, but the v0.0.x catalogue declines and widens to Nominal[String].
|
|
203
168
|
def fold_string_percent(args)
|
|
204
169
|
return nil unless args.size == 1
|
|
205
170
|
|
|
@@ -228,11 +193,9 @@ module Rigor
|
|
|
228
193
|
end
|
|
229
194
|
end
|
|
230
195
|
|
|
231
|
-
# `String#*` raises ArgumentError on a negative multiplier, so a
|
|
232
|
-
#
|
|
233
|
-
#
|
|
234
|
-
# than promising a `literal-string` value that could never
|
|
235
|
-
# exist at runtime.
|
|
196
|
+
# `String#*` raises ArgumentError on a negative multiplier, so a `Constant<-1>` argument is not a
|
|
197
|
+
# valid lift target. Decline so the call site keeps the existing nil-result behaviour rather than
|
|
198
|
+
# promising a `literal-string` value that could never exist at runtime.
|
|
236
199
|
def known_negative_integer?(type)
|
|
237
200
|
type.is_a?(Type::Constant) && type.value.is_a?(Integer) && type.value.negative?
|
|
238
201
|
end
|
|
@@ -6,43 +6,34 @@ require_relative "singleton_folding"
|
|
|
6
6
|
module Rigor
|
|
7
7
|
module Inference
|
|
8
8
|
module MethodDispatcher
|
|
9
|
-
# Folds `Math` module-function calls on statically known numeric
|
|
10
|
-
# constants.
|
|
9
|
+
# Folds `Math` module-function calls on statically known numeric constants.
|
|
11
10
|
#
|
|
12
|
-
# `Math` is a pure, side-effect-free module whose functions are
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
# the call at inference time and returns the concrete result.
|
|
11
|
+
# `Math` is a pure, side-effect-free module whose functions are deterministic over their inputs — the
|
|
12
|
+
# same number always produces the same result. When every relevant argument is a `Constant` carrying
|
|
13
|
+
# a `Numeric` value, the analyzer evaluates the call at inference time and returns the concrete
|
|
14
|
+
# result.
|
|
17
15
|
#
|
|
18
16
|
# === Supported methods
|
|
19
17
|
#
|
|
20
|
-
# * Single-argument transcendental functions (`sqrt`, `cbrt`,
|
|
21
|
-
# `
|
|
22
|
-
# `
|
|
23
|
-
# `asinh`, `acosh`, `atanh`, `erf`, `erfc`, `gamma`) — return
|
|
24
|
-
# `Constant[Float]`.
|
|
18
|
+
# * Single-argument transcendental functions (`sqrt`, `cbrt`, `exp`, `log2`, `log10`, `log1p`,
|
|
19
|
+
# `expm1`, `sin`, `cos`, `tan`, `asin`, `acos`, `atan`, `sinh`, `cosh`, `tanh`, `asinh`, `acosh`,
|
|
20
|
+
# `atanh`, `erf`, `erfc`, `gamma`) — return `Constant[Float]`.
|
|
25
21
|
#
|
|
26
|
-
# * Two-argument functions (`atan2`, `hypot`, `ldexp`) — return
|
|
27
|
-
# `Constant[Float]`.
|
|
22
|
+
# * Two-argument functions (`atan2`, `hypot`, `ldexp`) — return `Constant[Float]`.
|
|
28
23
|
#
|
|
29
|
-
# * `log(x)` / `log(x, base)` — variadic; folds the 1- and
|
|
30
|
-
# 2-argument forms to `Constant[Float]`.
|
|
24
|
+
# * `log(x)` / `log(x, base)` — variadic; folds the 1- and 2-argument forms to `Constant[Float]`.
|
|
31
25
|
#
|
|
32
|
-
# * `frexp(x)` / `lgamma(x)` — return a two-element array, lifted
|
|
33
|
-
#
|
|
26
|
+
# * `frexp(x)` / `lgamma(x)` — return a two-element array, lifted to
|
|
27
|
+
# `Tuple[Constant[Float], Constant[Integer]]`.
|
|
34
28
|
#
|
|
35
29
|
# === Non-constant / unsupported cases
|
|
36
30
|
#
|
|
37
|
-
# Any call where the receiver is not `Singleton[Math]`, an
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
# `RangeError` (domain-error inputs like `Math.sqrt(-1)`) returns
|
|
41
|
-
# `nil`, deferring to the next dispatcher tier.
|
|
31
|
+
# Any call where the receiver is not `Singleton[Math]`, an argument is not a numeric `Constant`, the
|
|
32
|
+
# method is not in the supported set, or the Ruby call raises `Math::DomainError` / `RangeError`
|
|
33
|
+
# (domain-error inputs like `Math.sqrt(-1)`) returns `nil`, deferring to the next dispatcher tier.
|
|
42
34
|
#
|
|
43
|
-
# An infinite or NaN result (`Math.log(0.0)` → `-Infinity`) is
|
|
44
|
-
#
|
|
45
|
-
# `ConstantFolding`'s treatment of `Float / 0`.
|
|
35
|
+
# An infinite or NaN result (`Math.log(0.0)` → `-Infinity`) is still folded — `Constant[Float]`
|
|
36
|
+
# carries those values, matching `ConstantFolding`'s treatment of `Float / 0`.
|
|
46
37
|
module MathFolding
|
|
47
38
|
MATH_UNARY = Set[
|
|
48
39
|
:sqrt, :cbrt, :exp, :log2, :log10, :log1p, :expm1,
|
|
@@ -64,8 +55,7 @@ module Rigor
|
|
|
64
55
|
args = context.args
|
|
65
56
|
return nil unless SingletonFolding.receiver?(receiver, "Math")
|
|
66
57
|
|
|
67
|
-
# `log` is variadic (1 or 2 args), so it cannot live in the
|
|
68
|
-
# fixed-arity sets above.
|
|
58
|
+
# `log` is variadic (1 or 2 args), so it cannot live in the fixed-arity sets above.
|
|
69
59
|
return fold_log(args) if method_name == :log
|
|
70
60
|
return fold_unary(method_name, args) if MATH_UNARY.include?(method_name)
|
|
71
61
|
return fold_binary(method_name, args) if MATH_BINARY.include?(method_name)
|
|
@@ -74,8 +64,8 @@ module Rigor
|
|
|
74
64
|
nil
|
|
75
65
|
end
|
|
76
66
|
|
|
77
|
-
# Unwraps a numeric `Constant` argument to its Ruby value.
|
|
78
|
-
#
|
|
67
|
+
# Unwraps a numeric `Constant` argument to its Ruby value. Returns nil for any non-`Constant` or
|
|
68
|
+
# non-`Numeric` carrier.
|
|
79
69
|
def numeric_constant(arg)
|
|
80
70
|
return nil unless arg.is_a?(Type::Constant)
|
|
81
71
|
|
|
@@ -106,8 +96,7 @@ module Rigor
|
|
|
106
96
|
nil
|
|
107
97
|
end
|
|
108
98
|
|
|
109
|
-
# `Math.log(x)` and `Math.log(x, base)` — the only variadic
|
|
110
|
-
# `Math` function.
|
|
99
|
+
# `Math.log(x)` and `Math.log(x, base)` — the only variadic `Math` function.
|
|
111
100
|
def fold_log(args)
|
|
112
101
|
return nil unless [1, 2].include?(args.size)
|
|
113
102
|
|
|
@@ -119,8 +108,8 @@ module Rigor
|
|
|
119
108
|
nil
|
|
120
109
|
end
|
|
121
110
|
|
|
122
|
-
# `Math.frexp` / `Math.lgamma` return a two-element array;
|
|
123
|
-
#
|
|
111
|
+
# `Math.frexp` / `Math.lgamma` return a two-element array; lift it to
|
|
112
|
+
# `Tuple[Constant[Float], Constant[Integer]]`.
|
|
124
113
|
def fold_tuple_unary(method_name, args)
|
|
125
114
|
return nil unless args.size == 1
|
|
126
115
|
|
|
@@ -5,25 +5,20 @@ require_relative "../../type"
|
|
|
5
5
|
module Rigor
|
|
6
6
|
module Inference
|
|
7
7
|
module MethodDispatcher
|
|
8
|
-
# The member-shape projections shared by {DataFolding} and
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
# `
|
|
12
|
-
#
|
|
13
|
-
# `
|
|
14
|
-
# two folders. Only `#with`'s carrier constructor differs
|
|
15
|
-
# (`data_instance_of` vs `struct_instance_of`), so it takes a block
|
|
16
|
-
# that builds the new instance from the merged member map.
|
|
8
|
+
# The member-shape projections shared by {DataFolding} and {StructFolding}. A `DataInstance` and a
|
|
9
|
+
# `StructInstance` expose the same surface — an ordered `members` map, `member_names`, and a
|
|
10
|
+
# `class_name` — so the value projections off that surface (`[]` / `to_h` / `deconstruct` /
|
|
11
|
+
# `deconstruct_keys` / `members` / `with`) and the reader-redefinition guard are identical between the
|
|
12
|
+
# two folders. Only `#with`'s carrier constructor differs (`data_instance_of` vs
|
|
13
|
+
# `struct_instance_of`), so it takes a block that builds the new instance from the merged member map.
|
|
17
14
|
#
|
|
18
|
-
# Both folders `extend` this module so the projections resolve as
|
|
19
|
-
#
|
|
15
|
+
# Both folders `extend` this module so the projections resolve as their own module functions
|
|
16
|
+
# (matching their `module_function` style).
|
|
20
17
|
module MemberShapeProjection
|
|
21
|
-
# A Data/Struct subclass body can redefine a member's synthesised
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
# has none), so an entry in the project def-node table gates the
|
|
26
|
-
# bare member read off.
|
|
18
|
+
# A Data/Struct subclass body can redefine a member's synthesised reader (`def x`); when it does,
|
|
19
|
+
# `inst.x` runs that `def`, not the member, so folding the read would be unsound. A real `def` node
|
|
20
|
+
# under the class name is the discriminator (the synthesised reader has none), so an entry in the
|
|
21
|
+
# project def-node table gates the bare member read off.
|
|
27
22
|
def reader_overridden?(instance, method_name, scope)
|
|
28
23
|
class_name = instance.class_name
|
|
29
24
|
return false if class_name.nil? || scope.nil?
|
|
@@ -56,9 +51,8 @@ module Rigor
|
|
|
56
51
|
Type::Combinator.tuple_of(*instance.members.values)
|
|
57
52
|
end
|
|
58
53
|
|
|
59
|
-
# `deconstruct_keys(nil)` / `deconstruct_keys([:x])` both yield a
|
|
60
|
-
#
|
|
61
|
-
# is the full closed member shape.
|
|
54
|
+
# `deconstruct_keys(nil)` / `deconstruct_keys([:x])` both yield a subset of the member map; the
|
|
55
|
+
# conservative, always-correct answer is the full closed member shape.
|
|
62
56
|
def instance_deconstruct_keys(instance, args)
|
|
63
57
|
return nil unless args.size <= 1
|
|
64
58
|
|
|
@@ -69,12 +63,10 @@ module Rigor
|
|
|
69
63
|
Type::Combinator.tuple_of(*instance.member_names.map { |name| Type::Combinator.constant_of(name) })
|
|
70
64
|
end
|
|
71
65
|
|
|
72
|
-
# `#with(x: 9)` returns a new copy with the named members
|
|
73
|
-
#
|
|
74
|
-
#
|
|
75
|
-
#
|
|
76
|
-
# carrier constructor differs per folder, so the caller supplies it
|
|
77
|
-
# as a block taking the merged member map and the class name.
|
|
66
|
+
# `#with(x: 9)` returns a new copy with the named members overridden. Only a closed keyword
|
|
67
|
+
# `HashShape` whose keys are a subset of the members folds; anything else defers (RBS resolves
|
|
68
|
+
# `with` to `self`, returning the unchanged instance type). The carrier constructor differs per
|
|
69
|
+
# folder, so the caller supplies it as a block taking the merged member map and the class name.
|
|
78
70
|
def instance_with(instance, args)
|
|
79
71
|
return instance if args.empty?
|
|
80
72
|
return nil unless args.size == 1
|
|
@@ -7,49 +7,32 @@ module Rigor
|
|
|
7
7
|
module MethodDispatcher
|
|
8
8
|
# `Method` (and friends) precision tier.
|
|
9
9
|
#
|
|
10
|
-
# Two folds make a `Method` carrier round-trip with its
|
|
11
|
-
# binding visible:
|
|
10
|
+
# Two folds make a `Method` carrier round-trip with its binding visible:
|
|
12
11
|
#
|
|
13
|
-
# 1. **Forward** — `<receiver>.method(:sym)` (or
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
# `
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
# bound `(receiver_type, method_name)` and recurses
|
|
23
|
-
# back into `MethodDispatcher.dispatch`. The
|
|
24
|
-
# re-entrant call lets the substituted dispatch
|
|
25
|
-
# consume every tier the original call site would
|
|
26
|
-
# have — constant folding, shape dispatch, RBS,
|
|
27
|
-
# plugin contributions, etc. The original block_type
|
|
28
|
-
# / environment / call_node / scope are threaded
|
|
29
|
-
# through unchanged so capture-sensitive tiers (the
|
|
30
|
-
# block fold) keep working.
|
|
12
|
+
# 1. **Forward** — `<receiver>.method(:sym)` (or `.method("sym")`) lifts to {Type::BoundMethod}
|
|
13
|
+
# carrying the receiver type AND the resolved Symbol. Calling with a non-literal symbol-shaped
|
|
14
|
+
# argument declines so the RBS tier still answers `Nominal[Method]`.
|
|
15
|
+
# 2. **Backward** — `Type::BoundMethod#call(...)` / `#()` (Prism lowers `.()` into a CallNode whose
|
|
16
|
+
# `name` is `:call`) / `#[](...)` substitutes the bound `(receiver_type, method_name)` and
|
|
17
|
+
# recurses back into `MethodDispatcher.dispatch`. The re-entrant call lets the substituted
|
|
18
|
+
# dispatch consume every tier the original call site would have — constant folding, shape
|
|
19
|
+
# dispatch, RBS, plugin contributions, etc. The original block_type / environment / call_node /
|
|
20
|
+
# scope are threaded through unchanged so capture-sensitive tiers (the block fold) keep working.
|
|
31
21
|
#
|
|
32
|
-
# Lives ABOVE the standard precision-tier chain so the
|
|
33
|
-
# RBS
|
|
34
|
-
#
|
|
35
|
-
# `Method#call: (*untyped) -> untyped`, which is exactly
|
|
36
|
-
# the precision loss the carrier exists to avoid.
|
|
22
|
+
# Lives ABOVE the standard precision-tier chain so the RBS tier never sees a `BoundMethod` receiver —
|
|
23
|
+
# `Method` erasure means RBS would otherwise return `Method#call: (*untyped) -> untyped`, which is
|
|
24
|
+
# exactly the precision loss the carrier exists to avoid.
|
|
37
25
|
module MethodFolding
|
|
38
26
|
module_function
|
|
39
27
|
|
|
40
|
-
# Forward fold. Returns a {Type::BoundMethod} when the
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
# String argument. Declines on every other shape so
|
|
44
|
-
# the RBS tier still answers `Method` for non-folding
|
|
45
|
-
# cases.
|
|
28
|
+
# Forward fold. Returns a {Type::BoundMethod} when the call shape is `<receiver>.method(:name)` /
|
|
29
|
+
# `.method("name")` with a precisely-known Symbol / String argument. Declines on every other shape
|
|
30
|
+
# so the RBS tier still answers `Method` for non-folding cases.
|
|
46
31
|
#
|
|
47
32
|
# @param receiver [Rigor::Type] caller's receiver
|
|
48
|
-
# @param method_name [Symbol] the method being
|
|
49
|
-
# dispatched on `receiver` — only `:method` triggers
|
|
33
|
+
# @param method_name [Symbol] the method being dispatched on `receiver` — only `:method` triggers
|
|
50
34
|
# the fold.
|
|
51
|
-
# @param args [Array<Rigor::Type>] caller's argument
|
|
52
|
-
# types in order. Only the single-argument case
|
|
35
|
+
# @param args [Array<Rigor::Type>] caller's argument types in order. Only the single-argument case
|
|
53
36
|
# matches; other arities decline.
|
|
54
37
|
def try_dispatch(context)
|
|
55
38
|
receiver = context.receiver
|
|
@@ -64,35 +47,24 @@ module Rigor
|
|
|
64
47
|
Type::Combinator.bound_method_of(receiver, bound_name)
|
|
65
48
|
end
|
|
66
49
|
|
|
67
|
-
# Backward fold. Recurses into `MethodDispatcher.dispatch`
|
|
68
|
-
#
|
|
69
|
-
#
|
|
70
|
-
#
|
|
71
|
-
#
|
|
72
|
-
#
|
|
73
|
-
# `Dynamic[top]` rather than `nil` when the recursive
|
|
74
|
-
# dispatch declines so the call site still ends in a
|
|
75
|
-
# well-defined type (the gradual-safety net mirrors
|
|
76
|
-
# the engine's "BoundMethod erases to `Method`,
|
|
77
|
-
# `Method#call: (*untyped) -> untyped`" RBS fallback).
|
|
50
|
+
# Backward fold. Recurses into `MethodDispatcher.dispatch` with the bound `(receiver_type,
|
|
51
|
+
# method_name)`. The `block_type` / `environment` / `call_node` / `scope` are forwarded so every
|
|
52
|
+
# downstream tier (constant folding, shape dispatch, plugin contributions, …) keeps the original
|
|
53
|
+
# call site's context. Returns `Dynamic[top]` rather than `nil` when the recursive dispatch declines
|
|
54
|
+
# so the call site still ends in a well-defined type (the gradual-safety net mirrors the engine's
|
|
55
|
+
# "BoundMethod erases to `Method`, `Method#call: (*untyped) -> untyped`" RBS fallback).
|
|
78
56
|
def try_backward(context)
|
|
79
57
|
receiver = context.receiver
|
|
80
58
|
method_name = context.method_name
|
|
81
59
|
return nil unless receiver.is_a?(Type::BoundMethod)
|
|
82
60
|
return nil unless backward_method?(method_name)
|
|
83
61
|
|
|
84
|
-
# `Method#curry` is treated as identity on the carrier
|
|
85
|
-
#
|
|
86
|
-
#
|
|
87
|
-
#
|
|
88
|
-
#
|
|
89
|
-
#
|
|
90
|
-
# forms (`.curry(n).call(a)`) lose precision and fall
|
|
91
|
-
# through to RBS via the trailing
|
|
92
|
-
# `Type::Combinator.untyped`. A faithful
|
|
93
|
-
# `Type::CurriedBoundMethod(receiver_type,
|
|
94
|
-
# method_name, accumulated_args)` carrier is reserved
|
|
95
|
-
# for a future slice when concrete user demand
|
|
62
|
+
# `Method#curry` is treated as identity on the carrier — `<bound>.curry` keeps the same
|
|
63
|
+
# `(receiver_type, method_name)` so a subsequent `<curried>.call` still routes through the
|
|
64
|
+
# recursive dispatch below. This is correct for the dominant no-arg form (`.curry.call`);
|
|
65
|
+
# partially-applied forms (`.curry(n).call(a)`) lose precision and fall through to RBS via the
|
|
66
|
+
# trailing `Type::Combinator.untyped`. A faithful `Type::CurriedBoundMethod(receiver_type,
|
|
67
|
+
# method_name, accumulated_args)` carrier is reserved for a future slice when concrete user demand
|
|
96
68
|
# surfaces.
|
|
97
69
|
return receiver if method_name == :curry
|
|
98
70
|
|
|
@@ -106,14 +78,10 @@ module Rigor
|
|
|
106
78
|
scope: context.scope
|
|
107
79
|
) || Type::Combinator.untyped
|
|
108
80
|
end
|
|
109
|
-
# `Method#call` / `Method#()` and `Method#[]` are the
|
|
110
|
-
#
|
|
111
|
-
#
|
|
112
|
-
#
|
|
113
|
-
# do NOT fold through it (the case/when narrowing path
|
|
114
|
-
# already special-cases `===` for branch typing).
|
|
115
|
-
# `Method#curry` rides through as identity (see the
|
|
116
|
-
# comment in `try_backward`).
|
|
81
|
+
# `Method#call` / `Method#()` and `Method#[]` are the invocation entry points on the `Method` API;
|
|
82
|
+
# the alias `===` is also `call` semantically but is more commonly used as a case-equality
|
|
83
|
+
# predicate, so we do NOT fold through it (the case/when narrowing path already special-cases `===`
|
|
84
|
+
# for branch typing). `Method#curry` rides through as identity (see the comment in `try_backward`).
|
|
117
85
|
BACKWARD_METHOD_NAMES = %i[call [] curry].freeze
|
|
118
86
|
private_constant :BACKWARD_METHOD_NAMES
|
|
119
87
|
|
|
@@ -121,11 +89,9 @@ module Rigor
|
|
|
121
89
|
BACKWARD_METHOD_NAMES.include?(method_name)
|
|
122
90
|
end
|
|
123
91
|
|
|
124
|
-
# `Object#method` accepts both Symbol and String at
|
|
125
|
-
#
|
|
126
|
-
#
|
|
127
|
-
# but cheap to support and matches Ruby's documented
|
|
128
|
-
# contract.
|
|
92
|
+
# `Object#method` accepts both Symbol and String at runtime (the latter coerced via `to_sym`). The
|
|
93
|
+
# `Constant<String>` form is rare in production code but cheap to support and matches Ruby's
|
|
94
|
+
# documented contract.
|
|
129
95
|
def symbol_name_of(arg)
|
|
130
96
|
return nil unless arg.is_a?(Type::Constant)
|
|
131
97
|
|