rigortype 0.1.18 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +159 -224
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +9 -3
- data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +25 -0
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +32 -23
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +54 -0
- data/lib/rigor/analysis/check_rules/rule_walk.rb +151 -23
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +24 -15
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +9 -3
- data/lib/rigor/analysis/check_rules.rb +756 -132
- data/lib/rigor/analysis/dependency_source_inference/index.rb +4 -7
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +2 -18
- data/lib/rigor/analysis/dependency_source_inference.rb +3 -12
- data/lib/rigor/analysis/diagnostic.rb +8 -0
- data/lib/rigor/analysis/fact_store.rb +5 -4
- data/lib/rigor/analysis/rule_catalog.rb +153 -6
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +19 -18
- data/lib/rigor/analysis/runner/project_pre_passes.rb +13 -9
- data/lib/rigor/analysis/runner.rb +75 -27
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +3 -4
- data/lib/rigor/analysis/worker_session.rb +31 -25
- data/lib/rigor/bleeding_edge.rb +123 -0
- data/lib/rigor/builtins/predefined_constant_refinements.rb +151 -0
- data/lib/rigor/cache/descriptor.rb +86 -8
- data/lib/rigor/cache/rbs_descriptor.rb +2 -1
- data/lib/rigor/cache/store.rb +5 -3
- data/lib/rigor/cli/annotate_command.rb +122 -16
- data/lib/rigor/cli/baseline_command.rb +4 -3
- data/lib/rigor/cli/check_command.rb +118 -16
- data/lib/rigor/cli/coverage_command.rb +148 -16
- data/lib/rigor/cli/coverage_scan.rb +57 -0
- data/lib/rigor/cli/explain_command.rb +2 -0
- data/lib/rigor/cli/lsp_command.rb +3 -7
- data/lib/rigor/cli/mutation_protection_renderer.rb +63 -0
- data/lib/rigor/cli/mutation_protection_report.rb +73 -0
- data/lib/rigor/cli/options.rb +9 -0
- data/lib/rigor/cli/plugins_command.rb +4 -5
- data/lib/rigor/cli/plugins_renderer.rb +0 -2
- data/lib/rigor/cli/protection_renderer.rb +63 -0
- data/lib/rigor/cli/protection_report.rb +68 -0
- data/lib/rigor/cli/show_bleedingedge_command.rb +114 -0
- data/lib/rigor/cli/sig_gen_command.rb +2 -1
- data/lib/rigor/cli/trace_command.rb +2 -1
- data/lib/rigor/cli/triage_command.rb +8 -4
- data/lib/rigor/cli/triage_renderer.rb +15 -1
- data/lib/rigor/cli/type_of_command.rb +1 -1
- data/lib/rigor/cli/type_scan_command.rb +2 -1
- data/lib/rigor/cli.rb +12 -3
- data/lib/rigor/configuration/dependencies.rb +2 -4
- data/lib/rigor/configuration/severity_profile.rb +13 -1
- data/lib/rigor/configuration.rb +100 -6
- data/lib/rigor/environment/bundle_sig_discovery.rb +61 -13
- data/lib/rigor/environment/class_registry.rb +4 -3
- data/lib/rigor/environment/constant_type_cache_holder.rb +43 -0
- data/lib/rigor/environment/lockfile_resolver.rb +1 -1
- data/lib/rigor/environment/rbs_collection_discovery.rb +1 -2
- data/lib/rigor/environment/rbs_coverage_report.rb +2 -1
- data/lib/rigor/environment/rbs_loader.rb +74 -5
- data/lib/rigor/environment.rb +17 -7
- data/lib/rigor/flow_contribution/fact.rb +1 -1
- data/lib/rigor/flow_contribution.rb +3 -5
- data/lib/rigor/inference/acceptance.rb +17 -9
- data/lib/rigor/inference/block_parameter_binder.rb +2 -3
- data/lib/rigor/inference/body_fixpoint.rb +89 -0
- data/lib/rigor/inference/budget_trace.rb +29 -2
- data/lib/rigor/inference/builtins/comparable_catalog.rb +2 -2
- data/lib/rigor/inference/builtins/enumerable_catalog.rb +2 -2
- data/lib/rigor/inference/builtins/method_catalog.rb +19 -0
- data/lib/rigor/inference/builtins/string_catalog.rb +9 -1
- data/lib/rigor/inference/expression_typer.rb +1072 -71
- data/lib/rigor/inference/hkt_body.rb +8 -11
- data/lib/rigor/inference/hkt_body_parser.rb +10 -12
- data/lib/rigor/inference/hkt_registry.rb +10 -11
- data/lib/rigor/inference/macro_block_self_type.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/array_to_h_folding.rb +60 -0
- data/lib/rigor/inference/method_dispatcher/call_context.rb +1 -4
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +210 -35
- data/lib/rigor/inference/method_dispatcher/data_folding.rb +9 -73
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +6 -7
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +10 -16
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +25 -13
- data/lib/rigor/inference/method_dispatcher/member_shape_projection.rb +93 -0
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +1 -3
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +24 -22
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +281 -0
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +71 -0
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +237 -24
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +303 -0
- data/lib/rigor/inference/method_dispatcher.rb +112 -49
- data/lib/rigor/inference/method_parameter_binder.rb +56 -2
- data/lib/rigor/inference/multi_target_binder.rb +46 -3
- data/lib/rigor/inference/mutation_widening.rb +147 -11
- data/lib/rigor/inference/narrowing.rb +284 -53
- data/lib/rigor/inference/parameter_inference_collector.rb +367 -0
- data/lib/rigor/inference/project_patched_methods.rb +4 -7
- data/lib/rigor/inference/project_patched_scanner.rb +2 -13
- data/lib/rigor/inference/protection_scanner.rb +86 -0
- data/lib/rigor/inference/scope_indexer.rb +821 -76
- data/lib/rigor/inference/statement_evaluator.rb +1179 -102
- data/lib/rigor/inference/struct_fold_safety.rb +181 -0
- data/lib/rigor/inference/synthetic_method.rb +7 -7
- data/lib/rigor/inference/synthetic_method_scanner.rb +1 -1
- data/lib/rigor/language_server/completion_provider.rb +6 -12
- data/lib/rigor/language_server/diagnostic_publisher.rb +4 -4
- data/lib/rigor/language_server/document_symbol_provider.rb +3 -3
- data/lib/rigor/language_server/hover_provider.rb +2 -3
- data/lib/rigor/language_server/hover_renderer.rb +2 -11
- data/lib/rigor/language_server/server.rb +9 -17
- data/lib/rigor/language_server.rb +4 -5
- data/lib/rigor/plugin/base.rb +245 -87
- data/lib/rigor/plugin/macro/block_as_method.rb +25 -25
- data/lib/rigor/plugin/macro/heredoc_template.rb +4 -7
- data/lib/rigor/plugin/macro/nested_class_template.rb +9 -7
- data/lib/rigor/plugin/macro/trait_registry.rb +3 -6
- data/lib/rigor/plugin/macro.rb +6 -8
- data/lib/rigor/plugin/manifest.rb +49 -90
- data/lib/rigor/plugin/node_rule_walk.rb +59 -14
- data/lib/rigor/plugin/registry.rb +18 -18
- data/lib/rigor/plugin/type_node_resolver.rb +6 -8
- data/lib/rigor/protection/mutation_scanner.rb +120 -0
- data/lib/rigor/protection/mutator.rb +246 -0
- data/lib/rigor/rbs_extended.rb +24 -36
- data/lib/rigor/reflection.rb +4 -7
- data/lib/rigor/scope/discovery_index.rb +16 -2
- data/lib/rigor/scope.rb +185 -16
- data/lib/rigor/sig_gen/generator.rb +8 -0
- data/lib/rigor/sig_gen/observed_call.rb +3 -3
- data/lib/rigor/sig_gen/writer.rb +40 -2
- data/lib/rigor/source/constant_path.rb +62 -0
- data/lib/rigor/source.rb +1 -0
- data/lib/rigor/triage/catalogue.rb +4 -19
- data/lib/rigor/triage.rb +69 -1
- data/lib/rigor/type/bound_method.rb +2 -11
- data/lib/rigor/type/combinator.rb +45 -3
- data/lib/rigor/type/constant.rb +2 -11
- data/lib/rigor/type/data_class.rb +2 -11
- data/lib/rigor/type/data_instance.rb +2 -11
- data/lib/rigor/type/hash_shape.rb +2 -11
- data/lib/rigor/type/integer_range.rb +2 -11
- data/lib/rigor/type/intersection.rb +2 -11
- data/lib/rigor/type/nominal.rb +2 -11
- data/lib/rigor/type/plain_lattice.rb +37 -0
- data/lib/rigor/type/refined.rb +72 -13
- data/lib/rigor/type/singleton.rb +2 -11
- data/lib/rigor/type/struct_class.rb +75 -0
- data/lib/rigor/type/struct_instance.rb +93 -0
- data/lib/rigor/type/tuple.rb +5 -15
- data/lib/rigor/type.rb +2 -0
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +3 -3
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +16 -32
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +5 -13
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +13 -32
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +11 -17
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +34 -100
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +3 -2
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +13 -30
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +4 -4
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +26 -27
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +5 -7
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +9 -8
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +9 -11
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +8 -9
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +13 -12
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +3 -4
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +8 -8
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +9 -11
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +7 -8
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +18 -49
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +12 -13
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +15 -23
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +4 -4
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +3 -3
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +10 -21
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +2 -4
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +27 -11
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +22 -35
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +4 -6
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +12 -18
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +16 -23
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +0 -1
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +3 -4
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +1 -1
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +1 -1
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +21 -27
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +0 -1
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +3 -23
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +5 -4
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +8 -21
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +1 -1
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +2 -3
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/method_signature.rb +7 -11
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +4 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +6 -9
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +5 -15
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +52 -40
- data/sig/rigor/analysis/fact_store.rbs +3 -0
- data/sig/rigor/inference/builtins/method_catalog.rbs +1 -1
- data/sig/rigor/plugin/base.rbs +5 -2
- data/sig/rigor/plugin/manifest.rbs +1 -2
- data/sig/rigor/scope.rbs +18 -1
- data/sig/rigor/type.rbs +37 -1
- data/sig/rigor.rbs +1 -1
- data/skills/rigor-baseline-reduce/references/01-classify.md +27 -0
- data/skills/rigor-plugin-author/SKILL.md +6 -4
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +22 -17
- data/skills/rigor-project-init/references/03-baseline-and-bugs.md +18 -1
- metadata +25 -2
- data/lib/rigor/plugin/macro/external_file.rb +0 -143
|
@@ -80,6 +80,35 @@ module Rigor
|
|
|
80
80
|
Constant.new(value)
|
|
81
81
|
end
|
|
82
82
|
|
|
83
|
+
# Widens every value-pinned (`Constant`) constituent of `type` to its
|
|
84
|
+
# nominal base (`Constant[1]` -> `Nominal["Integer"]`), recursing
|
|
85
|
+
# through unions and leaving non-pinned constituents untouched.
|
|
86
|
+
# `Constant[nil]` is preserved (no nominal base of interest). Shared
|
|
87
|
+
# by the ADR-55 recursive-return fixpoint and the ADR-56 block /
|
|
88
|
+
# loop-body fixpoint (`BodyFixpoint`) to force convergence on the
|
|
89
|
+
# final permitted iteration.
|
|
90
|
+
def widen_value_pinned(type)
|
|
91
|
+
case type
|
|
92
|
+
when Constant
|
|
93
|
+
type.value.nil? ? type : nominal_of(type.value.class.name)
|
|
94
|
+
when Refined
|
|
95
|
+
# A refinement (`non-empty-string`) is a value-narrowed nominal;
|
|
96
|
+
# widen it to its base so an accumulator whose per-pass result is
|
|
97
|
+
# a bounded refinement converges on the final iteration rather
|
|
98
|
+
# than flooring to `Dynamic[top]` (ADR-56).
|
|
99
|
+
widen_value_pinned(type.base)
|
|
100
|
+
when IntegerRange
|
|
101
|
+
# `int<1, 6>` is likewise a value-narrowed `Integer` (it erases to
|
|
102
|
+
# `Integer` in RBS); widen it so a bounded-int accumulator
|
|
103
|
+
# converges (ADR-56).
|
|
104
|
+
nominal_of("Integer")
|
|
105
|
+
when Union
|
|
106
|
+
union(*type.members.map { |member| widen_value_pinned(member) })
|
|
107
|
+
else
|
|
108
|
+
type
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
83
112
|
# `Object#method(:name)` carrier. Stores the bound
|
|
84
113
|
# `(receiver, method_name)` pair so the dispatcher can
|
|
85
114
|
# substitute the original dispatch at `.call` / `.()` /
|
|
@@ -376,6 +405,21 @@ module Rigor
|
|
|
376
405
|
DataInstance.new(members, class_name)
|
|
377
406
|
end
|
|
378
407
|
|
|
408
|
+
# ADR-48 Struct follow-up — the class object produced by
|
|
409
|
+
# `Struct.new(:x, :y)`. `members` is the ordered Symbol member-name
|
|
410
|
+
# list; `keyword_init` records the `keyword_init:` flag; `class_name`
|
|
411
|
+
# tags the class when known (the named-subclass form).
|
|
412
|
+
def struct_class_of(members:, class_name: nil, keyword_init: false)
|
|
413
|
+
StructClass.new(members, class_name, keyword_init: keyword_init)
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
# ADR-48 Struct follow-up — a `Struct.new` value instance. `members`
|
|
417
|
+
# is the ordered member-name -> value-type map; `class_name` tags the
|
|
418
|
+
# instance's class when known.
|
|
419
|
+
def struct_instance_of(members:, class_name: nil)
|
|
420
|
+
StructInstance.new(members, class_name)
|
|
421
|
+
end
|
|
422
|
+
|
|
379
423
|
# Normalized union. Flattens nested Unions, deduplicates structurally
|
|
380
424
|
# equal members, drops Bot, and collapses 0/1-member results.
|
|
381
425
|
def union(*types)
|
|
@@ -900,9 +944,7 @@ module Rigor
|
|
|
900
944
|
end
|
|
901
945
|
end
|
|
902
946
|
|
|
903
|
-
#
|
|
904
|
-
# `Dynamic[Top]` carrier on the main Ractor at load time.
|
|
905
|
-
# The `untyped` reader above just returns this ivar.
|
|
947
|
+
# Eager-allocated at load time; see `untyped` method comment above.
|
|
906
948
|
@untyped = Dynamic.new(Top.instance)
|
|
907
949
|
end
|
|
908
950
|
end
|
data/lib/rigor/type/constant.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "date"
|
|
4
4
|
require_relative "../trinary"
|
|
5
5
|
require_relative "acceptance_router"
|
|
6
|
+
require_relative "plain_lattice"
|
|
6
7
|
|
|
7
8
|
module Rigor
|
|
8
9
|
module Type
|
|
@@ -100,17 +101,7 @@ module Rigor
|
|
|
100
101
|
end
|
|
101
102
|
end
|
|
102
103
|
|
|
103
|
-
|
|
104
|
-
Trinary.no
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def bot
|
|
108
|
-
Trinary.no
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def dynamic
|
|
112
|
-
Trinary.no
|
|
113
|
-
end
|
|
104
|
+
include Rigor::Type::PlainLattice
|
|
114
105
|
|
|
115
106
|
include Rigor::Type::AcceptanceRouter
|
|
116
107
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require_relative "../trinary"
|
|
4
4
|
require_relative "../value_semantics"
|
|
5
5
|
require_relative "acceptance_router"
|
|
6
|
+
require_relative "plain_lattice"
|
|
6
7
|
|
|
7
8
|
module Rigor
|
|
8
9
|
module Type
|
|
@@ -54,17 +55,7 @@ module Rigor
|
|
|
54
55
|
"singleton(#{class_name || 'Data'})"
|
|
55
56
|
end
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
Trinary.no
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def bot
|
|
62
|
-
Trinary.no
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def dynamic
|
|
66
|
-
Trinary.no
|
|
67
|
-
end
|
|
58
|
+
include Rigor::Type::PlainLattice
|
|
68
59
|
|
|
69
60
|
include Rigor::Type::AcceptanceRouter
|
|
70
61
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require_relative "../trinary"
|
|
4
4
|
require_relative "../value_semantics"
|
|
5
5
|
require_relative "acceptance_router"
|
|
6
|
+
require_relative "plain_lattice"
|
|
6
7
|
|
|
7
8
|
module Rigor
|
|
8
9
|
module Type
|
|
@@ -74,17 +75,7 @@ module Rigor
|
|
|
74
75
|
name
|
|
75
76
|
end
|
|
76
77
|
|
|
77
|
-
|
|
78
|
-
Trinary.no
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def bot
|
|
82
|
-
Trinary.no
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def dynamic
|
|
86
|
-
Trinary.no
|
|
87
|
-
end
|
|
78
|
+
include Rigor::Type::PlainLattice
|
|
88
79
|
|
|
89
80
|
include Rigor::Type::AcceptanceRouter
|
|
90
81
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require_relative "../trinary"
|
|
4
4
|
require_relative "../value_semantics"
|
|
5
5
|
require_relative "acceptance_router"
|
|
6
|
+
require_relative "plain_lattice"
|
|
6
7
|
|
|
7
8
|
module Rigor
|
|
8
9
|
module Type
|
|
@@ -96,17 +97,7 @@ module Rigor
|
|
|
96
97
|
read_only_keys.include?(key)
|
|
97
98
|
end
|
|
98
99
|
|
|
99
|
-
|
|
100
|
-
Trinary.no
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
def bot
|
|
104
|
-
Trinary.no
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def dynamic
|
|
108
|
-
Trinary.no
|
|
109
|
-
end
|
|
100
|
+
include Rigor::Type::PlainLattice
|
|
110
101
|
|
|
111
102
|
include Rigor::Type::AcceptanceRouter
|
|
112
103
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require_relative "../trinary"
|
|
4
4
|
require_relative "../value_semantics"
|
|
5
5
|
require_relative "acceptance_router"
|
|
6
|
+
require_relative "plain_lattice"
|
|
6
7
|
|
|
7
8
|
module Rigor
|
|
8
9
|
module Type
|
|
@@ -103,17 +104,7 @@ module Rigor
|
|
|
103
104
|
"Integer"
|
|
104
105
|
end
|
|
105
106
|
|
|
106
|
-
|
|
107
|
-
Trinary.no
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def bot
|
|
111
|
-
Trinary.no
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
def dynamic
|
|
115
|
-
Trinary.no
|
|
116
|
-
end
|
|
107
|
+
include Rigor::Type::PlainLattice
|
|
117
108
|
|
|
118
109
|
include Rigor::Type::AcceptanceRouter
|
|
119
110
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require_relative "../trinary"
|
|
4
4
|
require_relative "../value_semantics"
|
|
5
5
|
require_relative "acceptance_router"
|
|
6
|
+
require_relative "plain_lattice"
|
|
6
7
|
|
|
7
8
|
module Rigor
|
|
8
9
|
module Type
|
|
@@ -62,17 +63,7 @@ module Rigor
|
|
|
62
63
|
members.first.erase_to_rbs
|
|
63
64
|
end
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
Trinary.no
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def bot
|
|
70
|
-
Trinary.no
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def dynamic
|
|
74
|
-
Trinary.no
|
|
75
|
-
end
|
|
66
|
+
include Rigor::Type::PlainLattice
|
|
76
67
|
|
|
77
68
|
include Rigor::Type::AcceptanceRouter
|
|
78
69
|
|
data/lib/rigor/type/nominal.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require_relative "../trinary"
|
|
4
4
|
require_relative "../value_semantics"
|
|
5
5
|
require_relative "acceptance_router"
|
|
6
|
+
require_relative "plain_lattice"
|
|
6
7
|
|
|
7
8
|
module Rigor
|
|
8
9
|
module Type
|
|
@@ -52,17 +53,7 @@ module Rigor
|
|
|
52
53
|
"#{class_name}[#{rendered}]"
|
|
53
54
|
end
|
|
54
55
|
|
|
55
|
-
|
|
56
|
-
Trinary.no
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def bot
|
|
60
|
-
Trinary.no
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def dynamic
|
|
64
|
-
Trinary.no
|
|
65
|
-
end
|
|
56
|
+
include Rigor::Type::PlainLattice
|
|
66
57
|
|
|
67
58
|
include Rigor::Type::AcceptanceRouter
|
|
68
59
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../trinary"
|
|
4
|
+
|
|
5
|
+
module Rigor
|
|
6
|
+
module Type
|
|
7
|
+
# Supplies the lattice-membership trio for the "plain" carriers — the
|
|
8
|
+
# concrete value types that are neither a lattice extreme (`Top` /
|
|
9
|
+
# `Bot` / `Dynamic`) nor a wrapper that computes membership from an
|
|
10
|
+
# inner type.
|
|
11
|
+
#
|
|
12
|
+
# Every such carrier answers `top` / `bot` / `dynamic` with the same
|
|
13
|
+
# `Trinary.no` ("this value is not that lattice point"), so the trio
|
|
14
|
+
# lived as a byte-identical copy in a dozen carriers. The extremes
|
|
15
|
+
# override the relevant member (`Top#top` / `Bot#bot` /
|
|
16
|
+
# `Dynamic#dynamic` answer `Trinary.yes`) and the delegators (`App`,
|
|
17
|
+
# `Difference`, `Refined`, `Union`) compute `dynamic` from their inner
|
|
18
|
+
# type(s); none of those include this module.
|
|
19
|
+
#
|
|
20
|
+
# Mirrors the existing {AcceptanceRouter} / `ValueSemantics` mixins —
|
|
21
|
+
# narrow trait sharing, never carrier inheritance (which the type-object
|
|
22
|
+
# contract forbids).
|
|
23
|
+
module PlainLattice
|
|
24
|
+
def top
|
|
25
|
+
Trinary.no
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def bot
|
|
29
|
+
Trinary.no
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def dynamic
|
|
33
|
+
Trinary.no
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
data/lib/rigor/type/refined.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "prism"
|
|
4
|
+
|
|
3
5
|
require_relative "../trinary"
|
|
4
6
|
require_relative "../value_semantics"
|
|
5
7
|
require_relative "acceptance_router"
|
|
@@ -104,18 +106,31 @@ module Rigor
|
|
|
104
106
|
# so callers can pass any `Constant#value` without a
|
|
105
107
|
# type-prefilter.
|
|
106
108
|
#
|
|
107
|
-
# Plugin-contributed predicates
|
|
108
|
-
#
|
|
109
|
-
# built-in catalogue.
|
|
109
|
+
# Plugin-contributed predicates are not yet wired; today
|
|
110
|
+
# the table covers the built-in catalogue.
|
|
110
111
|
#
|
|
111
112
|
# Recogniser policy:
|
|
112
113
|
#
|
|
113
|
-
# - `:numeric`
|
|
114
|
-
#
|
|
115
|
-
#
|
|
116
|
-
#
|
|
117
|
-
#
|
|
118
|
-
#
|
|
114
|
+
# - `:numeric` recognises a string that is a *single Ruby
|
|
115
|
+
# numeric literal* — exactly the syntax that, written in
|
|
116
|
+
# Ruby source, evaluates to an `Integer` / `Float` /
|
|
117
|
+
# `Rational` / `Complex`. The recogniser delegates to the
|
|
118
|
+
# real Ruby parser ({Refined.ruby_numeric_literal?} via
|
|
119
|
+
# Prism), so it tracks Ruby's grammar precisely: decimal /
|
|
120
|
+
# `0x` hex / `0o` (or leading-zero) octal / `0b` binary /
|
|
121
|
+
# `0d` decimal integers, underscore digit separators
|
|
122
|
+
# (`1_000`), decimal fractions and scientific floats
|
|
123
|
+
# (`1.5`, `1E-5`), and the `r` rational / `i` imaginary
|
|
124
|
+
# suffixes (`1r`, `2i`, `0xffr`). A single leading sign is
|
|
125
|
+
# folded into the literal (`-1`, `+1.5`), but a doubled
|
|
126
|
+
# sign (`--1`, `++1`) parses as a unary-operator chain — a
|
|
127
|
+
# `CallNode`, not a literal — and is rejected, as are
|
|
128
|
+
# multi-dot junk (`1.2.3`), partial literals (`0x`, `1_`),
|
|
129
|
+
# whitespace-padded strings, and — crucially — non-ASCII
|
|
130
|
+
# "digits" (full-width `1`, superscript `²`, other Unicode
|
|
131
|
+
# number characters): Ruby's lexer only accepts `[0-9]` in
|
|
132
|
+
# a numeric literal, so those are `CallNode`s too. The
|
|
133
|
+
# stricter base-N predicates below remain proper subsets.
|
|
119
134
|
# - `:decimal_int` is "what `Integer(s, 10)` would parse
|
|
120
135
|
# without remainder" — one or more decimal digits,
|
|
121
136
|
# optional leading sign, no whitespace, no fractional
|
|
@@ -127,20 +142,64 @@ module Rigor
|
|
|
127
142
|
# not octal-int-string. This matches the typical user
|
|
128
143
|
# intent — a refinement marks a string that "looks like
|
|
129
144
|
# octal", not "happens to be base-8 valid".
|
|
130
|
-
NUMERIC_STRING_PATTERN = /\A-?\d+(?:\.\d+)?\z/
|
|
131
145
|
DECIMAL_INT_STRING_PATTERN = /\A-?\d+\z/
|
|
132
146
|
OCTAL_INT_STRING_PATTERN = /\A-?(?:0[oO][0-7]+|0[0-7]+)\z/
|
|
133
147
|
HEX_INT_STRING_PATTERN = /\A-?0[xX][0-9a-fA-F]+\z/
|
|
134
|
-
private_constant :
|
|
148
|
+
private_constant :DECIMAL_INT_STRING_PATTERN,
|
|
135
149
|
:OCTAL_INT_STRING_PATTERN, :HEX_INT_STRING_PATTERN
|
|
136
150
|
|
|
151
|
+
# Prism node classes that represent a numeric literal. A
|
|
152
|
+
# string is a numeric-string exactly when the parser reduces
|
|
153
|
+
# the whole input to a single one of these (the leading sign
|
|
154
|
+
# is already folded into the literal by the parser).
|
|
155
|
+
NUMERIC_LITERAL_NODES = [
|
|
156
|
+
Prism::IntegerNode,
|
|
157
|
+
Prism::FloatNode,
|
|
158
|
+
Prism::RationalNode,
|
|
159
|
+
Prism::ImaginaryNode
|
|
160
|
+
].freeze
|
|
161
|
+
private_constant :NUMERIC_LITERAL_NODES
|
|
162
|
+
|
|
163
|
+
# Cheap pre-filter applied before invoking the parser: every
|
|
164
|
+
# Ruby numeric literal starts with an ASCII digit, optionally
|
|
165
|
+
# preceded by exactly one sign. Strings that fail this never
|
|
166
|
+
# reach Prism (the common non-numeric case stays allocation-
|
|
167
|
+
# and parse-free).
|
|
168
|
+
NUMERIC_LITERAL_PREFIX = /\A[+-]?\d/
|
|
169
|
+
private_constant :NUMERIC_LITERAL_PREFIX
|
|
170
|
+
|
|
171
|
+
# @param value [Object] typically a `Constant#value`
|
|
172
|
+
# @return [Boolean] true when `value` is a String that is a
|
|
173
|
+
# single, complete Ruby numeric literal. Total over
|
|
174
|
+
# arbitrary input — never raises (Prism reports malformed
|
|
175
|
+
# input through `errors`, it does not throw).
|
|
176
|
+
def self.ruby_numeric_literal?(value)
|
|
177
|
+
return false unless value.is_a?(String)
|
|
178
|
+
return false if value.empty?
|
|
179
|
+
# A numeric literal carries no whitespace; reject any
|
|
180
|
+
# leading / trailing / interior space so the *whole* string
|
|
181
|
+
# must be the literal (Prism would otherwise accept a
|
|
182
|
+
# trailing-space `"1 "`).
|
|
183
|
+
return false if value.match?(/\s/)
|
|
184
|
+
return false unless value.match?(NUMERIC_LITERAL_PREFIX)
|
|
185
|
+
|
|
186
|
+
result = Prism.parse(value)
|
|
187
|
+
return false unless result.errors.empty?
|
|
188
|
+
|
|
189
|
+
body = result.value.statements&.body
|
|
190
|
+
return false unless body && body.size == 1
|
|
191
|
+
|
|
192
|
+
node = body.first
|
|
193
|
+
NUMERIC_LITERAL_NODES.any? { |klass| node.is_a?(klass) }
|
|
194
|
+
end
|
|
195
|
+
|
|
137
196
|
PREDICATES = {
|
|
138
197
|
lowercase: ->(v) { v.is_a?(String) && v == v.downcase },
|
|
139
198
|
not_lowercase: ->(v) { v.is_a?(String) && v != v.downcase },
|
|
140
199
|
uppercase: ->(v) { v.is_a?(String) && v == v.upcase },
|
|
141
200
|
not_uppercase: ->(v) { v.is_a?(String) && v != v.upcase },
|
|
142
|
-
numeric: ->(v) {
|
|
143
|
-
not_numeric: ->(v) { v.is_a?(String) && !
|
|
201
|
+
numeric: ->(v) { ruby_numeric_literal?(v) },
|
|
202
|
+
not_numeric: ->(v) { v.is_a?(String) && !ruby_numeric_literal?(v) },
|
|
144
203
|
decimal_int: ->(v) { v.is_a?(String) && DECIMAL_INT_STRING_PATTERN.match?(v) },
|
|
145
204
|
octal_int: ->(v) { v.is_a?(String) && OCTAL_INT_STRING_PATTERN.match?(v) },
|
|
146
205
|
hex_int: ->(v) { v.is_a?(String) && HEX_INT_STRING_PATTERN.match?(v) },
|
data/lib/rigor/type/singleton.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require_relative "../trinary"
|
|
4
4
|
require_relative "../value_semantics"
|
|
5
5
|
require_relative "acceptance_router"
|
|
6
|
+
require_relative "plain_lattice"
|
|
6
7
|
|
|
7
8
|
module Rigor
|
|
8
9
|
module Type
|
|
@@ -34,17 +35,7 @@ module Rigor
|
|
|
34
35
|
"singleton(#{class_name})"
|
|
35
36
|
end
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
Trinary.no
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def bot
|
|
42
|
-
Trinary.no
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def dynamic
|
|
46
|
-
Trinary.no
|
|
47
|
-
end
|
|
38
|
+
include Rigor::Type::PlainLattice
|
|
48
39
|
|
|
49
40
|
include Rigor::Type::AcceptanceRouter
|
|
50
41
|
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../trinary"
|
|
4
|
+
require_relative "../value_semantics"
|
|
5
|
+
require_relative "acceptance_router"
|
|
6
|
+
require_relative "plain_lattice"
|
|
7
|
+
|
|
8
|
+
module Rigor
|
|
9
|
+
module Type
|
|
10
|
+
# The class object produced by `Struct.new(:x, :y)` (ADR-48 Struct
|
|
11
|
+
# follow-up). The mutable sibling of {DataClass}: it models the *class*
|
|
12
|
+
# (the value bound to `Point` in `Point = Struct.new(:x, :y)`, or the
|
|
13
|
+
# anonymous superclass in `class Point < Struct.new(:x, :y)`), carrying
|
|
14
|
+
# the ordered member-name list so `Point.new(...)` can materialise a
|
|
15
|
+
# {StructInstance}.
|
|
16
|
+
#
|
|
17
|
+
# `keyword_init` records the `Struct.new(..., keyword_init: true)` flag
|
|
18
|
+
# so `.new` only materialises a precise instance for the matching call
|
|
19
|
+
# form — a positional `.new(1, 2)` on a `keyword_init: true` struct, or
|
|
20
|
+
# a keyword `.new(x: 1)` on a positional struct, is a different runtime
|
|
21
|
+
# shape and must degrade rather than fold a wrong member map.
|
|
22
|
+
#
|
|
23
|
+
# `class_name` carries the binding name when known (the named-subclass
|
|
24
|
+
# form) and is `nil` for the anonymous result of a bare `Struct.new(...)`
|
|
25
|
+
# before it is assigned to a constant.
|
|
26
|
+
#
|
|
27
|
+
# Equality and hashing are structural over the member list, the class
|
|
28
|
+
# name, and the keyword-init flag.
|
|
29
|
+
#
|
|
30
|
+
# See docs/adr/48-data-struct-value-folding.md § "Struct follow-up".
|
|
31
|
+
class StructClass
|
|
32
|
+
attr_reader :members, :class_name, :keyword_init
|
|
33
|
+
|
|
34
|
+
# @param members [Array<Symbol>] ordered member names.
|
|
35
|
+
# @param class_name [String, nil] the bound class name, or nil for
|
|
36
|
+
# the anonymous `Struct.new(...)` result.
|
|
37
|
+
# @param keyword_init [Boolean] the `keyword_init:` flag.
|
|
38
|
+
def initialize(members, class_name = nil, keyword_init: false)
|
|
39
|
+
unless members.is_a?(Array) && members.all?(Symbol)
|
|
40
|
+
raise ArgumentError, "members must be an Array of Symbols, got #{members.inspect}"
|
|
41
|
+
end
|
|
42
|
+
unless class_name.nil? || (class_name.is_a?(String) && !class_name.empty?)
|
|
43
|
+
raise ArgumentError, "class_name must be a non-empty String or nil, got #{class_name.inspect}"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
@members = members.dup.freeze
|
|
47
|
+
@class_name = class_name&.freeze
|
|
48
|
+
@keyword_init = keyword_init ? true : false
|
|
49
|
+
freeze
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def describe(_verbosity = :short)
|
|
53
|
+
return "singleton(#{class_name})" if class_name
|
|
54
|
+
|
|
55
|
+
"Struct.new(#{members.map(&:inspect).join(', ')})"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def erase_to_rbs
|
|
59
|
+
"singleton(#{class_name || 'Struct'})"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
include Rigor::Type::PlainLattice
|
|
63
|
+
|
|
64
|
+
include Rigor::Type::AcceptanceRouter
|
|
65
|
+
|
|
66
|
+
include Rigor::ValueSemantics
|
|
67
|
+
|
|
68
|
+
value_fields :members, :class_name, :keyword_init
|
|
69
|
+
|
|
70
|
+
def inspect
|
|
71
|
+
"#<Rigor::Type::StructClass #{describe(:short)}>"
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../trinary"
|
|
4
|
+
require_relative "../value_semantics"
|
|
5
|
+
require_relative "acceptance_router"
|
|
6
|
+
require_relative "plain_lattice"
|
|
7
|
+
|
|
8
|
+
module Rigor
|
|
9
|
+
module Type
|
|
10
|
+
# A `Struct.new` value instance (ADR-48 Struct follow-up) —
|
|
11
|
+
# `Point.new(1, 2)`. The mutable sibling of {DataInstance}: a closed,
|
|
12
|
+
# total, class-tagged member map (member name -> value type),
|
|
13
|
+
# HashShape-shaped but nominal.
|
|
14
|
+
#
|
|
15
|
+
# Unlike {DataInstance}, a `Struct` instance is **mutable** — `s.x = v`,
|
|
16
|
+
# `s[:x] = v`, and escape can invalidate the member map. The folding
|
|
17
|
+
# tier therefore only projects member reads off a **fresh** instance
|
|
18
|
+
# (the transient receiver of a `.new(...).x` / `.with(...).x` chain,
|
|
19
|
+
# which provably cannot have been mutated between materialisation and
|
|
20
|
+
# the read); a read off a *stored* binding degrades to `Dynamic[top]`
|
|
21
|
+
# rather than fold a possibly-stale member value. Promoting the
|
|
22
|
+
# fold to mutation-free bound locals is the deferred slice 3 (see ADR).
|
|
23
|
+
#
|
|
24
|
+
# That mutability-gating lives in the dispatch tier (`StructFolding`),
|
|
25
|
+
# not the carrier: the carrier itself just records the member map. Like
|
|
26
|
+
# {DataInstance}, non-folded methods project to the `Struct` nominal (or
|
|
27
|
+
# the tagged class) through {RbsDispatch}'s `receiver_descriptor`, so
|
|
28
|
+
# non-member calls resolve without mis-firing undefined-method.
|
|
29
|
+
#
|
|
30
|
+
# Equality and hashing are structural over the (member -> type) map and
|
|
31
|
+
# the class name.
|
|
32
|
+
#
|
|
33
|
+
# See docs/adr/48-data-struct-value-folding.md § "Struct follow-up".
|
|
34
|
+
class StructInstance
|
|
35
|
+
attr_reader :members, :class_name
|
|
36
|
+
|
|
37
|
+
# @param members [Hash{Symbol => Rigor::Type}] ordered member -> type
|
|
38
|
+
# map. Every declared member is present (Struct instances are total).
|
|
39
|
+
# @param class_name [String, nil] the tagging class name, or nil for
|
|
40
|
+
# an instance of an anonymous `Struct.new(...)` class.
|
|
41
|
+
def initialize(members, class_name = nil)
|
|
42
|
+
unless members.is_a?(Hash) && members.each_key.all?(Symbol)
|
|
43
|
+
raise ArgumentError, "members must be a Hash with Symbol keys, got #{members.inspect}"
|
|
44
|
+
end
|
|
45
|
+
unless class_name.nil? || (class_name.is_a?(String) && !class_name.empty?)
|
|
46
|
+
raise ArgumentError, "class_name must be a non-empty String or nil, got #{class_name.inspect}"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
@members = members.dup.freeze
|
|
50
|
+
@class_name = class_name&.freeze
|
|
51
|
+
freeze
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @return [Array<Symbol>] ordered member names.
|
|
55
|
+
def member_names
|
|
56
|
+
members.keys
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# @return [Rigor::Type, nil] the member's value type, or nil when the
|
|
60
|
+
# name is not a declared member.
|
|
61
|
+
def member_type(name)
|
|
62
|
+
members[name]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def describe(verbosity = :short)
|
|
66
|
+
rendered = members.map { |name, type| "#{name}: #{type.describe(verbosity)}" }
|
|
67
|
+
"#{class_name || 'Struct'}(#{rendered.join(', ')})"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Erases to the tagging class nominal (conservative: the structural
|
|
71
|
+
# members are not RBS-expressible as a class instance). The
|
|
72
|
+
# anonymous case erases to the `Struct` supertype.
|
|
73
|
+
def erase_to_rbs
|
|
74
|
+
name = class_name
|
|
75
|
+
return "Struct" if name.nil?
|
|
76
|
+
|
|
77
|
+
name
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
include Rigor::Type::PlainLattice
|
|
81
|
+
|
|
82
|
+
include Rigor::Type::AcceptanceRouter
|
|
83
|
+
|
|
84
|
+
include Rigor::ValueSemantics
|
|
85
|
+
|
|
86
|
+
value_fields :members, :class_name
|
|
87
|
+
|
|
88
|
+
def inspect
|
|
89
|
+
"#<Rigor::Type::StructInstance #{describe(:short)}>"
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
data/lib/rigor/type/tuple.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require_relative "../trinary"
|
|
4
4
|
require_relative "../value_semantics"
|
|
5
5
|
require_relative "acceptance_router"
|
|
6
|
+
require_relative "plain_lattice"
|
|
6
7
|
|
|
7
8
|
module Rigor
|
|
8
9
|
module Type
|
|
@@ -17,10 +18,9 @@ module Rigor
|
|
|
17
18
|
#
|
|
18
19
|
# Slice 5 phase 1 introduces the carrier and surfaces it from the
|
|
19
20
|
# `ArrayNode` literal handler when every element is a non-splat
|
|
20
|
-
# value. Tuple-aware refinements
|
|
21
|
-
# destructuring
|
|
22
|
-
#
|
|
23
|
-
# {Rigor::Inference::MethodDispatcher::RbsDispatch}.
|
|
21
|
+
# value. Tuple-aware refinements (`tuple[0]`, `tuple.first`,
|
|
22
|
+
# destructuring) are implemented in `ShapeDispatch`, which runs
|
|
23
|
+
# above {Rigor::Inference::MethodDispatcher::RbsDispatch}.
|
|
24
24
|
#
|
|
25
25
|
# Equality and hashing are structural across an ordered, frozen
|
|
26
26
|
# element list. The empty Tuple `Tuple[]` is permitted; the array
|
|
@@ -53,17 +53,7 @@ module Rigor
|
|
|
53
53
|
"[#{elements.map(&:erase_to_rbs).join(', ')}]"
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
Trinary.no
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def bot
|
|
61
|
-
Trinary.no
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def dynamic
|
|
65
|
-
Trinary.no
|
|
66
|
-
end
|
|
56
|
+
include Rigor::Type::PlainLattice
|
|
67
57
|
|
|
68
58
|
include Rigor::Type::AcceptanceRouter
|
|
69
59
|
|
data/lib/rigor/type.rb
CHANGED
|
@@ -21,6 +21,8 @@ require_relative "type/tuple"
|
|
|
21
21
|
require_relative "type/hash_shape"
|
|
22
22
|
require_relative "type/data_class"
|
|
23
23
|
require_relative "type/data_instance"
|
|
24
|
+
require_relative "type/struct_class"
|
|
25
|
+
require_relative "type/struct_instance"
|
|
24
26
|
require_relative "type/union"
|
|
25
27
|
require_relative "type/difference"
|
|
26
28
|
require_relative "type/refined"
|
data/lib/rigor/version.rb
CHANGED
|
@@ -26,7 +26,7 @@ module Rigor
|
|
|
26
26
|
# `stream_for` call) so the analyzer knows it can't
|
|
27
27
|
# be sure of every stream name.
|
|
28
28
|
#
|
|
29
|
-
#
|
|
29
|
+
# Intentional limitations:
|
|
30
30
|
#
|
|
31
31
|
# - Direct-superclass match only.
|
|
32
32
|
# - Public-vs-private is not tracked; the framework
|