`SpecializationBuilder` migration

2026-03-06

I've been working on a migration this week to change the internals of the `SpecializationBuilder` in ty. This type performs the bulk of the work when inferring a specialization when calling a generic function. We are in the middle of migrating to a new solver, which uses binary decision diagrams (BDDs) to encode the set of constraints that must collectively hold for the valid specializations.

» Theory » Binary decision diagrams

The builder currently lives in a hybrid state:

The goal of this migration is to change the builder's internal "pending" state from the simple `HashMap` to a `ConstraintSet`, bringing us one step closer to using the new solver everywhere.

I've been dreading this part of the migration, because it requires updating several call sites that bake in deep assumptions about the internal state of `SpecializationBuilder`. I've been pleasantly surprised with how well the pi coding agent has done in putting together a detailed plan and chipping away at the implementation. I'm putting the transcripts here for posterity. Given time, I might also add some summary notes here as well.

Pi coding agent

Raw transcripts

Generating the plan

Phase 1: Add the solution extraction hook API

Phase 2: Migrate callers to use the solution extraction hook API

Phase 3: Update callers that can make raw `ContraintSet` queries

Phase 4a: Update `preferred_type_mappings`

Phase 4b: Update final `infer_reverse` callers

Update the plan to reorder phases 5 and 6

Phase 5a: Fill in a constraint set on the side

Phase 5b: Use conjunction for new solver cases