astral-sh/ruff · error
typevar should be interned before ordering
Error message
typevar should be interned before ordering
What it means
Constraint-set storage interns every typevar through `intern_typevar` before it can be ordered; `typevar_id` only performs a lookup in `typevar_cache` keyed by typevar identity. The expect fires when ordering is requested for a `BoundTypeVarInstance` that was never interned in this builder - a typevar from another storage/overlay, or one added without going through the interning path.
Source
Thrown at crates/ty_python_semantic/src/types/constraints.rs:1398
support.insert(typevar);
}
walk_type_with_recursion_guard(db, ty, self, &self.recursion_guard);
}
}
InternMentionedTypevars {
env,
storage: RefCell::new(self),
support: RefCell::new(support),
recursion_guard: TypeCollector::default(),
}
.visit_type(db, ty);
}
/// Interns all of the typevars mentioned in a constraint in a stable order.
fn intern_constraint_typevars(
&mut self,
db: &'db dyn Db,
env: &ProgramEnvironment<'db>,
constraint: Constraint<'db>,
) -> Support {
let mut support = Support::default();
support.insert(self.intern_typevar(db, constraint.typevar()));
for bound in constraint.iter_stored_bounds() {
self.intern_mentioned_typevars_in_type(db, env, bound.ty(), &mut support);
}
support
}
fn intern_constraint(
&mut self,
db: &'db dyn Db,
env: &ProgramEnvironment<'db>,
data: Constraint<'db>,
) -> ConstraintId {
let support = self.intern_constraint_typevars(db, env, data);View on GitHub (pinned to 15f3fe6b15)
Solutions
- Ensure every code path that can later order a typevar calls `intern_typevar` (constraints.rs:1261) when adding its constraints.
- If ordering foreign typevars is legitimate, make `typevar_id` intern on miss instead of expecting.
- Add a regression test that orders a typevar immediately after adding constraints and one after compaction.
- Report upstream with the reproducer if stock ty panics.
Example fix
// before
let id = self.typevar_id(db, typevar);
// after: intern first, ordering stays a pure lookup
let id = {
self.storage.borrow_mut().intern_typevar(db, typevar);
self.typevar_id(db, typevar)
}; Defensive patterns
Strategy: try-catch
Try / catch
let id = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
builder.typevar_id(db, typevar)
}))
.ok(); // callers must treat None as 'not yet known to this builder' Prevention
- Contributors: every constraint-adding path must intern the typevar first; ordering is lookup-only by design.
- Never reuse typevars across builders/storages in tests.
- Reduce repros to the smallest typevar set that still panics before reporting.
When it happens
Trigger: Calling ordering logic on a typevar whose constraints were never loaded into this builder: mixing storages, using a typevar after compaction split the storage, or a new code path that creates constraints without interning the typevar first.
Common situations: Contributions adding constraint-producing operations that bypass `intern_typevar`; overlay/borrow issues where the cache is ensured (`ensure_overlay_identity_caches`) but never populated; ordering-sensitive mdtests failing after a solver refactor.
Related errors
- storage-free owned constraint sets must have terminal roots
- every TDD constraint should have a source order
- non-terminal BDD should have source_order
- node should be non-terminal
- non-terminal constraint set should have a source_order
AI-assisted analysis of astral-sh/ruff@15f3fe6b15 (2026-08-20).
Data as JSON: /api/errors/71bf16573b4039e3.
Report an issue: GitHub.