Skip to content

#346: per-instantiation Option/Result classdefs + compute_mro residualization - #429

Merged
youknowone merged 3 commits into
mainfrom
rtyper-legacy
Jul 8, 2026
Merged

#346: per-instantiation Option/Result classdefs + compute_mro residualization#429
youknowone merged 3 commits into
mainfrom
rtyper-legacy

Conversation

@youknowone

@youknowone youknowone commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Two follow-on #346 slices toward retiring the rtyper legacy walker: per-instantiation classdef specialization for the Option/Result combinator front passes, and residualizing the compute_mro C3 walk so the numeric/unary and lookup families stop failing the two-phase prepass on the foreign vec! alloc intrinsic.

Commits

per-instantiation enum root + closure-Args Tuple suffix for Option combinators

A generic enum instantiation (Option<X>, Result<T,E>) and a collapsed non-suffixed spelling of the same enum (core.option.Option) were interned as distinct classdefs with no shared base, so commonbase returned None at a phi merge. Separately, the bool::then / map_or / map / and_then / unwrap_or_else front passes minted a bare Tuple for the closure Args, whose __pos_0 unioned every closure payload in the program onto one classdef (PyObject ∪ FrameDebugData).

  • Subclass a generic enum instantiation and a collapsed spelling of the same enum under the bare enum leaf in intern_class_by_qualname (discriminant-only root, no payload attr to conflict on).
  • Suffix the tagged-pair enum root (emit_tagged_pair_aggregate, the checked_neg / usize::try_from runtime-discriminant lowering) with the destination Option<X>/Result<X,E>'s <X>.
  • Suffix the enum root in recognize_bool_then_site / recognize_map_or_site / recognize_closure_select_site from the site's dest/recv Option<X>; suffix the synthesized closure-Args tuple in option_map_or / option_closure_select via option_payload_tuple_suffix, which routes the receiver Option's payload node through tyref_tuple_suffix — the same renderer the extracted call_once reads .0 under at resolve_place — so the __pos_0 write and read key under one classdef. A niladic closure's () tuple stays bare Tuple.

Effect: cannot unify instances with no common base class 52→10 (the Option<…> ∪ core.option.Option family and PyObject ∪ FrameDebugData go to zero).

residualize compute_mro / lookup_in_type_where_uncached via dont_look_inside

compute_mro (C3 linearization) starts with vec![w_type], which lowers to the foreign non-scalar box_assume_init_into_vec_unsafe alloc intrinsic that has no annotator graph; the self-recursive C3 walk blocked every numeric/unary and lookup-family graph funneling through the cold uncached lookup_where branch.

  • Annotate compute_mro and the scalar-Option boundary lookup_in_type_where_uncached #[dont_look_inside] so the walk residualizes — MRO computation opaque, MRO iteration traced (compute_C3_mro behind __init__ dont_look_inside, typeobject.py:199/1687).
  • Bind the residual fnaddrs for compute_mro, its wrapper compute_default_mro, and lookup_in_type_where_uncached (siblings of the note_alloc / try_gc_charge residuals).
  • Correct the union-fallback skip comment in cutover.rs: upstream RAISES for the pairs reaching it (pair(SomeObject,SomeObject).union binaryop.py:90-93, pair(SomePtr,SomeObject) llannotation.py:118-120), so the skip marks a pyre producer divergence (a boxed pointer lifted as SomePtr where RPython carries SomeInstance), not a missing union handler.

Effect: compute_at_fixpoint prepass failures 165→138.

Verification

check.py dynasm 183/183 + cranelift 183/183 (the JIT paths that consume the new classdef owners / residual fnaddrs). The four wasm-backend check.py failures (inline_callee_constructs_object, inlined_helper_mutation, inlined_mutation_before_abort, sre_pattern_methods) reproduce identically on the base commit — pre-existing, independent of these changes.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Improved handling of optional values and closure-based rewrites, including better support for generic cases and empty-argument closures.
  • Bug Fixes

    • Fixed cases where different generic forms could be treated as separate enum identities.
    • Improved consistency in type resolution and method lookup during tracing, reducing mismatches and unexpected fallbacks.
    • Strengthened tracing behavior so internal lookup and MRO processing stay more stable and predictable.

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@youknowone, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 5 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0ef8fb01-679f-4c2b-9f72-393dbf912fad

📥 Commits

