rigortype 0.1.19 → 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/lib/rigor/analysis/check_rules/ivar_write_collector.rb +3 -23
- data/lib/rigor/analysis/check_rules/rule_walk.rb +3 -21
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +24 -15
- data/lib/rigor/analysis/check_rules.rb +492 -71
- 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/fact_store.rb +5 -4
- data/lib/rigor/analysis/rule_catalog.rb +153 -6
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +17 -17
- data/lib/rigor/analysis/runner/project_pre_passes.rb +9 -8
- data/lib/rigor/analysis/runner.rb +17 -6
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +3 -4
- data/lib/rigor/analysis/worker_session.rb +10 -14
- data/lib/rigor/builtins/predefined_constant_refinements.rb +151 -0
- data/lib/rigor/cache/store.rb +5 -3
- data/lib/rigor/cli/annotate_command.rb +28 -7
- data/lib/rigor/cli/baseline_command.rb +4 -3
- data/lib/rigor/cli/check_command.rb +115 -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 +2 -1
- data/lib/rigor/cli/protection_renderer.rb +63 -0
- data/lib/rigor/cli/protection_report.rb +68 -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 +2 -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 +3 -2
- data/lib/rigor/configuration/dependencies.rb +2 -4
- data/lib/rigor/configuration.rb +45 -7
- 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 +49 -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/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 +20 -28
- 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/method_dispatcher/call_context.rb +1 -4
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +156 -21
- 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/shape_dispatch.rb +90 -15
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +303 -0
- data/lib/rigor/inference/method_dispatcher.rb +40 -48
- data/lib/rigor/inference/mutation_widening.rb +5 -11
- data/lib/rigor/inference/narrowing.rb +14 -16
- 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 +129 -55
- data/lib/rigor/inference/statement_evaluator.rb +244 -114
- data/lib/rigor/inference/struct_fold_safety.rb +181 -0
- data/lib/rigor/inference/synthetic_method.rb +7 -7
- 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 +10 -8
- data/lib/rigor/plugin/macro/block_as_method.rb +3 -4
- data/lib/rigor/plugin/macro/heredoc_template.rb +4 -7
- data/lib/rigor/plugin/macro/trait_registry.rb +3 -6
- data/lib/rigor/plugin/macro.rb +4 -5
- data/lib/rigor/plugin/manifest.rb +45 -66
- data/lib/rigor/plugin/registry.rb +6 -7
- 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 +14 -2
- data/lib/rigor/scope.rb +54 -11
- 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/type/bound_method.rb +2 -11
- data/lib/rigor/type/combinator.rb +16 -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 +3 -3
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +5 -13
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +11 -17
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +7 -10
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +3 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +4 -4
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +6 -8
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +5 -7
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +1 -2
- 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 +7 -9
- 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 +3 -3
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +3 -3
- 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 +1 -1
- 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 +5 -5
- 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 +19 -14
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +0 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +5 -4
- 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 +28 -41
- data/sig/rigor/scope.rbs +9 -1
- data/sig/rigor/type.rbs +36 -1
- metadata +19 -1
data/lib/rigor/rbs_extended.rb
CHANGED
|
@@ -7,43 +7,30 @@ require_relative "rbs_extended/reporter"
|
|
|
7
7
|
require_relative "rbs_extended/hkt_directives"
|
|
8
8
|
|
|
9
9
|
module Rigor
|
|
10
|
-
#
|
|
11
|
-
# `RBS::Extended` annotation surface described in
|
|
10
|
+
# Reader for the `RBS::Extended` annotation surface described in
|
|
12
11
|
# `docs/type-specification/rbs-extended.md`.
|
|
13
12
|
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
# consume. v0.0.2 recognises:
|
|
13
|
+
# Reads `%a{rigor:v1:<directive> <payload>}` annotations off RBS
|
|
14
|
+
# method definitions and returns well-typed effect objects the
|
|
15
|
+
# inference engine can consume. Implemented directives:
|
|
18
16
|
#
|
|
19
|
-
# - `rigor:v1:predicate-if-true <target> is <ClassName>`
|
|
20
|
-
# - `rigor:v1:predicate-if-false <target> is <ClassName>`
|
|
21
|
-
# - `rigor:v1:assert <target> is <ClassName>`
|
|
22
|
-
# - `rigor:v1:assert-if-true <target> is <ClassName>`
|
|
23
|
-
# - `rigor:v1:assert-if-false <target> is <ClassName>`
|
|
17
|
+
# - `rigor:v1:predicate-if-true <target> is <ClassName|refinement>`
|
|
18
|
+
# - `rigor:v1:predicate-if-false <target> is <ClassName|refinement>`
|
|
19
|
+
# - `rigor:v1:assert <target> is <ClassName|refinement>`
|
|
20
|
+
# - `rigor:v1:assert-if-true <target> is <ClassName|refinement>`
|
|
21
|
+
# - `rigor:v1:assert-if-false <target> is <ClassName|refinement>`
|
|
22
|
+
# - `rigor:v1:param <name> <type-expr>` — per-call param narrowing
|
|
23
|
+
# - `rigor:v1:return <type-expr>` — per-call return override
|
|
24
|
+
# - `rigor:v1:conforms-to <InterfaceName>` — structural conformance
|
|
24
25
|
#
|
|
25
|
-
# `predicate-if-*` fires when the call is used as an
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
# `target: self` narrowing, ...) remain on the v0.0.x
|
|
34
|
-
# roadmap. Annotations whose key is in the `rigor:v1:`
|
|
35
|
-
# namespace but whose directive is unrecognised are
|
|
36
|
-
# silently ignored at first-preview quality (a future slice
|
|
37
|
-
# MAY surface them as diagnostics-on-Rigor-itself per the
|
|
38
|
-
# spec's "unsupported metadata" guidance).
|
|
39
|
-
#
|
|
40
|
-
# The parser is minimal: it accepts a strict shape
|
|
41
|
-
# `<target> is <ClassName>` where `<target>` is a Ruby
|
|
42
|
-
# identifier (parameter name) or `self`, and `<ClassName>`
|
|
43
|
-
# is a single non-namespaced class identifier or a
|
|
44
|
-
# `::Foo::Bar` style constant path. Negative refinements
|
|
45
|
-
# (`~T`), intersections, and unions are deferred to the
|
|
46
|
-
# next iteration.
|
|
26
|
+
# `predicate-if-*` fires when the call is used as an `if` / `unless`
|
|
27
|
+
# condition; `assert` fires unconditionally at the call's post-scope;
|
|
28
|
+
# `assert-if-true` / `assert-if-false` fire at the post-scope only
|
|
29
|
+
# when the call's return value can be observed as truthy / falsey.
|
|
30
|
+
# Negation (`~T`) is supported for both class-name and refinement
|
|
31
|
+
# right-hand sides. Parameterised refinements (`non-empty-array[T]`)
|
|
32
|
+
# are also recognised. Annotations whose directive is unrecognised
|
|
33
|
+
# are silently ignored per the spec's "unsupported metadata" guidance.
|
|
47
34
|
module RbsExtended # rubocop:disable Metrics/ModuleLength
|
|
48
35
|
DIRECTIVE_PREFIX = "rigor:v1:"
|
|
49
36
|
|
|
@@ -58,9 +45,10 @@ module Rigor
|
|
|
58
45
|
# a kebab-case refinement name (`non-empty-string`,
|
|
59
46
|
# `lowercase-string`, …) instead of a Capitalised class
|
|
60
47
|
# name. The narrowing tier substitutes the carrier for the
|
|
61
|
-
# current local type; `class_name` is then nil
|
|
62
|
-
#
|
|
63
|
-
#
|
|
48
|
+
# current local type; `class_name` is then nil. `negative`
|
|
49
|
+
# may be true for refinement-form directives — `~T` negation
|
|
50
|
+
# is supported; the narrowing tier computes the complement
|
|
51
|
+
# decomposition (see `AssertEffect` docs below).
|
|
64
52
|
class PredicateEffect < Data.define(:edge, :target_kind, :target_name, :class_name, :negative, :refinement_type)
|
|
65
53
|
def truthy_only? = edge == :truthy_only
|
|
66
54
|
def falsey_only? = edge == :falsey_only
|
data/lib/rigor/reflection.rb
CHANGED
|
@@ -17,11 +17,8 @@ module Rigor
|
|
|
17
17
|
# classes / modules, in-source constants, discovered method
|
|
18
18
|
# nodes, class ivar / cvar declarations).
|
|
19
19
|
#
|
|
20
|
-
# This module is the **stable read shape**
|
|
21
|
-
#
|
|
22
|
-
# calls out a unified reflection layer as a prerequisite for the
|
|
23
|
-
# extension protocols, and `docs/design/20260505-v0.1.0-readiness.md`
|
|
24
|
-
# nominates this module as the highest-leverage cold-start slice.
|
|
20
|
+
# This module is the **stable read shape** the plugin API is
|
|
21
|
+
# designed against (ADR-2, `docs/adr/2-extension-api.md`).
|
|
25
22
|
#
|
|
26
23
|
# The facade is **read-only and additive**. Existing call sites
|
|
27
24
|
# that read directly from `Rigor::Scope` or
|
|
@@ -52,8 +49,8 @@ module Rigor
|
|
|
52
49
|
# defined in the analyzed sources?
|
|
53
50
|
#
|
|
54
51
|
# The provenance side of the API (which source family contributed
|
|
55
|
-
# each fact) is explicitly out of scope for the v0.0.7 first
|
|
56
|
-
#
|
|
52
|
+
# each fact) is explicitly out of scope for the v0.0.7 first pass;
|
|
53
|
+
# v0.1.0's plugin API added it as a separate concern.
|
|
57
54
|
module Reflection
|
|
58
55
|
module_function
|
|
59
56
|
|
|
@@ -28,7 +28,9 @@ module Rigor
|
|
|
28
28
|
:discovered_superclasses,
|
|
29
29
|
:discovered_includes,
|
|
30
30
|
:discovered_class_sources,
|
|
31
|
-
:data_member_layouts
|
|
31
|
+
:data_member_layouts,
|
|
32
|
+
:struct_member_layouts,
|
|
33
|
+
:param_inferred_types
|
|
32
34
|
)
|
|
33
35
|
|
|
34
36
|
class DiscoveryIndex
|
|
@@ -53,7 +55,17 @@ module Rigor
|
|
|
53
55
|
discovered_superclasses: EMPTY_TABLE,
|
|
54
56
|
discovered_includes: EMPTY_TABLE,
|
|
55
57
|
discovered_class_sources: EMPTY_TABLE,
|
|
56
|
-
data_member_layouts: EMPTY_TABLE
|
|
58
|
+
data_member_layouts: EMPTY_TABLE,
|
|
59
|
+
struct_member_layouts: EMPTY_TABLE,
|
|
60
|
+
# ADR-67 WD3 — the call-site parameter-inference table, keyed by
|
|
61
|
+
# `[class_name, method_name, kind]` (the same `(class, method, kind)`
|
|
62
|
+
# triple {Inference::ParameterInferenceCollector} records and that
|
|
63
|
+
# `build_method_entry_scope` reconstructs from the lexical class path).
|
|
64
|
+
# The value is a `{param_name(Symbol) => Rigor::Type}` map of the union
|
|
65
|
+
# of resolved call-site argument types. Empty on every normal run; only
|
|
66
|
+
# the `coverage --protection` collection pass populates it today, so a
|
|
67
|
+
# `check` run leaves it empty and seeds nothing (byte-identical).
|
|
68
|
+
param_inferred_types: EMPTY_TABLE
|
|
57
69
|
)
|
|
58
70
|
end
|
|
59
71
|
end
|
data/lib/rigor/scope.rb
CHANGED
|
@@ -23,7 +23,7 @@ module Rigor
|
|
|
23
23
|
:ivars, :cvars, :globals,
|
|
24
24
|
:indexed_narrowings, :method_chain_narrowings,
|
|
25
25
|
:declaration_sourced,
|
|
26
|
-
:source_path, :discovery
|
|
26
|
+
:source_path, :discovery, :struct_fold_safe_locals
|
|
27
27
|
|
|
28
28
|
# ADR-53 Track A — the seed-time discovery tables live on the
|
|
29
29
|
# {DiscoveryIndex} the scope carries by a single reference; the
|
|
@@ -51,6 +51,13 @@ module Rigor
|
|
|
51
51
|
def discovered_includes = @discovery.discovered_includes
|
|
52
52
|
def discovered_class_sources = @discovery.discovered_class_sources
|
|
53
53
|
def data_member_layouts = @discovery.data_member_layouts
|
|
54
|
+
def struct_member_layouts = @discovery.struct_member_layouts
|
|
55
|
+
# ADR-67 WD3 — call-site-inferred parameter types, keyed by
|
|
56
|
+
# `[class_name, method_name, kind]`. `build_method_entry_scope` consults
|
|
57
|
+
# this to seed an undeclared `def` parameter with the union of its
|
|
58
|
+
# resolved call-site argument types (precision-additive; an RBS-declared
|
|
59
|
+
# parameter always wins). Empty unless a collection pass seeded it.
|
|
60
|
+
def param_inferred_types = @discovery.param_inferred_types
|
|
54
61
|
|
|
55
62
|
# Narrowing key for an indexed read `receiver[key]` where both
|
|
56
63
|
# the receiver and the key are stable enough to address. The
|
|
@@ -99,8 +106,14 @@ module Rigor
|
|
|
99
106
|
# principle. Any flow-live touch (write / narrowing) drops the mark, so
|
|
100
107
|
# the diagnostic keeps firing exactly as before on flow-observed nil.
|
|
101
108
|
EMPTY_DECLARATION_SOURCED = Set.new.freeze
|
|
109
|
+
# ADR-48 Struct slice 3 — the per-body set of local names whose struct
|
|
110
|
+
# member reads are fold-safe (provably never mutated / aliased / escaped).
|
|
111
|
+
# A static per-scope context like {#source_path}: inherited unchanged
|
|
112
|
+
# through flow transitions and ignored by `==` / `hash`.
|
|
113
|
+
EMPTY_FOLD_SAFE = Set.new.freeze
|
|
102
114
|
private_constant :EMPTY_VAR_BINDINGS, :EMPTY_INDEXED_NARROWINGS,
|
|
103
|
-
:EMPTY_CHAIN_NARROWINGS, :EMPTY_DECLARATION_SOURCED
|
|
115
|
+
:EMPTY_CHAIN_NARROWINGS, :EMPTY_DECLARATION_SOURCED,
|
|
116
|
+
:EMPTY_FOLD_SAFE
|
|
104
117
|
|
|
105
118
|
class << self
|
|
106
119
|
def empty(environment: Environment.default, source_path: nil)
|
|
@@ -120,7 +133,8 @@ module Rigor
|
|
|
120
133
|
indexed_narrowings: EMPTY_INDEXED_NARROWINGS,
|
|
121
134
|
method_chain_narrowings: EMPTY_CHAIN_NARROWINGS,
|
|
122
135
|
declaration_sourced: EMPTY_DECLARATION_SOURCED,
|
|
123
|
-
source_path: nil
|
|
136
|
+
source_path: nil,
|
|
137
|
+
struct_fold_safe_locals: EMPTY_FOLD_SAFE
|
|
124
138
|
)
|
|
125
139
|
@environment = environment
|
|
126
140
|
@locals = locals
|
|
@@ -134,6 +148,7 @@ module Rigor
|
|
|
134
148
|
@method_chain_narrowings = method_chain_narrowings
|
|
135
149
|
@declaration_sourced = declaration_sourced
|
|
136
150
|
@source_path = source_path
|
|
151
|
+
@struct_fold_safe_locals = struct_fold_safe_locals
|
|
137
152
|
freeze
|
|
138
153
|
end
|
|
139
154
|
|
|
@@ -180,17 +195,29 @@ module Rigor
|
|
|
180
195
|
rebuild(self_type: type)
|
|
181
196
|
end
|
|
182
197
|
|
|
183
|
-
# ADR-
|
|
184
|
-
#
|
|
185
|
-
#
|
|
186
|
-
#
|
|
187
|
-
#
|
|
188
|
-
# file does this call site belong to?" without
|
|
198
|
+
# ADR-28 / ADR-52 slice 5a — per-file source path carried on
|
|
199
|
+
# the scope. The analyzer stamps the current file's path onto
|
|
200
|
+
# the seed scope; nested rebuilds propagate it so plugin rules
|
|
201
|
+
# (`dynamic_return`'s `file_methods:` gate, sigil checks) can
|
|
202
|
+
# resolve "which file does this call site belong to?" without
|
|
189
203
|
# thread-locals.
|
|
190
204
|
def with_source_path(path)
|
|
191
205
|
rebuild(source_path: path)
|
|
192
206
|
end
|
|
193
207
|
|
|
208
|
+
# ADR-48 Struct slice 3 — installs the per-body fold-safe-local set
|
|
209
|
+
# ({Inference::StructFoldSafety}). Set once at body entry; inherited
|
|
210
|
+
# unchanged through subsequent flow transitions.
|
|
211
|
+
def with_struct_fold_safe(locals)
|
|
212
|
+
rebuild(struct_fold_safe_locals: locals)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# True when `name`'s `Struct` member reads are fold-safe in this body
|
|
216
|
+
# (the local is provably never mutated / aliased / escaped).
|
|
217
|
+
def struct_fold_safe?(name)
|
|
218
|
+
@struct_fold_safe_locals.include?(name.to_sym)
|
|
219
|
+
end
|
|
220
|
+
|
|
194
221
|
# ADR-53 Track A — swaps the whole discovery index in one transition.
|
|
195
222
|
# The sole seeding path; the per-table writers it replaced are derived
|
|
196
223
|
# off-`Scope` through `scope.discovery.with(table_name: table)`.
|
|
@@ -484,6 +511,20 @@ module Rigor
|
|
|
484
511
|
layout
|
|
485
512
|
end
|
|
486
513
|
|
|
514
|
+
# ADR-48 Struct follow-up — the `{ members:, keyword_init: }` layout
|
|
515
|
+
# recorded for a `Struct.new(...)`-defined class, in the constant form
|
|
516
|
+
# (`Point = Struct.new(:x, :y)`) and the named-subclass form
|
|
517
|
+
# (`class Point < Struct.new(:x, :y)`). Consumed by
|
|
518
|
+
# {Inference::MethodDispatcher::StructFolding} so `Point.new(...)` on a
|
|
519
|
+
# `Singleton[Point]` receiver materialises a member instance. Returns nil
|
|
520
|
+
# when the class has no recorded struct layout. Mirrors
|
|
521
|
+
# {#data_member_layout}'s dependency-recording contract.
|
|
522
|
+
def struct_member_layout(class_name)
|
|
523
|
+
layout = @discovery.struct_member_layouts[class_name.to_s]
|
|
524
|
+
record_class_dependency(class_name) if layout && Analysis::DependencyRecorder.active?
|
|
525
|
+
layout
|
|
526
|
+
end
|
|
527
|
+
|
|
487
528
|
# ADR-24 slice 2 — per-class/module table mapping a fully
|
|
488
529
|
# qualified user class or module to the list of module
|
|
489
530
|
# names it `include`s / `prepend`s, AS WRITTEN at the
|
|
@@ -674,7 +715,8 @@ module Rigor
|
|
|
674
715
|
indexed_narrowings: @indexed_narrowings,
|
|
675
716
|
method_chain_narrowings: @method_chain_narrowings,
|
|
676
717
|
declaration_sourced: @declaration_sourced,
|
|
677
|
-
source_path: @source_path
|
|
718
|
+
source_path: @source_path,
|
|
719
|
+
struct_fold_safe_locals: @struct_fold_safe_locals
|
|
678
720
|
)
|
|
679
721
|
self.class.new(
|
|
680
722
|
environment: environment, locals: locals,
|
|
@@ -684,7 +726,8 @@ module Rigor
|
|
|
684
726
|
indexed_narrowings: indexed_narrowings,
|
|
685
727
|
method_chain_narrowings: method_chain_narrowings,
|
|
686
728
|
declaration_sourced: declaration_sourced,
|
|
687
|
-
source_path: source_path
|
|
729
|
+
source_path: source_path,
|
|
730
|
+
struct_fold_safe_locals: struct_fold_safe_locals
|
|
688
731
|
)
|
|
689
732
|
end
|
|
690
733
|
|
|
@@ -5,9 +5,9 @@ module Rigor
|
|
|
5
5
|
# Per-call-site argument observation produced by
|
|
6
6
|
# {ObservationCollector}. ADR-14 follow-up: the earlier
|
|
7
7
|
# MVP shape (`Array[Type]` of positional types only)
|
|
8
|
-
# could not represent keyword arguments —
|
|
9
|
-
# `MethodCatalog.new(path: ..., mutating_selectors: ...)`
|
|
10
|
-
#
|
|
8
|
+
# could not represent keyword arguments — keyword calls
|
|
9
|
+
# like `MethodCatalog.new(path: ..., mutating_selectors: ...)`
|
|
10
|
+
# were silently skipped in that shape.
|
|
11
11
|
# The new shape carries positional and keyword arg types
|
|
12
12
|
# in parallel so the per-position / per-keyword unions
|
|
13
13
|
# can each be reconstructed independently.
|
data/lib/rigor/sig_gen/writer.rb
CHANGED
|
@@ -46,6 +46,11 @@ module Rigor
|
|
|
46
46
|
def initialize(path_mapper:, overwrite: false)
|
|
47
47
|
@path_mapper = path_mapper
|
|
48
48
|
@overwrite = overwrite
|
|
49
|
+
# Run-level (cross-file) namespace-kind view, populated
|
|
50
|
+
# per `#write_all` from every candidate's per-file map.
|
|
51
|
+
# Empty until then so the single-target `#write` path
|
|
52
|
+
# falls back to per-candidate kinds only.
|
|
53
|
+
@global_namespace_kinds = {}
|
|
49
54
|
end
|
|
50
55
|
|
|
51
56
|
# Process the full candidate list by resolving each
|
|
@@ -65,6 +70,7 @@ module Rigor
|
|
|
65
70
|
emittable = candidates.select { |c| EMITTABLE.include?(c.classification) }
|
|
66
71
|
return [] if emittable.empty?
|
|
67
72
|
|
|
73
|
+
@global_namespace_kinds = build_namespace_kinds(candidates)
|
|
68
74
|
emittable.group_by { |c| @path_mapper.target_for(c.path, class_name: c.class_name) }
|
|
69
75
|
.map { |target, group| write_target(target, group) }
|
|
70
76
|
end
|
|
@@ -161,13 +167,45 @@ module Rigor
|
|
|
161
167
|
end
|
|
162
168
|
|
|
163
169
|
def merged_namespace_kinds(candidates)
|
|
164
|
-
merged =
|
|
170
|
+
merged = @global_namespace_kinds.dup
|
|
165
171
|
candidates.each do |c|
|
|
166
|
-
(c.namespace_kinds || {}).each { |k, v| merged
|
|
172
|
+
(c.namespace_kinds || {}).each { |k, v| apply_namespace_kind(merged, k, v) }
|
|
167
173
|
end
|
|
168
174
|
merged
|
|
169
175
|
end
|
|
170
176
|
|
|
177
|
+
# Folds every candidate's per-file namespace-kind map
|
|
178
|
+
# into one run-level view so a `class Foo` recorded
|
|
179
|
+
# while scanning `foo.rb` governs the wrapper keyword
|
|
180
|
+
# emitted for `Foo` in a *sibling* file's target — e.g.
|
|
181
|
+
# `foo/bar.rb` declaring `class Foo::Bar`, whose compact
|
|
182
|
+
# constant path never names `Foo`, so the walker records
|
|
183
|
+
# no kind for it. Without this view that sibling target
|
|
184
|
+
# wraps the nested class in `module Foo` while `foo.rbs`
|
|
185
|
+
# declares `class Foo`; loading both raises
|
|
186
|
+
# `RBS::DuplicatedDeclarationError`, aborting the whole
|
|
187
|
+
# RBS env build.
|
|
188
|
+
def build_namespace_kinds(candidates)
|
|
189
|
+
candidates.each_with_object({}) do |candidate, acc|
|
|
190
|
+
(candidate.namespace_kinds || {}).each { |name, kind| apply_namespace_kind(acc, name, kind) }
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# A `class` declaration is authoritative and MUST win
|
|
195
|
+
# over the `:module` wrapper default: a compact
|
|
196
|
+
# `class Foo::Bar` never names `Foo`, so the only signal
|
|
197
|
+
# for `Foo`'s kind is an actual `class Foo` (or
|
|
198
|
+
# `Const = Data.define(...)` shell) seen elsewhere. This
|
|
199
|
+
# guarantees the generated tree never mixes `class` /
|
|
200
|
+
# `module` for the same constant.
|
|
201
|
+
def apply_namespace_kind(map, key, kind)
|
|
202
|
+
if kind == :class
|
|
203
|
+
map[key] = :class
|
|
204
|
+
else
|
|
205
|
+
map[key] ||= :module
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
171
209
|
# Tree node: { name:, children: Hash{String => node},
|
|
172
210
|
# methods: Array<MethodCandidate>, shell: Boolean }.
|
|
173
211
|
# `shell` flags nodes that came in via `class_shells`
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rigor
|
|
4
|
+
module Source
|
|
5
|
+
# Flattens a Prism constant-reference node (`ConstantReadNode` /
|
|
6
|
+
# `ConstantPathNode`) to its source-qualified `"A::B::C"` string.
|
|
7
|
+
#
|
|
8
|
+
# Two nil policies for the one edge case that distinguishes the call
|
|
9
|
+
# sites — a constant path rooted in a *dynamic* base (`expr::Bar`, where
|
|
10
|
+
# the left side is a runtime expression rather than a constant):
|
|
11
|
+
#
|
|
12
|
+
# * {.qualified_name} / {.render} are LENIENT — they drop the dynamic
|
|
13
|
+
# segment and render the trailing constant names (`expr::Bar` => "Bar").
|
|
14
|
+
# The scope indexer and statement evaluator feed only genuine
|
|
15
|
+
# class/module path nodes and want a best-effort name.
|
|
16
|
+
# * {.qualified_name_or_nil} is STRICT — a dynamic base anywhere in the
|
|
17
|
+
# chain yields `nil`, so a caller that statically names constants can
|
|
18
|
+
# treat the path as opaque rather than guessing.
|
|
19
|
+
#
|
|
20
|
+
# A leading `::` (absolute root, `::Foo`) renders as `"Foo"` under both
|
|
21
|
+
# policies. A node that is neither a `ConstantReadNode` nor a
|
|
22
|
+
# `ConstantPathNode` yields `nil` under both.
|
|
23
|
+
module ConstantPath
|
|
24
|
+
module_function
|
|
25
|
+
|
|
26
|
+
# Lenient dispatch over a constant-reference node.
|
|
27
|
+
def qualified_name(node)
|
|
28
|
+
case node
|
|
29
|
+
when Prism::ConstantReadNode then node.name.to_s
|
|
30
|
+
when Prism::ConstantPathNode then render(node)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Lenient render of a `ConstantPathNode`; never nil for a path node.
|
|
35
|
+
def render(node)
|
|
36
|
+
prefix =
|
|
37
|
+
case node.parent
|
|
38
|
+
when Prism::ConstantReadNode then "#{node.parent.name}::"
|
|
39
|
+
when Prism::ConstantPathNode then "#{render(node.parent)}::"
|
|
40
|
+
else ""
|
|
41
|
+
end
|
|
42
|
+
"#{prefix}#{node.name}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Strict dispatch: a dynamic base anywhere in the path yields nil.
|
|
46
|
+
def qualified_name_or_nil(node)
|
|
47
|
+
case node
|
|
48
|
+
when Prism::ConstantReadNode
|
|
49
|
+
node.name.to_s
|
|
50
|
+
when Prism::ConstantPathNode
|
|
51
|
+
parent = node.parent
|
|
52
|
+
return node.name.to_s if parent.nil?
|
|
53
|
+
|
|
54
|
+
parent_name = qualified_name_or_nil(parent)
|
|
55
|
+
return nil if parent_name.nil?
|
|
56
|
+
|
|
57
|
+
"#{parent_name}::#{node.name}"
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
data/lib/rigor/source.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
|
|
@@ -46,17 +47,7 @@ module Rigor
|
|
|
46
47
|
"Method"
|
|
47
48
|
end
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
Trinary.no
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def bot
|
|
54
|
-
Trinary.no
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def dynamic
|
|
58
|
-
Trinary.no
|
|
59
|
-
end
|
|
50
|
+
include Rigor::Type::PlainLattice
|
|
60
51
|
|
|
61
52
|
include Rigor::Type::AcceptanceRouter
|
|
62
53
|
|
|
@@ -405,6 +405,21 @@ module Rigor
|
|
|
405
405
|
DataInstance.new(members, class_name)
|
|
406
406
|
end
|
|
407
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
|
+
|
|
408
423
|
# Normalized union. Flattens nested Unions, deduplicates structurally
|
|
409
424
|
# equal members, drops Bot, and collapses 0/1-member results.
|
|
410
425
|
def union(*types)
|
|
@@ -929,9 +944,7 @@ module Rigor
|
|
|
929
944
|
end
|
|
930
945
|
end
|
|
931
946
|
|
|
932
|
-
#
|
|
933
|
-
# `Dynamic[Top]` carrier on the main Ractor at load time.
|
|
934
|
-
# The `untyped` reader above just returns this ivar.
|
|
947
|
+
# Eager-allocated at load time; see `untyped` method comment above.
|
|
935
948
|
@untyped = Dynamic.new(Top.instance)
|
|
936
949
|
end
|
|
937
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
|
|