diff --git a/crates/ty_python_semantic/resources/mdtest/narrow/type.md b/crates/ty_python_semantic/resources/mdtest/narrow/type.md index 0376ca8d04..ef754d021a 100644 --- a/crates/ty_python_semantic/resources/mdtest/narrow/type.md +++ b/crates/ty_python_semantic/resources/mdtest/narrow/type.md @@ -70,6 +70,56 @@ def _(x: A | B, y: A | C): reveal_type(y) # revealed: A ``` +## No narrowing for `type(x) is C[int]` + +At runtime, `type(x)` will never return a generic alias object (only ever a class-literal object), +so no narrowing can occur if `type(x)` is compared with a generic alias object. + +```toml +[environment] +python-version = "3.12" +``` + +```py +class A[T]: ... +class B: ... + +def f(x: A[int] | B): + if type(x) is A[int]: + # this branch is actually unreachable -- we *could* reveal `Never` here! + reveal_type(x) # revealed: A[int] | B + else: + reveal_type(x) # revealed: A[int] | B + + if type(x) is A: + # TODO: this should be `A[int]`, but `A[int] | B` would be better than `Never` + reveal_type(x) # revealed: Never + else: + reveal_type(x) # revealed: A[int] | B + + if type(x) is B: + reveal_type(x) # revealed: B + else: + reveal_type(x) # revealed: A[int] | B + + if type(x) is not A[int]: + reveal_type(x) # revealed: A[int] | B + else: + # this branch is actually unreachable -- we *could* reveal `Never` here! + reveal_type(x) # revealed: A[int] | B + + if type(x) is not A: + reveal_type(x) # revealed: A[int] | B + else: + # TODO: this should be `A[int]`, but `A[int] | B` would be better than `Never` + reveal_type(x) # revealed: Never + + if type(x) is not B: + reveal_type(x) # revealed: A[int] | B + else: + reveal_type(x) # revealed: B +``` + ## `type(x) == C`, `type(x) != C` No narrowing can occur for equality comparisons, since there might be a custom `__eq__` diff --git a/crates/ty_python_semantic/src/types/narrow.rs b/crates/ty_python_semantic/src/types/narrow.rs index 39c2ba402d..8569c961d5 100644 --- a/crates/ty_python_semantic/src/types/narrow.rs +++ b/crates/ty_python_semantic/src/types/narrow.rs @@ -756,12 +756,8 @@ impl<'db, 'ast> NarrowingConstraintsBuilder<'db, 'ast> { node_index: _, }, }) if keywords.is_empty() => { - let rhs_class = match rhs_ty { - Type::ClassLiteral(class) => class, - Type::GenericAlias(alias) => alias.origin(self.db), - _ => { - continue; - } + let Type::ClassLiteral(rhs_class) = rhs_ty else { + continue; }; let target = match &**args {