Reviewing files that changed from the base of the PR and between a4f4582 and e169c1a.

📒 Files selected for processing (7)
  • majit/majit-translate/src/annotator/bookkeeper.rs
  • majit/majit-translate/src/front/mir.rs
  • majit/majit-translate/src/front/option_closure_select.rs
  • majit/majit-translate/src/front/option_map_or.rs
  • majit/majit-translate/src/translator/rtyper/cutover.rs
  • pyre/pyre-interpreter/src/baseobjspace.rs
  • pyre/pyre-interpreter/src/jit_fnaddr.rs

Walkthrough

This PR threads per-instantiation type suffixes through enum and tuple owner name construction in MIR lowering, closure-select, and map_or rewriting so distinct Option<X>/Result<X,E> instantiations resolve to distinct owners, adds an enum bare-leaf canonicalization step in class interning, updates a skip-reason comment, and marks MRO lookup/computation functions as opaque JIT tracing boundaries with corresponding function-address registry entries.

Changes

Enum/Tuple Instantiation Suffix Threading

Layer / File(s) Summary
Enum-base bare-leaf canonicalization
majit/majit-translate/src/annotator/bookkeeper.rs
intern_class_by_qualname now strips generic args from enum-base spellings and short-circuits to the bare leaf for shared identity.
Suffix extraction helpers
majit/majit-translate/src/front/mir.rs
Adds tyref_enum_instantiation_suffix and option_payload_tuple_suffix to derive <X>/Tuple<X> suffixes fail-closed from TyRef/Adt structures.
Applying suffixes to Option/Result owners
majit/majit-translate/src/front/mir.rs
Destination/receiver Option<X> owner strings and resolve_aggregate_adt ctor routing now append the instantiation suffix instead of the bare template name path.
MapOrSite suffix wiring in mir.rs
majit/majit-translate/src/front/mir.rs
Computes args_tuple_suffix from the receiver payload and includes it when constructing option_map_or::MapOrSite.
ClosureSelectSite suffix and emit_call_once
majit/majit-translate/src/front/option_closure_select.rs
Adds args_tuple_suffix field, threads it through rewrite arms into emit_call_once, and derives tuple_owner for the synthetic ctor and FieldDescriptor.owner_root; tests updated.
MapOrSite suffix in option_map_or.rs
majit/majit-translate/src/front/option_map_or.rs
Adds args_tuple_suffix field used to build tuple_owner for the Some arm's synthetic Args tuple ctor and field write; test helper updated.
Skip-reason comment update
majit/majit-translate/src/translator/rtyper/cutover.rs
Rewrites documentation for the "cannot unify instances with no common base class" skip case without logic changes.

MRO Tracing Opacity Boundaries

Layer / File(s) Summary
Opaque boundary annotations
pyre/pyre-interpreter/src/baseobjspace.rs
Applies #[majit_macros::dont_look_inside] to lookup_in_type_where_uncached (now pub(crate)) and compute_mro, with added documentation.
Function-address registry entries
pyre/pyre-interpreter/src/jit_fnaddr.rs
Registers compute_mro, compute_default_mro, and lookup_in_type_where_uncached pointers with module-qualified and crate-root alias paths.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • youknowone/pyre#164: Both PRs modify Bookkeeper::intern_class_by_qualname header-chain/class-resolution logic in the same function.
  • youknowone/pyre#411: Both PRs modify enum-base resolution logic within intern_class_by_qualname, directly overlapping the new bare-leaf short-circuit.

Poem

A rabbit hops through generic gates,
Suffixing owners, untangling fates,
Enum leaves bare, tuples aligned,
MRO walks now safely confined,
Hop, hop — the traces stay opaque and neat! 🐇✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately captures the two main changes: per-instantiation Option/Result classdefs and compute_mro residualization.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch rtyper-legacy

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

🤖 Codex parity review

Static analysis of this diff vs the local RPython/PyPy sources (commit 1dfca47).

1. Regressions to PyPy parity introduced by this patch

None.

2. Other mismatches introduced by this patch

None.

