From 33c5f6f4f8a47e050ba421131262a534c2fb7fc5 Mon Sep 17 00:00:00 2001 From: Carl Meyer Date: Mon, 25 Aug 2025 11:32:18 -0700 Subject: [PATCH] [ty] don't mark entire type-alias scopes as Deferred (#20086) ## Summary This has been here for awhile (since our initial PEP 695 type alias support) but isn't really correct. The right-hand-side of a PEP 695 type alias is a distinct scope, and we don't mark it as an "eager" nested scope, so it automatically gets "deferred" resolution of names from outer scopes (just like a nested function). Thus it's redundant/unnecessary for us to use `DeferredExpressionState::Deferred` for resolving that RHS expression -- that's for deferring resolution of individual names within a scope. Using it here causes us to wrongly ignore applicable outer-scope narrowing. ## Test Plan Added mdtest that failed before this PR (the second snippet -- the first snippet always passed.) --- .../resources/mdtest/pep695_type_aliases.md | 26 +++++++++++++++++++ crates/ty_python_semantic/src/types/infer.rs | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/crates/ty_python_semantic/resources/mdtest/pep695_type_aliases.md b/crates/ty_python_semantic/resources/mdtest/pep695_type_aliases.md index 904f08099a..32f64a246a 100644 --- a/crates/ty_python_semantic/resources/mdtest/pep695_type_aliases.md +++ b/crates/ty_python_semantic/resources/mdtest/pep695_type_aliases.md @@ -75,6 +75,32 @@ def f(x: T): reveal_type(b) # revealed: str ``` +## Scoping + +PEP 695 type aliases delay runtime evaluation of their right-hand side, so they are a lazy (not +eager) nested scope. + +```py +type Alias = Foo | str + +def f(x: Alias): + reveal_type(x) # revealed: Foo | str + +class Foo: + pass +``` + +But narrowing of names used in the type alias is still respected: + +```py +def _(flag: bool): + t = int if flag else None + if t is not None: + type Alias = t | str + def f(x: Alias): + reveal_type(x) # revealed: int | str +``` + ## Generic type aliases ```py diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs index c9fc52c6f8..27c23dcf97 100644 --- a/crates/ty_python_semantic/src/types/infer.rs +++ b/crates/ty_python_semantic/src/types/infer.rs @@ -2344,7 +2344,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { } fn infer_type_alias(&mut self, type_alias: &ast::StmtTypeAlias) { - self.infer_annotation_expression(&type_alias.value, DeferredExpressionState::Deferred); + self.infer_annotation_expression(&type_alias.value, DeferredExpressionState::None); } /// If the current scope is a method inside an enclosing class,