Class: Rigor::Inference::HktRegistry

Inherits:
Object
  • Object
show all
Defined in:
lib/rigor/inference/hkt_registry.rb

Overview

ADR-20 § “Decision D1 / D2” — registry of Lightweight HKT tag registrations + type-function bodies parsed off the ‘%a…` / `%a…` annotations in shipped `.rbs` files.

The registry stores registration metadata (arity, variance, bound) and the definition body as both a raw String and an evaluable ‘HktBody` node tree. `HktReducer` (Slice 2a) and `HktBodyParser` (Slice 2b) are both shipped and reduce `Type::App` instances against the definition. The carrier never needs to read from the registry because Slice 1’s ‘Type::App` carries its `bound` directly; the registry exists at this slice solely so the parser round-trip and downstream slices have a stable target API.

The registry is immutable after construction. Callers that need to extend it (e.g. plugin registrations layered on top of stdlib registrations) MUST build a new registry via ‘merge` rather than mutating an existing one. This keeps the registry shareable across Ractor boundaries per ADR-15.

Defined Under Namespace

Classes: Definition, Registration

Constant Summary collapse

EMPTY =
new.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(registrations: [], definitions: []) ⇒ HktRegistry

Returns a new instance of HktRegistry.

Parameters:



120
121
122
123
124
# File 'lib/rigor/inference/hkt_registry.rb', line 120

def initialize(registrations: [], definitions: [])
  @registrations = registrations.to_h { |r| [r.uri, r] }.freeze
  @definitions = definitions.to_h { |d| [d.uri, d] }.freeze
  freeze
end

Instance Attribute Details

#definitionsObject (readonly)

Returns the value of attribute definitions.



116
117
118
# File 'lib/rigor/inference/hkt_registry.rb', line 116

def definitions
  @definitions
end

#registrationsObject (readonly)

Returns the value of attribute registrations.



116
117
118
# File 'lib/rigor/inference/hkt_registry.rb', line 116

def registrations
  @registrations
end

Class Method Details

.definition_with_body_tree(uri:, params:, body_tree:, source_path: nil, source_line: nil) ⇒ Object

Convenience constructor for callers that have a body tree but no raw String — typically Rigor-bundled HKT overlays that build the body programmatically. The raw ‘body` slot is filled with an empty placeholder so existing consumers keep their type contract.



105
106
107
108
109
110
111
112
113
114
# File 'lib/rigor/inference/hkt_registry.rb', line 105

def self.definition_with_body_tree(uri:, params:, body_tree:, source_path: nil, source_line: nil)
  Definition.new(
    uri: uri,
    params: params,
    body: "",
    body_tree: body_tree,
    source_path: source_path,
    source_line: source_line
  )
end

.scan_rbs_loader(rbs_loader, base: EMPTY, name_scope: nil, reporter: nil) ⇒ Object

ADR-20 slice 2e — scan a Rigor RbsLoader for ‘rigor:v1:hkt_register` / `rigor:v1:hkt_define` annotations attached to class- or module-level declarations in the loaded RBS env, parse them via RbsExtended::HktDirectives, and return a new registry that is the union of `base` and every parsed entry. Last-write-wins on URI collisions per #merge’s contract. Fail-soft on per-annotation parse errors (the reporter records an ‘:info` entry; the other annotations still apply).

Parameters:

  • rbs_loader (Rigor::Environment::RbsLoader)
  • base (HktRegistry) (defaults to: EMPTY)

    starting registry (typically the bundled ‘Rigor::Builtins::HktBuiltins.registry`).

  • name_scope (Rigor::Environment::NameScope, nil) (defaults to: nil)

    threaded through to the bound resolver for class-name lookups; safe to omit during scanning since hkt bounds are typically ‘untyped` or stdlib classes.

  • reporter (#record, nil) (defaults to: nil)

    same fail-soft reporter contract the other RBS-extended parsers use.



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/rigor/inference/hkt_registry.rb', line 187

def self.scan_rbs_loader(rbs_loader, base: EMPTY, name_scope: nil, reporter: nil)
  return base if rbs_loader.nil?

  # Required lazily here to avoid a hard circular
  # require between hkt_registry / hkt_directives;
  # HktDirectives requires HktRegistry to construct its
  # value objects.
  require_relative "../rbs_extended/hkt_directives"

  registrations = []
  definitions = []

  rbs_loader.each_class_decl_annotation do |annotation_string, source_location|
    reg = Rigor::RbsExtended::HktDirectives.parse_register(
      annotation_string, name_scope: name_scope, reporter: reporter, source_location: source_location
    )
    registrations << reg if reg

    defn = Rigor::RbsExtended::HktDirectives.parse_define(
      annotation_string, reporter: reporter, source_location: source_location
    )
    definitions << defn if defn
  end

  return base if registrations.empty? && definitions.empty?

  overlay = new(registrations: registrations, definitions: definitions)
  base.merge(overlay)
end

Instance Method Details

#defined?(uri) ⇒ Boolean

Returns:

  • (Boolean)


130
131
132
# File 'lib/rigor/inference/hkt_registry.rb', line 130

def defined?(uri)
  @definitions.key?(uri)
end

#definition(uri) ⇒ Object



138
139
140
# File 'lib/rigor/inference/hkt_registry.rb', line 138

def definition(uri)
  @definitions[uri]
end

#empty?Boolean

Returns:

  • (Boolean)


155
156
157
# File 'lib/rigor/inference/hkt_registry.rb', line 155

def empty?
  @registrations.empty? && @definitions.empty?
end

#merge(other) ⇒ HktRegistry

Returns a new registry whose entries are the union of this registry’s and ‘other`’s. On URI collisions ‘other`’s entries win (last-write-wins; OQ3 tentative).

Returns:

  • (HktRegistry)

    a new registry whose entries are the union of this registry’s and ‘other`’s. On URI collisions ‘other`’s entries win (last-write-wins; OQ3 tentative).

Raises:

  • (ArgumentError)


146
147
148
149
150
151
152
153
# File 'lib/rigor/inference/hkt_registry.rb', line 146

def merge(other)
  raise ArgumentError, "merge target must be an HktRegistry, got #{other.class}" unless other.is_a?(HktRegistry)

  self.class.new(
    registrations: @registrations.merge(other.registrations).values,
    definitions: @definitions.merge(other.definitions).values
  )
end

#reduce(app, fuel: HktReducer::DEFAULT_FUEL) ⇒ Object

ADR-20 Slice 2a — reduce an ‘App` against this registry. Convenience wrapper around `HktReducer.new(self).reduce`. Each call allocates a fresh reducer; concurrent reductions are safe.



163
164
165
# File 'lib/rigor/inference/hkt_registry.rb', line 163

def reduce(app, fuel: HktReducer::DEFAULT_FUEL)
  HktReducer.new(self).reduce(app, fuel: fuel)
end

#registered?(uri) ⇒ Boolean

Returns:

  • (Boolean)


126
127
128
# File 'lib/rigor/inference/hkt_registry.rb', line 126

def registered?(uri)
  @registrations.key?(uri)
end

#registration(uri) ⇒ Object



134
135
136
# File 'lib/rigor/inference/hkt_registry.rb', line 134

def registration(uri)
  @registrations[uri]
end