3. Pre-existing mismatches (already present before this patch)

  • majit/majit-translate/src/translator/rtyper/cutover.rs:1256 ↔ rpython/annotator/annrpython.py:531: ours classifies "AnnotatorError:" / fixpoint failures as known-unported skip; RPython records or raises AnnotatorError from the annotator path. This mismatch was already in the allowlist; the patch only comments it.

  • majit/majit-translate/src/translator/rtyper/cutover.rs:1272 ↔ rpython/rtyper/rtyper.py:815: ours skips "don't know how to convert from"; RPython convertvar raises TyperError("don't know how to convert...") when conversion returns NotImplemented.

  • majit/majit-translate/src/translator/rtyper/cutover.rs:1281 ↔ rpython/annotator/binaryop.py:673: ours skips "cannot unify instances with no common base class"; RPython raises UnionError(... "RPython cannot unify instances with no common base class").

  • majit/majit-translate/src/translator/rtyper/cutover.rs:1291 ↔ rpython/annotator/binaryop.py:92: ours skips "no upstream pair(s1, s2).union() handler..."; RPython pair(SomeObject, SomeObject).union() raises UnionError.

  • majit/majit-translate/src/translator/rtyper/cutover.rs:1291 ↔ rpython/rtyper/llannotation.py:119: same allowlist entry also covers SomePtr ∪ SomeObject; RPython pair(SomePtr, SomeObject).union() raises UnionError.

  • pyre/pyre-interpreter/src/baseobjspace.rs:6573 ↔ pypy/objspace/std/typeobject.py:1697: ours breaks out on C3 inconsistency and returns the partial MRO; PyPy calls mro_error(...), raising TypeError. This body behavior predates the patch; the patch only adds the tracing boundary.

