From 4016521bf6096549279958e3ddeb7e93ea1445c7 Mon Sep 17 00:00:00 2001 From: David Peter Date: Tue, 1 Jul 2025 11:05:52 +0200 Subject: [PATCH] [ty] Eagerly evaluate `TYPE_CHECKING` constraints (#19044) ## Summary Evaluate `TYPE_CHECKING` to `ALWAYS_TRUE` and `not TYPE_CHECKING` to `ALWAYS_FALSE` during semantic index building. This is a follow-up to https://github.com/astral-sh/ruff/pull/18998 and is in principle just a performance optimization. We see some (favorable) ecosystem changes because we can eliminate definitely-unreachable branches early now and retain narrowing constraints without solving https://github.com/astral-sh/ty/issues/690 first. --- .../src/semantic_index/builder.rs | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/crates/ty_python_semantic/src/semantic_index/builder.rs b/crates/ty_python_semantic/src/semantic_index/builder.rs index 4e678ac8ef..4f0ffd5a67 100644 --- a/crates/ty_python_semantic/src/semantic_index/builder.rs +++ b/crates/ty_python_semantic/src/semantic_index/builder.rs @@ -542,15 +542,31 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> { } fn build_predicate(&mut self, predicate_node: &ast::Expr) -> PredicateOrLiteral<'db> { + // Some commonly used test expressions are eagerly evaluated as `true` + // or `false` here for performance reasons. This list does not need to + // be exhaustive. More complex expressions will still evaluate to the + // correct value during type-checking. + fn resolve_to_literal(node: &ast::Expr) -> Option { + match node { + ast::Expr::BooleanLiteral(ast::ExprBooleanLiteral { value, .. }) => Some(*value), + ast::Expr::Name(ast::ExprName { id, .. }) if id == "TYPE_CHECKING" => Some(true), + ast::Expr::UnaryOp(ast::ExprUnaryOp { + op: ast::UnaryOp::Not, + operand, + .. + }) => Some(!resolve_to_literal(operand)?), + _ => None, + } + } + let expression = self.add_standalone_expression(predicate_node); - if let Some(boolean_literal) = predicate_node.as_boolean_literal_expr() { - PredicateOrLiteral::Literal(boolean_literal.value) - } else { - PredicateOrLiteral::Predicate(Predicate { + match resolve_to_literal(predicate_node) { + Some(literal) => PredicateOrLiteral::Literal(literal), + None => PredicateOrLiteral::Predicate(Predicate { node: PredicateNode::Expression(expression), is_positive: true, - }) + }), } }