rigortype 0.4.1 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/data/builtins/ruby_core/io.yml +1 -0
- data/data/builtins/ruby_core/proc.yml +4 -0
- data/data/builtins/ruby_core/random.yml +4 -0
- data/data/builtins/ruby_core/struct.yml +3 -0
- data/data/core_overlay/env.rbs +34 -0
- data/data/core_overlay/gc.rbs +50 -0
- data/data/core_overlay/hash.rbs +45 -0
- data/data/core_overlay/integer.rbs +31 -0
- data/data/core_overlay/io_buffer.rbs +27 -0
- data/data/core_overlay/kernel.rbs +40 -0
- data/data/core_overlay/match_data.rbs +28 -0
- data/data/core_overlay/module.rbs +51 -0
- data/data/core_overlay/object_space.rbs +29 -0
- data/data/core_overlay/proc.rbs +45 -0
- data/data/core_overlay/range.rbs +40 -0
- data/data/core_overlay/source_range.rbs +78 -0
- data/data/core_overlay/string.rbs +86 -0
- data/data/vendored_gem_sigs/prime/integer-extension.rbs +41 -0
- data/data/vendored_gem_sigs/prime/prime.rbs +372 -0
- data/docs/handbook/01-getting-started.md +3 -3
- data/docs/handbook/06-classes.md +3 -1
- data/docs/handbook/11-sig-gen.md +18 -5
- data/docs/handbook/appendix-liskov.md +5 -0
- data/docs/manual/02-cli-reference.md +19 -1
- data/docs/manual/03-configuration.md +7 -5
- data/docs/manual/04-diagnostics.md +2 -1
- data/docs/manual/05-inspecting-types.md +50 -0
- data/docs/manual/06-baseline.md +2 -0
- data/docs/manual/07-plugins.md +1 -1
- data/docs/manual/12-caching.md +18 -1
- data/docs/manual/14-rails-quickstart.md +2 -2
- data/docs/manual/18-removing-dead-code.md +41 -4
- data/docs/manual/plugins/README.md +6 -1
- data/docs/manual/plugins/rigor-activerecord.md +21 -0
- data/docs/manual/plugins/rigor-alba.md +60 -0
- data/docs/manual/plugins/rigor-minitest.md +22 -4
- data/docs/manual/plugins/rigor-typelizer.md +71 -0
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +27 -3
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +21 -92
- data/lib/rigor/analysis/check_rules/ruby_deprecations.rb +275 -0
- data/lib/rigor/analysis/check_rules/rule_ids.rb +11 -0
- data/lib/rigor/analysis/check_rules/source_arity.rb +21 -2
- data/lib/rigor/analysis/check_rules.rb +292 -59
- data/lib/rigor/analysis/dependency_recorder.rb +15 -0
- data/lib/rigor/analysis/dependency_source_inference/builder.rb +8 -1
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +21 -0
- data/lib/rigor/analysis/dependency_source_inference/index.rb +36 -11
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +196 -27
- data/lib/rigor/analysis/effects_cache_probe.rb +1 -1
- data/lib/rigor/analysis/erb_template_detector.rb +2 -1
- data/lib/rigor/analysis/incremental.rb +29 -9
- data/lib/rigor/analysis/incremental_run_slot/write_guard.rb +30 -5
- data/lib/rigor/analysis/incremental_run_slot.rb +6 -4
- data/lib/rigor/analysis/incremental_session.rb +103 -23
- data/lib/rigor/analysis/path_expansion.rb +62 -6
- data/lib/rigor/analysis/plugin_fact_fingerprint.rb +124 -37
- data/lib/rigor/analysis/reachability/graph.rb +241 -37
- data/lib/rigor/analysis/reachability/scan.rb +490 -77
- data/lib/rigor/analysis/reachability/scan_cache.rb +4 -2
- data/lib/rigor/analysis/rule_catalog.rb +43 -0
- data/lib/rigor/analysis/run_cache_key.rb +16 -1
- data/lib/rigor/analysis/run_cache_probe.rb +1 -1
- data/lib/rigor/analysis/run_stats.rb +28 -6
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +113 -6
- data/lib/rigor/analysis/runner/pool_coordinator.rb +77 -19
- data/lib/rigor/analysis/runner/project_pre_passes.rb +21 -1
- data/lib/rigor/analysis/runner/run_snapshots.rb +6 -1
- data/lib/rigor/analysis/runner.rb +62 -13
- data/lib/rigor/analysis/worker_session.rb +8 -5
- data/lib/rigor/cache/engine_source.rb +21 -7
- data/lib/rigor/cache/incremental_snapshot.rb +55 -5
- data/lib/rigor/cli/annotate_command.rb +5 -0
- data/lib/rigor/cli/baseline_command.rb +7 -18
- data/lib/rigor/cli/check_command.rb +140 -40
- data/lib/rigor/cli/docs_command.rb +5 -4
- data/lib/rigor/cli/lens_command.rb +144 -0
- data/lib/rigor/cli/lsp_command.rb +5 -2
- data/lib/rigor/cli/skill_command.rb +3 -3
- data/lib/rigor/cli/skill_describe.rb +1 -1
- data/lib/rigor/cli/trace_command.rb +5 -0
- data/lib/rigor/cli/type_of_command.rb +6 -3
- data/lib/rigor/cli/unused_command.rb +166 -27
- data/lib/rigor/cli.rb +39 -5
- data/lib/rigor/configuration/severity_profile.rb +6 -0
- data/lib/rigor/configuration.rb +61 -2
- data/lib/rigor/environment/bundle_sig_discovery.rb +11 -7
- data/lib/rigor/environment/gated_signature_guard.rb +43 -0
- data/lib/rigor/environment/gated_signature_plan.rb +339 -0
- data/lib/rigor/environment/installed_gem_set.rb +38 -11
- data/lib/rigor/environment/lockfile_resolver.rb +37 -6
- data/lib/rigor/environment/missing_gem_constant_index.rb +22 -7
- data/lib/rigor/environment/rbs_coverage_report.rb +1 -1
- data/lib/rigor/environment/rbs_loader.rb +316 -14
- data/lib/rigor/environment/required_features.rb +208 -0
- data/lib/rigor/environment.rb +33 -8
- data/lib/rigor/inference/acceptance.rb +28 -3
- data/lib/rigor/inference/builtins/cruby_definers.rb +78 -0
- data/lib/rigor/inference/builtins/method_catalog.rb +3 -0
- data/lib/rigor/inference/captured_locals.rb +43 -3
- data/lib/rigor/inference/def_node_resolver.rb +23 -1
- data/lib/rigor/inference/expression_typer.rb +261 -29
- data/lib/rigor/inference/global_write_census.rb +7 -4
- data/lib/rigor/inference/guard_rebinding.rb +1 -1
- data/lib/rigor/inference/in_effect_refinements/proc_literals.rb +83 -0
- data/lib/rigor/inference/in_effect_refinements/refine_defs.rb +54 -0
- data/lib/rigor/inference/in_effect_refinements/scope_reads.rb +286 -0
- data/lib/rigor/inference/in_effect_refinements/walk.rb +276 -0
- data/lib/rigor/inference/in_effect_refinements.rb +256 -0
- data/lib/rigor/inference/key_presence_guard/scan.rb +281 -0
- data/lib/rigor/inference/key_presence_guard.rb +303 -0
- data/lib/rigor/inference/macro_block_self_type.rb +59 -12
- data/lib/rigor/inference/match_rebinding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +36 -0
- data/lib/rigor/inference/method_dispatcher/argument_nodes.rb +25 -0
- data/lib/rigor/inference/method_dispatcher/arithmetic_sequence_elements.rb +73 -0
- data/lib/rigor/inference/method_dispatcher/imprecise_argument.rb +68 -0
- data/lib/rigor/inference/method_dispatcher/integer_step_block_params.rb +81 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +6 -0
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +3 -2
- data/lib/rigor/inference/method_dispatcher/keyword_arguments.rb +267 -0
- data/lib/rigor/inference/method_dispatcher/match_data_folding.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/member_shape_projection.rb +3 -3
- data/lib/rigor/inference/method_dispatcher/method_folding.rb +2 -1
- data/lib/rigor/inference/method_dispatcher/optional_count.rb +63 -0
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +122 -105
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +247 -28
- data/lib/rigor/inference/method_dispatcher/splat_arity.rb +71 -0
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +4 -7
- data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +8 -26
- data/lib/rigor/inference/method_dispatcher/unit_denominator_rational.rb +67 -0
- data/lib/rigor/inference/method_dispatcher.rb +96 -14
- data/lib/rigor/inference/module_function_state.rb +2 -1
- data/lib/rigor/inference/narrowing.rb +20 -6
- data/lib/rigor/inference/object_mixins.rb +180 -0
- data/lib/rigor/inference/project_patched_definedness_guard.rb +86 -0
- data/lib/rigor/inference/project_patched_methods.rb +12 -7
- data/lib/rigor/inference/project_patched_scanner.rb +108 -26
- data/lib/rigor/inference/refine_census.rb +239 -0
- data/lib/rigor/inference/refine_self.rb +317 -0
- data/lib/rigor/inference/refined_dispatch/class_object.rb +350 -0
- data/lib/rigor/inference/refined_dispatch/own_method.rb +475 -0
- data/lib/rigor/inference/refined_dispatch.rb +320 -0
- data/lib/rigor/inference/repeated_or_writes.rb +2 -0
- data/lib/rigor/inference/scope_indexer/mixin_accumulator.rb +13 -0
- data/lib/rigor/inference/scope_indexer.rb +827 -65
- data/lib/rigor/inference/statement_evaluator.rb +294 -51
- data/lib/rigor/inference/string_mutation.rb +9 -3
- data/lib/rigor/inference/synthetic_method_scanner.rb +2 -1
- data/lib/rigor/inference/untyped_rejoin.rb +75 -0
- data/lib/rigor/inference/version_guard.rb +19 -10
- data/lib/rigor/language_server/project_context.rb +87 -5
- data/lib/rigor/language_server/server.rb +18 -0
- data/lib/rigor/lens/anchor.rb +115 -0
- data/lib/rigor/lens/contract_reader.rb +118 -0
- data/lib/rigor/lens/document.rb +113 -0
- data/lib/rigor/lens/file_reader.rb +433 -0
- data/lib/rigor/lens/members.rb +153 -0
- data/lib/rigor/lens/parameters.rb +91 -0
- data/lib/rigor/lens/plugins.rb +40 -0
- data/lib/rigor/lens/run.rb +280 -0
- data/lib/rigor/lens/slot.rb +79 -0
- data/lib/rigor/lens.rb +40 -0
- data/lib/rigor/plugin/inflector.rb +1 -1
- data/lib/rigor/plugin/io_boundary.rb +42 -3
- data/lib/rigor/plugin/macro/block_as_method.rb +51 -8
- data/lib/rigor/project_environment.rb +48 -6
- data/lib/rigor/protection/mutation_cache.rb +3 -2
- data/lib/rigor/protection/mutator.rb +1 -1
- data/lib/rigor/reflection/constant_ancestors.rb +127 -11
- data/lib/rigor/reflection/constant_path.rb +13 -2
- data/lib/rigor/reflection.rb +40 -8
- data/lib/rigor/scope/discovery_index.rb +40 -1
- data/lib/rigor/scope/resolution_chain.rb +159 -11
- data/lib/rigor/scope.rb +211 -21
- data/lib/rigor/sig_gen/classification.rb +4 -1
- data/lib/rigor/sig_gen/generator.rb +100 -10
- data/lib/rigor/sig_gen/method_candidate.rb +2 -2
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +12 -0
- data/lib/rigor/source/alias_names.rb +52 -0
- data/lib/rigor/source/literals.rb +3 -2
- data/lib/rigor/source/symbol_name.rb +20 -0
- data/lib/rigor/type/combinator.rb +34 -2
- data/lib/rigor/type/float_range.rb +4 -1
- data/lib/rigor/type/nominal.rb +6 -1
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-ac-library-rb/lib/rigor/plugin/ac_library_rb.rb +28 -0
- data/plugins/rigor-ac-library-rb/lib/rigor-ac-library-rb.rb +3 -0
- data/plugins/rigor-ac-library-rb/sig/ac_library_rb/convolution.rbs +7 -0
- data/plugins/rigor-ac-library-rb/sig/ac_library_rb/data_structures.rbs +160 -0
- data/plugins/rigor-ac-library-rb/sig/ac_library_rb/graph.rbs +94 -0
- data/plugins/rigor-ac-library-rb/sig/ac_library_rb/math.rbs +42 -0
- data/plugins/rigor-ac-library-rb/sig/ac_library_rb/modint.rbs +71 -0
- data/plugins/rigor-ac-library-rb/sig/ac_library_rb/object.rbs +37 -0
- data/plugins/rigor-ac-library-rb/sig/ac_library_rb/segtree.rbs +83 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +2 -1
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_discoverer.rb +29 -3
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers.rb +5 -1
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/association_roots.rb +100 -0
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +94 -10
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +43 -2
- data/plugins/rigor-activerecord/sig/active_record/relation.rbs +3 -1
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_collector.rb +149 -0
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_discoverer.rb +74 -0
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_index.rb +104 -0
- data/plugins/rigor-alba/lib/rigor/plugin/alba.rb +85 -0
- data/plugins/rigor-alba/lib/rigor-alba.rb +3 -0
- data/plugins/rigor-alba/sig/alba.rbs +4 -0
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/analyzer.rb +2 -2
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/target_detector.rb +29 -12
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +7 -6
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +130 -21
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +6 -4
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +4 -4
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +1 -1
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +1 -1
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +31 -0
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_collector.rb +102 -0
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_discoverer.rb +87 -0
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_index.rb +76 -0
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer.rb +73 -0
- data/plugins/rigor-typelizer/lib/rigor-typelizer.rb +3 -0
- data/sig/rigor/analysis/dependency_source_inference/index.rbs +1 -1
- data/sig/rigor/plugin/io_boundary.rbs +3 -0
- data/sig/rigor/scope.rbs +30 -4
- data/sig/rigor/source.rbs +4 -0
- data/sig/rigor.rbs +9 -4
- data/skills/rigor-project-init/references/02-configure.md +2 -2
- metadata +83 -1
|
@@ -135,6 +135,18 @@ module Rigor
|
|
|
135
135
|
"body, not the override the subclass actually runs.",
|
|
136
136
|
next_step: "Generate signatures for the overriding subclass too — widen the `sig-gen` path set to " \
|
|
137
137
|
"cover it — and the parent's declaration becomes safe to emit."
|
|
138
|
+
),
|
|
139
|
+
"sig.skipped.top-level-def" => Entry.new(
|
|
140
|
+
id: "sig.skipped.top-level-def",
|
|
141
|
+
summary: "A top-level `def` defines a private `Object` method, and sig-gen writes no signature for it.",
|
|
142
|
+
explanation: "Not a gap in inference. A `def` outside any `class` or `module` has no class to " \
|
|
143
|
+
"declare the member under, and Ruby makes it a private method on `Object`. sig-gen " \
|
|
144
|
+
"reports it instead of dropping it silently, so a file that defines only top-level " \
|
|
145
|
+
"methods is not mistaken for one that was never read. Whether to emit it as a private " \
|
|
146
|
+
"`Object` method is undecided (#1676); `def self.x` and `def` inside a block body are " \
|
|
147
|
+
"not reported.",
|
|
148
|
+
next_step: "Nothing is required. To type the method, move it into a module (`module_function` or " \
|
|
149
|
+
"`extend self` keeps the call sites), or write the `Object` declaration by hand in `sig/`."
|
|
138
150
|
)
|
|
139
151
|
}.freeze
|
|
140
152
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "prism"
|
|
4
|
+
require_relative "symbol_name"
|
|
5
|
+
|
|
6
|
+
module Rigor
|
|
7
|
+
module Source
|
|
8
|
+
# The `[new_name, old_name]` pair a method-alias statement names, read off its syntax alone: the `alias` keyword
|
|
9
|
+
# (`alias to_m to_modint`, `alias :to_m :to_modint`) and an implicit-self `alias_method :to_m, :to_modint` call
|
|
10
|
+
# whose two arguments are Symbol or String literals. A computed name (`alias_method name, :x`, an interpolated
|
|
11
|
+
# symbol) is runtime data and reads as nil, so no walker files an alias for it.
|
|
12
|
+
#
|
|
13
|
+
# The one reader the per-file discovery walk ({Inference::ScopeIndexer}) and the `pre_eval:` pre-pass
|
|
14
|
+
# ({Inference::ProjectPatchedScanner}) share, so a patch file's aliases mean the same thing in both.
|
|
15
|
+
module AliasNames
|
|
16
|
+
module_function
|
|
17
|
+
|
|
18
|
+
# The pair for an `alias` keyword whose two names are plain symbols (a bare identifier parses as one), or nil.
|
|
19
|
+
def keyword_names(alias_node)
|
|
20
|
+
new_name = symbol_name(alias_node.new_name)
|
|
21
|
+
old_name = symbol_name(alias_node.old_name)
|
|
22
|
+
return nil if new_name.nil? || old_name.nil?
|
|
23
|
+
|
|
24
|
+
[new_name, old_name]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# The pair for an implicit-self `alias_method` call with two literal Symbol / String arguments, or nil.
|
|
28
|
+
def alias_method_call_names(call_node)
|
|
29
|
+
return nil unless call_node.name == :alias_method && call_node.receiver.nil?
|
|
30
|
+
|
|
31
|
+
args = call_node.arguments&.arguments
|
|
32
|
+
return nil unless args && args.size == 2
|
|
33
|
+
|
|
34
|
+
new_name = literal_name(args[0])
|
|
35
|
+
old_name = literal_name(args[1])
|
|
36
|
+
return nil if new_name.nil? || old_name.nil?
|
|
37
|
+
|
|
38
|
+
[new_name, old_name]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def symbol_name(node)
|
|
42
|
+
node.is_a?(Prism::SymbolNode) ? SymbolName.of(node.unescaped) : nil
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def literal_name(node)
|
|
46
|
+
return nil unless node.is_a?(Prism::SymbolNode) || node.is_a?(Prism::StringNode)
|
|
47
|
+
|
|
48
|
+
SymbolName.of(node.unescaped)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "prism"
|
|
4
|
+
require_relative "symbol_name"
|
|
4
5
|
|
|
5
6
|
module Rigor
|
|
6
7
|
module Source
|
|
@@ -34,7 +35,7 @@ module Rigor
|
|
|
34
35
|
def symbol_or_string(node)
|
|
35
36
|
return nil unless node.is_a?(Prism::SymbolNode) || node.is_a?(Prism::StringNode)
|
|
36
37
|
|
|
37
|
-
node.unescaped
|
|
38
|
+
SymbolName.of(node.unescaped)
|
|
38
39
|
end
|
|
39
40
|
|
|
40
41
|
# The String a literal `Prism::SymbolNode` / `Prism::StringNode` names, or `nil` for any other node
|
|
@@ -53,7 +54,7 @@ module Rigor
|
|
|
53
54
|
def symbol(node)
|
|
54
55
|
return nil unless node.is_a?(Prism::SymbolNode)
|
|
55
56
|
|
|
56
|
-
node.unescaped
|
|
57
|
+
SymbolName.of(node.unescaped)
|
|
57
58
|
end
|
|
58
59
|
|
|
59
60
|
# The String a literal `Prism::SymbolNode` names, or `nil` for any other node (including a
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rigor
|
|
4
|
+
module Source
|
|
5
|
+
# The Symbol a name's text denotes, or `nil` when no Symbol can hold its bytes.
|
|
6
|
+
#
|
|
7
|
+
# `"\xff".to_sym` raises EncodingError, and a String literal may carry any bytes (a Symbol literal with invalid
|
|
8
|
+
# bytes is a syntax error, so no analysed file has one). Every reader of a literal name goes through here, so such
|
|
9
|
+
# a name reads as `nil` — the answer a computed name already gets — instead of aborting the file's analysis (#1821).
|
|
10
|
+
# `valid_encoding?` is the test, not `ascii_only?`: a name that is valid in its own encoding (a binary or Shift_JIS
|
|
11
|
+
# source) is a real Symbol.
|
|
12
|
+
module SymbolName
|
|
13
|
+
module_function
|
|
14
|
+
|
|
15
|
+
def of(text)
|
|
16
|
+
text.to_sym if text&.valid_encoding?
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -832,7 +832,8 @@ module Rigor
|
|
|
832
832
|
# instead of several readings of it. The normative relation is
|
|
833
833
|
# docs/type-specification/normalization.md § "Member absorption"; {absorbed_by?} is that list.
|
|
834
834
|
#
|
|
835
|
-
# Only a `FloatRange`, `Tuple` or `
|
|
835
|
+
# Only a `FloatRange`, `Tuple`, `HashShape` or element-carrying `Enumerator::ArithmeticSequence` member
|
|
836
|
+
# can be dropped (the last also joins with its kind, {join_sequence_elements}), so the O(n²) scan is
|
|
836
837
|
# skipped for every union that carries none of them — this runs on the hot path of every join.
|
|
837
838
|
#
|
|
838
839
|
# The `!absorbed_by?(other, member)` re-check costs one predicate call per pair that absorbed
|
|
@@ -841,6 +842,7 @@ module Rigor
|
|
|
841
842
|
def absorb_contained_members(members)
|
|
842
843
|
return members unless members.any? { |m| absorbable_member?(m) }
|
|
843
844
|
|
|
845
|
+
members = join_sequence_elements(members)
|
|
844
846
|
members.reject do |member|
|
|
845
847
|
absorbable_member?(member) &&
|
|
846
848
|
members.any? do |other|
|
|
@@ -850,7 +852,36 @@ module Rigor
|
|
|
850
852
|
end
|
|
851
853
|
|
|
852
854
|
def absorbable_member?(type)
|
|
853
|
-
type.is_a?(FloatRange) || type.is_a?(Tuple) || type.is_a?(HashShape)
|
|
855
|
+
type.is_a?(FloatRange) || type.is_a?(Tuple) || type.is_a?(HashShape) || element_sequence?(type)
|
|
856
|
+
end
|
|
857
|
+
|
|
858
|
+
ARITHMETIC_SEQUENCE = "Enumerator::ArithmeticSequence"
|
|
859
|
+
private_constant :ARITHMETIC_SEQUENCE
|
|
860
|
+
|
|
861
|
+
# Issue #1794 — the `Enumerator::ArithmeticSequence[E]` block-less `Integer#step` returns, whose element is
|
|
862
|
+
# a Rigor-private type argument (`Nominal::RIGOR_PRIVATE_TYPE_ARGS`).
|
|
863
|
+
def element_sequence?(type)
|
|
864
|
+
type.is_a?(Nominal) && type.class_name == ARITHMETIC_SEQUENCE && type.type_args.size == 1
|
|
865
|
+
end
|
|
866
|
+
|
|
867
|
+
def plain_sequence?(type)
|
|
868
|
+
type.is_a?(Nominal) && type.class_name == ARITHMETIC_SEQUENCE && type.type_args.empty?
|
|
869
|
+
end
|
|
870
|
+
|
|
871
|
+
# Two element-carrying sequences join into one over the union of their elements, so a join of
|
|
872
|
+
# `1.step(10, 2)` and `1.step(10, 3)` stays one sequence whose block reads `Integer`, the answer each arm
|
|
873
|
+
# gives. (A plain sequence absorbing one with an element is the {absorbed_by?} clause.)
|
|
874
|
+
def join_sequence_elements(members)
|
|
875
|
+
sequences = members.select { |member| element_sequence?(member) }
|
|
876
|
+
return members if sequences.size < 2
|
|
877
|
+
|
|
878
|
+
joined = nominal_of(ARITHMETIC_SEQUENCE, type_args: [union(*sequences.map { |seq| seq.type_args.first })])
|
|
879
|
+
first = sequences.first
|
|
880
|
+
members.filter_map do |member|
|
|
881
|
+
if member.equal?(first) then joined
|
|
882
|
+
elsif !sequences.include?(member) then member
|
|
883
|
+
end
|
|
884
|
+
end
|
|
854
885
|
end
|
|
855
886
|
|
|
856
887
|
# `narrower`'s inhabitants are a subset of `wider`'s under a rule the union already applies to
|
|
@@ -864,6 +895,7 @@ module Rigor
|
|
|
864
895
|
return true if listed_in_union?(narrower, wider)
|
|
865
896
|
|
|
866
897
|
case narrower
|
|
898
|
+
when Nominal then element_sequence?(narrower) && plain_sequence?(wider)
|
|
867
899
|
when FloatRange then float_range_absorbed_by?(narrower, wider)
|
|
868
900
|
when Tuple then wider.is_a?(Tuple) && tuple_absorbed_by?(narrower, wider)
|
|
869
901
|
when HashShape then wider.is_a?(HashShape) && hash_shape_absorbed_by?(narrower, wider)
|
|
@@ -11,7 +11,7 @@ module Rigor
|
|
|
11
11
|
# bounds, never sentinels, because Ruby orders them. The range may exclude its end (`0.0...1.0`)
|
|
12
12
|
# and never its beginning, because Ruby's literal has no exclusive begin.
|
|
13
13
|
#
|
|
14
|
-
# No bounded range contains NaN
|
|
14
|
+
# No bounded range contains NaN (`#covers?` answers false for it on every Ruby), so
|
|
15
15
|
# the range from `-Float::INFINITY` to `Float::INFINITY` is "every Float except NaN"
|
|
16
16
|
# (`non-nan-float`), not `Float`. The whole of `Float` (`nil..nil` in Ruby, which does cover NaN)
|
|
17
17
|
# is never a carrier; the payload builder normalises it to `Nominal[Float]`.
|
|
@@ -58,6 +58,9 @@ module Rigor
|
|
|
58
58
|
# displays as does.
|
|
59
59
|
def covers?(value)
|
|
60
60
|
return false unless value.is_a?(Float)
|
|
61
|
+
# NaN is in no bounded range, so answer false here: `Range#cover?(Float::NAN)` raises
|
|
62
|
+
# ArgumentError on ruby-head (4.1), where Ruby 4.0 returned false.
|
|
63
|
+
return false if value.nan?
|
|
61
64
|
|
|
62
65
|
Range.new(min, max, @exclude_end).cover?(value)
|
|
63
66
|
end
|
data/lib/rigor/type/nominal.rb
CHANGED
|
@@ -49,9 +49,14 @@ module Rigor
|
|
|
49
49
|
"#{rendered_name}[#{rendered}]"
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
+
# Classes RBS declares without a type parameter, on which Rigor carries one of its own: the element type of
|
|
53
|
+
# the `Enumerator::ArithmeticSequence` that `Integer#step` returns (issue #1794). RBS has no slot for it, so
|
|
54
|
+
# the argument erases away.
|
|
55
|
+
RIGOR_PRIVATE_TYPE_ARGS = %w[Enumerator::ArithmeticSequence].freeze
|
|
56
|
+
|
|
52
57
|
def erase_to_rbs
|
|
53
58
|
return "untyped" if AnonymousClassName.match?(class_name)
|
|
54
|
-
return class_name if type_args.empty?
|
|
59
|
+
return class_name if type_args.empty? || RIGOR_PRIVATE_TYPE_ARGS.include?(class_name)
|
|
55
60
|
|
|
56
61
|
rendered = type_args.map(&:erase_to_rbs).join(", ")
|
|
57
62
|
"#{class_name}[#{rendered}]"
|
data/lib/rigor/version.rb
CHANGED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rigor/plugin"
|
|
4
|
+
|
|
5
|
+
module Rigor
|
|
6
|
+
module Plugin
|
|
7
|
+
# A pure RBS-bundle plugin for ac-library-rb, the Ruby port of the AtCoder Library. It emits no diagnostic and
|
|
8
|
+
# declares no producer: the manifest's `signature_paths: ["sig"]` adds the bundled `AcLibraryRb` signatures to the
|
|
9
|
+
# RBS environment.
|
|
10
|
+
#
|
|
11
|
+
# Inference cannot write these. The containers are generic over values the caller picks (a segment tree's monoid,
|
|
12
|
+
# a priority queue's elements), and their methods read parameters no call site in the library constrains, so
|
|
13
|
+
# `rigor sig-gen` over the gem's `lib_lock/` leaves 95 of its methods untyped. The signatures were written against
|
|
14
|
+
# that output and the gem's documentation, and `rigor check` over `lib_lock/` holds the method bodies to them.
|
|
15
|
+
class AcLibraryRb < Base
|
|
16
|
+
manifest(
|
|
17
|
+
id: "ac-library-rb",
|
|
18
|
+
target_gems: ["ac-library-rb"],
|
|
19
|
+
version: "0.1.0",
|
|
20
|
+
description: "RBS bundle for ac-library-rb (AtCoder Library): Segtree, LazySegtree, DSU, ModInt, flows " \
|
|
21
|
+
"and the math and string algorithms.",
|
|
22
|
+
signature_paths: ["sig"]
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
Rigor::Plugin.register(Rigor::Plugin::AcLibraryRb)
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
module AcLibraryRb
|
|
2
|
+
class DSU
|
|
3
|
+
attr_reader parent_or_size: Array[Integer]
|
|
4
|
+
attr_reader n: Integer
|
|
5
|
+
|
|
6
|
+
def initialize: (?Integer n) -> void
|
|
7
|
+
|
|
8
|
+
# The leader of the merged component.
|
|
9
|
+
def merge: (Integer a, Integer b) -> Integer
|
|
10
|
+
alias unite merge
|
|
11
|
+
|
|
12
|
+
def same?: (Integer a, Integer b) -> bool
|
|
13
|
+
alias same same?
|
|
14
|
+
|
|
15
|
+
def leader: (Integer a) -> Integer
|
|
16
|
+
alias root leader
|
|
17
|
+
alias find leader
|
|
18
|
+
|
|
19
|
+
# Like `leader`, growing the set to hold `a` when it is out of range.
|
|
20
|
+
def []: (Integer a) -> Integer
|
|
21
|
+
|
|
22
|
+
def size: (Integer a) -> Integer
|
|
23
|
+
|
|
24
|
+
def groups: () -> Array[Array[Integer]]
|
|
25
|
+
|
|
26
|
+
def to_s: () -> String
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class UnionFind = DSU
|
|
30
|
+
|
|
31
|
+
# Element values are whatever the caller adds: the tree starts from `0` and adds with `+`, so an
|
|
32
|
+
# `Integer`, a `Float` and a `ModInt` all work.
|
|
33
|
+
class FenwickTree
|
|
34
|
+
attr_reader data: Array[untyped]
|
|
35
|
+
attr_reader size: Integer
|
|
36
|
+
|
|
37
|
+
def initialize: (Array[untyped] | Integer arg) -> void
|
|
38
|
+
|
|
39
|
+
def add: (Integer i, untyped x) -> void
|
|
40
|
+
|
|
41
|
+
def sum: (Integer l, Integer r) -> untyped
|
|
42
|
+
| (Integer r) -> untyped
|
|
43
|
+
| (Range[Integer] range) -> untyped
|
|
44
|
+
|
|
45
|
+
def _sum: (Integer i) -> untyped
|
|
46
|
+
alias left_sum _sum
|
|
47
|
+
|
|
48
|
+
def to_s: () -> String
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# A binary heap that pops the highest-priority element first: the largest by default, or the first
|
|
52
|
+
# argument of the block when it returns truthy.
|
|
53
|
+
class PriorityQueue[T]
|
|
54
|
+
# The factories answer `PriorityQueue[untyped]`: bound from a literal array, `T` would be the literals it
|
|
55
|
+
# starts with, and a later `pop` would read as one of them.
|
|
56
|
+
def self.max: (Array[untyped] array) -> PriorityQueue[untyped]
|
|
57
|
+
|
|
58
|
+
def self.min: (Array[untyped] array) -> PriorityQueue[untyped]
|
|
59
|
+
|
|
60
|
+
def self.[]: (*untyped array) ?{ (untyped, untyped) -> boolish } -> PriorityQueue[untyped]
|
|
61
|
+
|
|
62
|
+
def initialize: (?Array[T] array) ?{ (T, T) -> boolish } -> void
|
|
63
|
+
|
|
64
|
+
attr_reader heap: Array[T]
|
|
65
|
+
alias to_a heap
|
|
66
|
+
|
|
67
|
+
def push: (T item) -> self
|
|
68
|
+
alias << push
|
|
69
|
+
alias append push
|
|
70
|
+
|
|
71
|
+
def pop: () -> T?
|
|
72
|
+
|
|
73
|
+
def get: () -> T?
|
|
74
|
+
alias top get
|
|
75
|
+
alias first get
|
|
76
|
+
|
|
77
|
+
def empty?: () -> bool
|
|
78
|
+
|
|
79
|
+
def size: () -> Integer
|
|
80
|
+
|
|
81
|
+
def to_s: () -> String
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
class HeapQueue = PriorityQueue
|
|
85
|
+
|
|
86
|
+
class Deque[T]
|
|
87
|
+
include Enumerable[T]
|
|
88
|
+
|
|
89
|
+
def self.[]: (*untyped args) -> Deque[untyped]
|
|
90
|
+
|
|
91
|
+
def initialize: (?Array[T] arg, ?untyped value, ?initial_capacity: Integer) -> void
|
|
92
|
+
| (Integer size, ?T value, ?initial_capacity: Integer) -> void
|
|
93
|
+
|
|
94
|
+
def empty?: () -> bool
|
|
95
|
+
|
|
96
|
+
def size: () -> Integer
|
|
97
|
+
alias length size
|
|
98
|
+
|
|
99
|
+
def <<: (T x) -> self
|
|
100
|
+
|
|
101
|
+
def push: (*T args) -> self
|
|
102
|
+
alias append push
|
|
103
|
+
|
|
104
|
+
def unshift: (*T args) -> self
|
|
105
|
+
alias prepend unshift
|
|
106
|
+
|
|
107
|
+
def pop: () -> T?
|
|
108
|
+
|
|
109
|
+
def shift: () -> T?
|
|
110
|
+
|
|
111
|
+
def last: () -> T?
|
|
112
|
+
|
|
113
|
+
def slice: (Integer idx) -> T?
|
|
114
|
+
|
|
115
|
+
def []: (Integer idx) -> T?
|
|
116
|
+
| (Integer start, Integer length) -> Deque[T]?
|
|
117
|
+
| (Range[Integer] range) -> Deque[T]?
|
|
118
|
+
|
|
119
|
+
def at: (Integer idx) -> T?
|
|
120
|
+
|
|
121
|
+
def []=: (Integer idx, T value) -> T
|
|
122
|
+
|
|
123
|
+
def ==: (untyped other) -> bool
|
|
124
|
+
|
|
125
|
+
def hash: () -> Integer
|
|
126
|
+
|
|
127
|
+
def reverse: () -> Deque[T]
|
|
128
|
+
|
|
129
|
+
def reverse!: () -> self
|
|
130
|
+
|
|
131
|
+
def reversed?: () -> bool
|
|
132
|
+
|
|
133
|
+
def dig: (int idx, *untyped) -> untyped
|
|
134
|
+
|
|
135
|
+
def each: () { (T) -> void } -> Array[T]
|
|
136
|
+
| () -> Enumerator[T, Array[T]]
|
|
137
|
+
|
|
138
|
+
def clear: () -> self
|
|
139
|
+
|
|
140
|
+
def join: (?String? sep) -> String
|
|
141
|
+
|
|
142
|
+
def rotate!: (?Integer cnt) -> self
|
|
143
|
+
|
|
144
|
+
def rotate: (?Integer cnt) -> Deque[T]
|
|
145
|
+
|
|
146
|
+
def sample: () -> T?
|
|
147
|
+
|
|
148
|
+
def shuffle: () -> Deque[T]
|
|
149
|
+
|
|
150
|
+
def replace: (_ToA[T] other) -> self
|
|
151
|
+
|
|
152
|
+
def swap: (Integer i, Integer j) -> self
|
|
153
|
+
|
|
154
|
+
def to_a: () -> Array[T]
|
|
155
|
+
|
|
156
|
+
def to_s: () -> String
|
|
157
|
+
|
|
158
|
+
def inspect: () -> String
|
|
159
|
+
end
|
|
160
|
+
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
module AcLibraryRb
|
|
2
|
+
class MaxFlow
|
|
3
|
+
def initialize: (Integer n) -> void
|
|
4
|
+
|
|
5
|
+
# The index of the added edge.
|
|
6
|
+
def add_edge: (Integer from, Integer to, Integer cap) -> Integer
|
|
7
|
+
|
|
8
|
+
def add_edges: (_Each[[Integer, Integer, Integer]] edges) -> self
|
|
9
|
+
|
|
10
|
+
def add: (Integer from, Integer to, Integer cap) -> Integer
|
|
11
|
+
| (_Each[[Integer, Integer, Integer]] edges) -> self
|
|
12
|
+
|
|
13
|
+
# `[from, to, cap]`, as `gets.split.map(&:to_i)` reads it.
|
|
14
|
+
def push: (Array[Integer] edge) -> Integer
|
|
15
|
+
alias << push
|
|
16
|
+
|
|
17
|
+
# `[from, to, cap, flow]` of the `i`-th edge.
|
|
18
|
+
def []: (Integer i) -> [Integer, Integer, Integer, Integer]
|
|
19
|
+
alias get_edge []
|
|
20
|
+
alias edge []
|
|
21
|
+
|
|
22
|
+
def edges: () -> Array[[Integer, Integer, Integer, Integer]]
|
|
23
|
+
|
|
24
|
+
def change_edge: (Integer i, Integer new_cap, Integer new_flow) -> void
|
|
25
|
+
|
|
26
|
+
# A `Float` limit the capacities do not bound comes back as the flow.
|
|
27
|
+
def flow: (Integer s, Integer t, ?Integer flow_limit) -> Integer
|
|
28
|
+
| (Integer s, Integer t, (Integer | Float) flow_limit) -> (Integer | Float)
|
|
29
|
+
alias max_flow flow
|
|
30
|
+
|
|
31
|
+
# Whether each vertex is reachable from `s` in the residual graph.
|
|
32
|
+
def min_cut: (Integer s) -> Array[bool]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class MinCostFlow
|
|
36
|
+
def initialize: (Integer n) -> void
|
|
37
|
+
|
|
38
|
+
# The index of the added edge.
|
|
39
|
+
def add_edge: (Integer from, Integer to, Integer cap, Integer cost) -> Integer
|
|
40
|
+
|
|
41
|
+
def add_edges: (_Each[[Integer, Integer, Integer, Integer]] edges) -> self
|
|
42
|
+
|
|
43
|
+
def add: (Integer from, Integer to, Integer cap, Integer cost) -> Integer
|
|
44
|
+
| (_Each[[Integer, Integer, Integer, Integer]] edges) -> self
|
|
45
|
+
|
|
46
|
+
# `[from, to, cap, flow, cost]` of the `i`-th edge.
|
|
47
|
+
def get_edge: (Integer i) -> [Integer, Integer, Integer, Integer, Integer]
|
|
48
|
+
alias edge get_edge
|
|
49
|
+
alias [] get_edge
|
|
50
|
+
|
|
51
|
+
def edges: () -> Array[[Integer, Integer, Integer, Integer, Integer]]
|
|
52
|
+
|
|
53
|
+
# `[flow, cost]`.
|
|
54
|
+
# The default limit is `Float::MAX`, which the capacities always bound; a smaller `Float` limit may not.
|
|
55
|
+
def flow: (Integer s, Integer t, ?Integer flow_limit) -> [Integer, Integer]
|
|
56
|
+
| (Integer s, Integer t, (Integer | Float) flow_limit) -> [Integer | Float, Integer | Float]
|
|
57
|
+
alias min_cost_max_flow flow
|
|
58
|
+
|
|
59
|
+
def dual_ref: (Integer s, Integer t) -> bool
|
|
60
|
+
|
|
61
|
+
# The `[flow, cost]` breakpoints of the cost curve.
|
|
62
|
+
def slope: (Integer s, Integer t, ?Integer flow_limit) -> Array[[Integer, Integer]]
|
|
63
|
+
| (Integer s, Integer t, (Integer | Float) flow_limit) -> Array[[Integer | Float, Integer | Float]]
|
|
64
|
+
alias min_cost_slop slope
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
class SCC
|
|
68
|
+
def initialize: (Integer n) -> void
|
|
69
|
+
|
|
70
|
+
def add_edge: (Integer from, Integer to) -> self
|
|
71
|
+
|
|
72
|
+
def add_edges: (_Each[[Integer, Integer]] edges) -> self
|
|
73
|
+
|
|
74
|
+
def add: (Integer from, Integer to) -> self
|
|
75
|
+
| (_Each[[Integer, Integer]] edges) -> self
|
|
76
|
+
|
|
77
|
+
# The strongly connected components in topological order.
|
|
78
|
+
def scc: () -> Array[Array[Integer]]
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
class TwoSAT
|
|
82
|
+
def initialize: (Integer n) -> void
|
|
83
|
+
|
|
84
|
+
# One assignment per variable once `satisfiable?` has answered true; `nil` before that.
|
|
85
|
+
attr_reader answer: Array[bool?]
|
|
86
|
+
|
|
87
|
+
def add_clause: (Integer i, boolish f, Integer j, boolish g) -> nil
|
|
88
|
+
|
|
89
|
+
def satisfiable?: () -> bool
|
|
90
|
+
alias satisfiable satisfiable?
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
class TwoSat = TwoSAT
|
|
94
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# ac-library-rb's math and string algorithms, instance methods of `AcLibraryRb` that a caller reaches by
|
|
2
|
+
# including the module.
|
|
3
|
+
module AcLibraryRb
|
|
4
|
+
# A callable taking two arguments: a `Proc`, a lambda or a `Method`.
|
|
5
|
+
interface _Call2[A, B, R]
|
|
6
|
+
def call: (A, B) -> R
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# An object `Deque#replace` can read elements from.
|
|
10
|
+
interface _ToA[T]
|
|
11
|
+
def to_a: () -> Array[T]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def convolution: (Array[Integer] a, Array[Integer] b, ?mod: Integer, ?k: Integer, ?z: Integer) -> Array[Integer]
|
|
15
|
+
|
|
16
|
+
# `[remainder, modulus]`, or `[0, 0]` when there is no solution.
|
|
17
|
+
def crt: (Array[Integer] r, Array[Integer] m) -> [Integer, Integer]
|
|
18
|
+
|
|
19
|
+
def inv_gcd: (Integer a, Integer b) -> [Integer, Integer]
|
|
20
|
+
|
|
21
|
+
def floor_sum: (Integer n, Integer m, Integer a, Integer b) -> Integer
|
|
22
|
+
|
|
23
|
+
def floor_sum_unsigned: (Integer n, Integer m, Integer a, Integer b) -> Integer
|
|
24
|
+
|
|
25
|
+
def inv_mod: (Integer x, Integer m) -> Integer
|
|
26
|
+
|
|
27
|
+
def _inv_gcd: (Integer a, Integer b) -> [Integer, Integer]
|
|
28
|
+
|
|
29
|
+
def pow_mod: (Integer x, Integer n, Integer m) -> Integer
|
|
30
|
+
|
|
31
|
+
def suffix_array: (String s) -> Array[Integer]
|
|
32
|
+
| (Array[untyped] a, ?Integer? upper) -> Array[Integer]
|
|
33
|
+
|
|
34
|
+
def sa_is: (Array[Integer] s, Integer upper) -> Array[Integer]
|
|
35
|
+
|
|
36
|
+
def sa_is_induce: (Array[Integer] s, Array[bool] ls, Array[Integer] sum_l, Array[Integer] sum_s,
|
|
37
|
+
Array[Integer] lms) -> Array[Integer]
|
|
38
|
+
|
|
39
|
+
def lcp_array: (String | Array[untyped] s, Array[Integer] sa) -> Array[Integer]
|
|
40
|
+
|
|
41
|
+
def z_algorithm: (String | Array[untyped] s) -> Array[Integer]
|
|
42
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module AcLibraryRb
|
|
2
|
+
# An integer modulo the global modulus set by `ModInt.set_mod`.
|
|
3
|
+
class ModInt < ::Numeric
|
|
4
|
+
def self.set_mod: (Integer mod) -> bool
|
|
5
|
+
|
|
6
|
+
def self.mod=: (Integer mod) -> bool
|
|
7
|
+
|
|
8
|
+
def self.mod: () -> Integer
|
|
9
|
+
|
|
10
|
+
def self.raw: (_ToI val) -> ModInt
|
|
11
|
+
|
|
12
|
+
def self.prime?: (Integer n) -> bool
|
|
13
|
+
|
|
14
|
+
def self.inv_gcd: (Integer a, Integer b) -> [Integer, Integer]
|
|
15
|
+
|
|
16
|
+
attr_accessor val: Integer
|
|
17
|
+
alias to_i val
|
|
18
|
+
|
|
19
|
+
def initialize: (?_ToI val) -> void
|
|
20
|
+
|
|
21
|
+
def inc!: () -> self
|
|
22
|
+
|
|
23
|
+
def dec!: () -> self
|
|
24
|
+
|
|
25
|
+
def add!: (_ToI other) -> self
|
|
26
|
+
|
|
27
|
+
def sub!: (_ToI other) -> self
|
|
28
|
+
|
|
29
|
+
def mul!: (_ToI other) -> self
|
|
30
|
+
|
|
31
|
+
def div!: (_ToI other) -> self
|
|
32
|
+
|
|
33
|
+
def +@: () -> self
|
|
34
|
+
|
|
35
|
+
def -@: () -> ModInt
|
|
36
|
+
|
|
37
|
+
# Answers the Integer `0` when the modulus is 1. Declared `ModInt` all the same: a union return reached
|
|
38
|
+
# `1 + m ** 2` as an argument, where overload selection reads a union whole (#1356), typed the sum `Integer`
|
|
39
|
+
# and reported `call.undefined-method` for `.val` on correct code.
|
|
40
|
+
def **: (Integer other) -> ModInt
|
|
41
|
+
alias pow **
|
|
42
|
+
|
|
43
|
+
def inv: () -> ModInt
|
|
44
|
+
|
|
45
|
+
def coerce: (_ToI other) -> [ModInt, ModInt]
|
|
46
|
+
|
|
47
|
+
def +: (_ToI other) -> ModInt
|
|
48
|
+
|
|
49
|
+
def -: (_ToI other) -> ModInt
|
|
50
|
+
|
|
51
|
+
def *: (_ToI other) -> ModInt
|
|
52
|
+
|
|
53
|
+
def /: (_ToI other) -> ModInt
|
|
54
|
+
|
|
55
|
+
def ==: (untyped other) -> bool
|
|
56
|
+
|
|
57
|
+
def pred: () -> ModInt
|
|
58
|
+
|
|
59
|
+
def succ: () -> ModInt
|
|
60
|
+
|
|
61
|
+
def zero?: () -> bool
|
|
62
|
+
|
|
63
|
+
def dup: () -> ModInt
|
|
64
|
+
|
|
65
|
+
def to_int: () -> Integer
|
|
66
|
+
|
|
67
|
+
def to_s: () -> String
|
|
68
|
+
|
|
69
|
+
def inspect: () -> String
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# The core extensions under `ac-library-rb/core_ext/`. `ac-library-rb/modint` loads the `ModInt` conversions;
|
|
2
|
+
# `Integer#divisors` and the `Array` conversions need `ac-library-rb/core_ext/all` (or `integer`).
|
|
3
|
+
class Object
|
|
4
|
+
private
|
|
5
|
+
|
|
6
|
+
def ModInt: (_ToI val) -> AcLibraryRb::ModInt
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class Array[unchecked out Elem]
|
|
10
|
+
def to_fenwick_tree: () -> AcLibraryRb::FenwickTree
|
|
11
|
+
alias to_fetree to_fenwick_tree
|
|
12
|
+
|
|
13
|
+
# The element type is not carried over: a literal array would pin it to the literals it starts with.
|
|
14
|
+
def to_priority_queue: () -> AcLibraryRb::PriorityQueue[untyped]
|
|
15
|
+
alias to_pq to_priority_queue
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class Integer
|
|
19
|
+
# `ModInt#coerce` makes an Integer on the left answer a `ModInt`.
|
|
20
|
+
def +: (AcLibraryRb::ModInt) -> AcLibraryRb::ModInt | ...
|
|
21
|
+
def -: (AcLibraryRb::ModInt) -> AcLibraryRb::ModInt | ...
|
|
22
|
+
def *: (AcLibraryRb::ModInt) -> AcLibraryRb::ModInt | ...
|
|
23
|
+
def /: (AcLibraryRb::ModInt) -> AcLibraryRb::ModInt | ...
|
|
24
|
+
|
|
25
|
+
def divisors: () -> Array[Integer]
|
|
26
|
+
|
|
27
|
+
def each_divisor: () { (Integer) -> void } -> Array[Integer]
|
|
28
|
+
| () -> Enumerator[Integer, Array[Integer]]
|
|
29
|
+
|
|
30
|
+
def to_modint: () -> AcLibraryRb::ModInt
|
|
31
|
+
alias to_m to_modint
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
class String
|
|
35
|
+
def to_modint: () -> AcLibraryRb::ModInt
|
|
36
|
+
alias to_m to_modint
|
|
37
|
+
end
|