[ty] Reduce false positives for ParamSpecs and TypeVarTuples (#20239)

This commit is contained in:
Alex Waygood 2025-09-04 23:34:37 +01:00 committed by GitHub
parent 08c1d3660c
commit 888a22e849
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 44 additions and 29 deletions

View file

@ -28,6 +28,23 @@ def i(callback: Callable[Concatenate[int, P], R_co], *args: P.args, **kwargs: P.
class Foo: class Foo:
def method(self, x: Self): def method(self, x: Self):
reveal_type(x) # revealed: Self@method reveal_type(x) # revealed: Self@method
def ex2(msg: str):
def wrapper(fn: Callable[P, R_co]) -> Callable[P, R_co]:
def wrapped(*args: P.args, **kwargs: P.kwargs) -> R_co:
print(msg)
return fn(*args, **kwargs)
return wrapped
return wrapper
def ex3(msg: str):
P = ParamSpec("P")
def wrapper(fn: Callable[P, R_co]) -> Callable[P, R_co]:
def wrapped(*args: P.args, **kwargs: P.kwargs) -> R_co:
print(msg)
return fn(*args, **kwargs)
return wrapped
return wrapper
``` ```
## Type expressions ## Type expressions

View file

@ -125,6 +125,7 @@ use crate::types::typed_dict::{
validate_typed_dict_key_assignment, validate_typed_dict_key_assignment,
}; };
use crate::types::unpacker::{UnpackResult, Unpacker}; use crate::types::unpacker::{UnpackResult, Unpacker};
use crate::types::visitor::any_over_type;
use crate::types::{ use crate::types::{
CallDunderError, CallableType, ClassLiteral, ClassType, DataclassParams, DynamicType, CallDunderError, CallableType, ClassLiteral, ClassType, DataclassParams, DynamicType,
IntersectionBuilder, IntersectionType, KnownClass, KnownInstanceType, LintDiagnosticGuard, IntersectionBuilder, IntersectionType, KnownClass, KnownInstanceType, LintDiagnosticGuard,
@ -9271,8 +9272,9 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
let typevars: Result<FxOrderSet<_>, GenericContextError> = typevars let typevars: Result<FxOrderSet<_>, GenericContextError> = typevars
.iter() .iter()
.map(|typevar| match typevar { .map(|typevar| {
Type::KnownInstance(KnownInstanceType::TypeVar(typevar)) => bind_typevar( if let Type::KnownInstance(KnownInstanceType::TypeVar(typevar)) = typevar {
bind_typevar(
self.db(), self.db(),
self.module(), self.module(),
self.index, self.index,
@ -9280,17 +9282,17 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
self.typevar_binding_context, self.typevar_binding_context,
*typevar, *typevar,
) )
.ok_or(GenericContextError::InvalidArgument), .ok_or(GenericContextError::InvalidArgument)
Type::Dynamic(DynamicType::TodoUnpack) => Err(GenericContextError::NotYetSupported), } else if any_over_type(self.db(), *typevar, &|ty| match ty {
Type::NominalInstance(nominal) Type::Dynamic(DynamicType::TodoUnpack) => true,
if matches!( Type::NominalInstance(nominal) => matches!(
nominal.class(self.db()).known(self.db()), nominal.class(self.db()).known(self.db()),
Some(KnownClass::TypeVarTuple | KnownClass::ParamSpec) Some(KnownClass::TypeVarTuple | KnownClass::ParamSpec)
) => ),
{ _ => false,
}) {
Err(GenericContextError::NotYetSupported) Err(GenericContextError::NotYetSupported)
} } else {
_ => {
if let Some(builder) = if let Some(builder) =
self.context.report_lint(&INVALID_ARGUMENT_TYPE, value_node) self.context.report_lint(&INVALID_ARGUMENT_TYPE, value_node)
{ {
@ -11265,19 +11267,15 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
// `Callable[]`. // `Callable[]`.
return None; return None;
} }
match self.infer_name_load(name) { if any_over_type(self.db(), self.infer_name_load(name), &|ty| match ty {
Type::Dynamic(DynamicType::TodoPEP695ParamSpec) => { Type::Dynamic(DynamicType::TodoPEP695ParamSpec) => true,
return Some(Parameters::todo()); Type::NominalInstance(nominal) => nominal
}
Type::NominalInstance(nominal)
if nominal
.class(self.db()) .class(self.db())
.is_known(self.db(), KnownClass::ParamSpec) => .is_known(self.db(), KnownClass::ParamSpec),
{ _ => false,
}) {
return Some(Parameters::todo()); return Some(Parameters::todo());
} }
_ => {}
}
} }
_ => {} _ => {}
} }