{"record":{"id":"b914ef2ffbc11c3e","repo":"astral-sh/ruff","slug":"non-terminal-bdd-should-have-source-order","errorCode":null,"errorMessage":"non-terminal BDD should have source_order","messagePattern":"non-terminal BDD should have source_order","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/ty_python_semantic/src/types/constraints.rs","lineNumber":1089,"sourceCode":"        self.constraint_cache.extend(\n            compacted\n                .constraint_indices\n                .iter_ones()\n                .zip(compacted.constraints.iter().copied())\n                .map(|(old_index, constraint)| (constraint, ConstraintId::from_usize(old_index))),\n        );\n        self.node_cache.extend(\n            compacted\n                .node_indices\n                .iter_ones()\n                .zip(compacted.nodes.iter().copied())\n                .map(|(old_index, node)| (node, NodeId::from_usize(old_index))),\n        );\n        self.source_order_cache.extend(\n            compacted\n                .source_orders\n                .iter()\n                .copied()\n                .enumerate()\n                .map(|(index, source_order)| (source_order, SourceOrderId::from_usize(index))),\n        );\n    }\n\n    // This is a separate method from `ensure_overlay_identity_caches` because it requires a `db`.\n    fn ensure_overlay_typevar_identity_cache(&mut self, db: &'db dyn Db) {\n        let Some(compacted) = &self.compacted else {\n            return;\n        };\n        if !self.typevar_cache.is_empty() {\n            return;\n        }\n\n        self.typevar_cache.extend(\n            compacted\n                .typevars\n                .iter_enumerated()","sourceCodeStart":1071,"sourceCodeEnd":1107,"githubUrl":"https://github.com/astral-sh/ruff/blob/15f3fe6b15a5f00172f34b0f542f8ea277f5a586/crates/ty_python_semantic/src/types/constraints.rs#L1071-L1107","documentation":"An `OwnedConstraintSet` pairs its BDD root node with a source-order tree. In this routine the set's constraints are transformed with a closure and the set is rebuilt; a non-terminal root must always carry `source_order`. The expect fires when the transformed set kept a non-terminal BDD but its `source_order` is None - a combine path that dropped the source order.","triggerScenarios":"Calling this map/compact routine on an owned constraint set where the closure `f` returns a constraint set whose node is non-terminal while `source_order` is None, e.g. a quantifier/combination operation that threads the BDD but forgets the source-order sidecar.","commonSituations":"Modifying ty's constraint solver (new combine/quantify operations on `OwnedConstraintSet`); typically surfaces in inference mdtests with multiple typevars and ordering-sensitive fixtures.","solutions":["Audit every operation that constructs `OwnedConstraintSet` to thread `source_order` for non-terminal roots; only terminal roots may set it to None.","Reproduce with the smallest inference case (few typevars, few constraints) and run the ty_python_semantic constraint tests.","Use `debug_assert!` in constructors to catch None-source-order/non-terminal combinations at creation time.","Report upstream with the reproducer if stock ty panics."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n    owned_set.map(db, f)\n}))\n.unwrap_or_else(|_| OwnedConstraintSet::terminal()); // degrade to trivially-true set","preventionTips":["Contributors: never construct an OwnedConstraintSet with a non-terminal node and None source_order; assert it in the constructor.","Keep ordering-sensitive mdtests in any PR touching constraint combination.","Users: pin a known-good ty release for CI so a solver regression cannot block merges."],"tags":["rust","panic","expect","ty","constraints","bdd","source-order","invariant"],"backgroundTag":"constraint-solver-invariant-panic","analyzedSha":"15f3fe6b15a5f00172f34b0f542f8ea277f5a586","analyzedAt":"2026-08-20T16:33:49.445Z","contentChangedAt":"2026-08-20T16:33:49.445Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}