Skip to content

Commit 729610a

Browse files
[ty] Fall back to ambiguous for large control flow graphs (#23399)
## Summary This [giant loop](https://github.com/Taiko2k/Tauon/blob/08bfd249f404817e58078a2cbce7a69d3f949f0c/src/tauon/t_modules/t_main.py#L44882-L49772) is causing us to create (per Claude) over 3 million nodes in the TDD graph. We now cap the analysis, which causes us to fall back to "ambiguous" -- so we can still detect most diagnostics, but lose some capabilities. Closes astral-sh/ty#2846.
1 parent 1425c18 commit 729610a

File tree

1 file changed

+19
-0
lines changed

1 file changed

+19
-0
lines changed

crates/ty_python_semantic/src/semantic_index/reachability_constraints.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,12 @@ const AMBIGUOUS: ScopedReachabilityConstraintId = ScopedReachabilityConstraintId
314314
const ALWAYS_FALSE: ScopedReachabilityConstraintId = ScopedReachabilityConstraintId::ALWAYS_FALSE;
315315
const SMALLEST_TERMINAL: ScopedReachabilityConstraintId = ALWAYS_FALSE;
316316

317+
/// Maximum number of interior TDD nodes per scope. When exceeded, new constraint
318+
/// operations return `AMBIGUOUS` to prevent exponential blowup on pathological inputs
319+
/// (e.g., a 5000-line while loop with hundreds of if-branches). This can lead to less precise
320+
/// reachability analysis and type narrowing.
321+
const MAX_INTERIOR_NODES: usize = 512 * 1024;
322+
317323
fn singleton_to_type(db: &dyn Db, singleton: ruff_python_ast::Singleton) -> Type<'_> {
318324
let ty = match singleton {
319325
ruff_python_ast::Singleton::None => Type::none(db),
@@ -588,6 +594,11 @@ impl ReachabilityConstraintsBuilder {
588594
if let Some(cached) = self.not_cache.get(&a) {
589595
return *cached;
590596
}
597+
598+
if self.interiors.len() >= MAX_INTERIOR_NODES {
599+
return AMBIGUOUS;
600+
}
601+
591602
let a_node = self.interiors[a];
592603
let if_true = self.add_not_constraint(a_node.if_true);
593604
let if_ambiguous = self.add_not_constraint(a_node.if_ambiguous);
@@ -621,6 +632,10 @@ impl ReachabilityConstraintsBuilder {
621632
return *cached;
622633
}
623634

635+
if self.interiors.len() >= MAX_INTERIOR_NODES {
636+
return AMBIGUOUS;
637+
}
638+
624639
let (atom, if_true, if_ambiguous, if_false) = match self.cmp_atoms(a, b) {
625640
Ordering::Equal => {
626641
let a_node = self.interiors[a];
@@ -687,6 +702,10 @@ impl ReachabilityConstraintsBuilder {
687702
return *cached;
688703
}
689704

705+
if self.interiors.len() >= MAX_INTERIOR_NODES {
706+
return AMBIGUOUS;
707+
}
708+
690709
let (atom, if_true, if_ambiguous, if_false) = match self.cmp_atoms(a, b) {
691710
Ordering::Equal => {
692711
let a_node = self.interiors[a];

0 commit comments

Comments
 (0)