4. Structural adaptations

  • majit/majit-translate/src/annotator/bookkeeper.rs:2182 ↔ rpython/annotator/bookkeeper.py:168: ours synthesizes generic enum instantiation class hierarchy for Option<X> / Result<T,E>; RPython keys ClassDef by an actual Python class object via getuniqueclassdef(cls). This is a Rust generic-ADT adaptation.

  • majit/majit-translate/src/front/mir.rs:7797 ↔ rpython/annotator/classdesc.py:251: ours suffixes bool::then Option<X> owners before deriving Some; RPython common-base behavior comes from real ClassDef.basedef, not generic owner strings. Structural Rust Option lowering.

  • majit/majit-translate/src/front/mir.rs:7970 ↔ rpython/annotator/classdesc.py:251: ours suffixes Option::map_or receiver owners with <X>; RPython has no generic Option class spelling to specialize.

  • majit/majit-translate/src/front/mir.rs:8026 ↔ rpython/annotator/classdesc.py:251: ours suffixes Option::map / and_then / unwrap_or_else receiver owners with <X>; RPython class hierarchy is object-based, not generic-name-based.

  • majit/majit-translate/src/front/mir.rs:8232 ↔ rpython/translator/simplify.py:105: ours materializes checked_neg() as a suffixed synthetic Option<i64> aggregate; RPython rewrites ovfcheck(-x) to an overflow-checking operation. This is a Rust-core spelling adaptation.

  • majit/majit-translate/src/front/mir.rs:8343 ↔ rpython/rlib/rarithmetic.py:140: ours materializes infallible usize::try_from as a suffixed synthetic Result<T,E> or direct payload bind; RPython widen() is the corresponding no-op widening path. Rust Result is structural glue.

  • majit/majit-translate/src/front/mir.rs:11938 ↔ rpython/annotator/bookkeeper.py:168: helper tyref_enum_instantiation_suffix manufactures <...> owner suffixes from Charon ADT generics; RPython has no equivalent because class identity is the Python class object.

  • majit/majit-translate/src/front/mir.rs:11967 ↔ rpython/rtyper/rtuple.py:131: helper option_payload_tuple_suffix creates Tuple<X> owner names for closure args; RPython uses TupleRepr(items_r) and TUPLE_TYPE(lltypes) per item shape, not synthetic classdef owner strings.

  • majit/majit-translate/src/front/option_map_or.rs:259 ↔ rpython/rtyper/rtuple.py:153: ours constructs closure args through SyntheticTransparentCtor("Tuple<X>"); RPython TupleRepr.newtuple mallocs the concrete tuple low-level type and sets fields.

  • majit/majit-translate/src/front/option_closure_select.rs:340 ↔ rpython/rtyper/rtuple.py:153: same tuple-owner adaptation for map / and_then / unwrap_or_else; niladic closures stay bare Tuple, while payload closures use Tuple<X>.

  • pyre/pyre-interpreter/src/baseobjspace.rs:5908 ↔ pypy/objspace/std/typeobject.py:480: ours marks lookup_in_type_where_uncached as dont_look_inside; PyPy marks _lookup_where as @unroll_safe. The patch keeps lookup_where traceable and residualizes only the Rust projection wrapper because of Rust slice/Vec phi typing.

  • pyre/pyre-interpreter/src/baseobjspace.rs:6521 ↔ pypy/objspace/std/typeobject.py:1687: ours marks compute_mro as dont_look_inside; PyPy’s compute_C3_mro function itself is undecorated, although normal type initialization is under W_TypeObject.__init__ @dont_look_inside at pypy/objspace/std/typeobject.py:199.

  • pyre/pyre-interpreter/src/jit_fnaddr.rs:597 ↔ rpython/rlib/jit.py:133: ours registers residual Rust function addresses for compute_mro, compute_default_mro, and lookup_in_type_where_uncached; RPython uses decorator metadata (dont_look_inside) rather than an explicit fn-address table.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a4f458290b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if reg.is_enum_base(&lookup) {
let stripped = majit_ir::descr::strip_generic_args(&lookup);
let bare_leaf = stripped.rsplit("::").next().unwrap_or(&stripped);
if bare_leaf != lookup.as_str() && !seen.contains(bare_leaf) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid self-basing qualified enum roots

When the prologue visits a qualified enum root such as core::option::Option before the bare alias, this branch returns Option as its base even though canonical_struct_name("Option") resolves back to the same core::option::Option cache key. The mint loop below does not de-duplicate chain entries, so it first inserts the bare-root class and then overwrites the same key with a second class whose base is the phantom first one, making enum ClassDef identity and inheritance numbering depend on HashMap iteration order. Please compare canonical keys (or restrict this to generic/dotted spellings) before adding the bare-leaf base.

Useful? React with 👍 / 👎.

…ion combinators

Subclass a generic enum instantiation (`Option<X>`, `Result<T,E>`) and a
collapsed non-suffixed spelling of the same enum (`core.option.Option`) under
the bare enum leaf in intern_class_by_qualname, so two sibling instantiations
and a collapsed value share a base and commonbase to it at a phi merge.

Suffix the tagged-pair enum root (emit_tagged_pair_aggregate, checked_neg /
usize::try_from) with the destination `Option<X>`/`Result<X,E>`'s `<X>` via
tyref_enum_instantiation_suffix, so a runtime-discriminant construction mints
the same per-instantiation root a static `Some(..)`/`Ok(..)` mints.

Suffix the enum root in recognize_bool_then_site / recognize_map_or_site /
recognize_closure_select_site from the site's dest/recv `Option<X>`. Suffix the
synthesized closure-`Args` tuple `(payload,)` in option_map_or and
option_closure_select with option_payload_tuple_suffix, which wraps the
receiver Option's payload node in a Tuple and routes it through
tyref_tuple_suffix — the same renderer the extracted call_once reads `.0`
under at resolve_place — so the `__pos_0` write and read key under one classdef.
A niladic closure's `()` tuple stays bare Tuple.

Census: cannot unify with no common base 52->10 (Option family 42->0,
PyObject union FrameDebugData 4->0). dynasm/cranelift check.py 183/183.

Assisted-by: Claude
…t_look_inside

`compute_mro` (C3 linearization) starts with `vec![w_type]`, which lowers to
the foreign non-scalar `box_assume_init_into_vec_unsafe` alloc intrinsic that
has no annotator graph; the self-recursive C3 walk therefore blocked every
numeric/unary and lookup-family graph funneling through the cold uncached
`lookup_where` branch. Annotate `compute_mro` and the scalar-Option boundary
`lookup_in_type_where_uncached` `#[dont_look_inside]` so the walk residualizes,
mirroring MRO computation opaque / MRO iteration traced (compute_C3_mro behind
`__init__` dont_look_inside, typeobject.py:199/1687). Bind the residual fnaddrs
for compute_mro, its wrapper compute_default_mro, and
lookup_in_type_where_uncached (siblings of the note_alloc / try_gc_charge
residuals).

Correct the union-fallback skip comment in cutover.rs: upstream RAISES for the
pairs reaching it (pair(SomeObject,SomeObject).union binaryop.py:90-93,
pair(SomePtr,SomeObject) llannotation.py:118-120), so the skip marks a pyre
producer divergence (a boxed pointer lifted as SomePtr where RPython carries
SomeInstance), not a missing union handler.

Census: cat2 compute_at_fixpoint 165->138. dynasm/cranelift check.py 183/183.

Assisted-by: Claude

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e169c1ae33

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +8026 to +8030
let option_owner = format!(
"{}{}",
td.item_meta.name_path(),
tyref_enum_instantiation_suffix(recv_ty, self.llbc)
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Split receiver and result Option owners for map/and_then

For Option<T>::map and and_then where the closure returns U/Option<U> with U != T, this suffix is derived from the receiver type and then reused both to read opt.__pos_0 and to construct the result Some/None in rewire_one_closure_select_site. That makes map write the U payload into the Option<T>::Some class and makes and_then build the None arm as Option<T>, while the actual result type is Option<U>. The pass now needs separate receiver owners from recv_ty and result owners from dest_ty for the combinators that return an Option.

Useful? React with 👍 / 👎.

@youknowone
youknowone merged commit 7dadb61 into main Jul 8, 2026
28 of 30 checks passed
@youknowone
youknowone deleted the rtyper-legacy branch July 8, 2026 21:50
youknowone added a commit that referenced this pull request Jul 9, 2026
…lization (#429)

* #346: per-instantiation enum root + closure-Args Tuple suffix for Option combinators

Subclass a generic enum instantiation (`Option<X>`, `Result<T,E>`) and a
collapsed non-suffixed spelling of the same enum (`core.option.Option`) under
the bare enum leaf in intern_class_by_qualname, so two sibling instantiations
and a collapsed value share a base and commonbase to it at a phi merge.

Suffix the tagged-pair enum root (emit_tagged_pair_aggregate, checked_neg /
usize::try_from) with the destination `Option<X>`/`Result<X,E>`'s `<X>` via
tyref_enum_instantiation_suffix, so a runtime-discriminant construction mints
the same per-instantiation root a static `Some(..)`/`Ok(..)` mints.

Suffix the enum root in recognize_bool_then_site / recognize_map_or_site /
recognize_closure_select_site from the site's dest/recv `Option<X>`. Suffix the
synthesized closure-`Args` tuple `(payload,)` in option_map_or and
option_closure_select with option_payload_tuple_suffix, which wraps the
receiver Option's payload node in a Tuple and routes it through
tyref_tuple_suffix — the same renderer the extracted call_once reads `.0`
under at resolve_place — so the `__pos_0` write and read key under one classdef.
A niladic closure's `()` tuple stays bare Tuple.

Census: cannot unify with no common base 52->10 (Option family 42->0,
PyObject union FrameDebugData 4->0). dynasm/cranelift check.py 183/183.

Assisted-by: Claude

* #346: residualize compute_mro / lookup_in_type_where_uncached via dont_look_inside

`compute_mro` (C3 linearization) starts with `vec![w_type]`, which lowers to
the foreign non-scalar `box_assume_init_into_vec_unsafe` alloc intrinsic that
has no annotator graph; the self-recursive C3 walk therefore blocked every
numeric/unary and lookup-family graph funneling through the cold uncached
`lookup_where` branch. Annotate `compute_mro` and the scalar-Option boundary
`lookup_in_type_where_uncached` `#[dont_look_inside]` so the walk residualizes,
mirroring MRO computation opaque / MRO iteration traced (compute_C3_mro behind
`__init__` dont_look_inside, typeobject.py:199/1687). Bind the residual fnaddrs
for compute_mro, its wrapper compute_default_mro, and
lookup_in_type_where_uncached (siblings of the note_alloc / try_gc_charge
residuals).

Correct the union-fallback skip comment in cutover.rs: upstream RAISES for the
pairs reaching it (pair(SomeObject,SomeObject).union binaryop.py:90-93,
pair(SomePtr,SomeObject) llannotation.py:118-120), so the skip marks a pyre
producer divergence (a boxed pointer lifted as SomePtr where RPython carries
SomeInstance), not a missing union handler.

Census: cat2 compute_at_fixpoint 165->138. dynasm/cranelift check.py 183/183.

Assisted-by: Claude

* #346: cargo fmt jit_fnaddr lookup_in_type_where_uncached binding

Assisted-by: Claude
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Retire the rtyper legacy walker: two-phase coverage roadmap (#131 goal G)

1 participant