diff --git a/crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_type_param_order.md b/crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_type_param_order.md index d48dd684a5..2b5d956f9b 100644 --- a/crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_type_param_order.md +++ b/crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_type_param_order.md @@ -13,6 +13,13 @@ from typing import TypeVar, Generic T1 = TypeVar("T1", default=int) T2 = TypeVar("T2") T3 = TypeVar("T3") +DefaultStrT = TypeVar("DefaultStrT", default=str) + +class SubclassMe(Generic[T1, DefaultStrT]): + x: DefaultStrT + +class Baz(SubclassMe[int, DefaultStrT]): + pass class Foo(Generic[T1, T2]): # error: [invalid-type-param-order] pass diff --git a/crates/ty_python_semantic/resources/mdtest/snapshots/invalid_type_param_o…_-_Invalid_Type_Param_O…_(8ff6f101710809cb).snap b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid_type_param_o…_-_Invalid_Type_Param_O…_(8ff6f101710809cb).snap index 51ef43c454..74cc600ed1 100644 --- a/crates/ty_python_semantic/resources/mdtest/snapshots/invalid_type_param_o…_-_Invalid_Type_Param_O…_(8ff6f101710809cb).snap +++ b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid_type_param_o…_-_Invalid_Type_Param_O…_(8ff6f101710809cb).snap @@ -17,39 +17,46 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_type 3 | T1 = TypeVar("T1", default=int) 4 | T2 = TypeVar("T2") 5 | T3 = TypeVar("T3") - 6 | - 7 | class Foo(Generic[T1, T2]): # error: [invalid-type-param-order] - 8 | pass - 9 | -10 | class Bar(Generic[T2, T1, T3]): # error: [invalid-type-param-order] -11 | pass + 6 | DefaultStrT = TypeVar("DefaultStrT", default=str) + 7 | + 8 | class SubclassMe(Generic[T1, DefaultStrT]): + 9 | x: DefaultStrT +10 | +11 | class Baz(SubclassMe[int, DefaultStrT]): +12 | pass +13 | +14 | class Foo(Generic[T1, T2]): # error: [invalid-type-param-order] +15 | pass +16 | +17 | class Bar(Generic[T2, T1, T3]): # error: [invalid-type-param-order] +18 | pass ``` # Diagnostics ``` error[invalid-type-param-order]: Type parameter T2 without a default follows type parameter with a default - --> src/mdtest_snippet.py:7:7 - | -5 | T3 = TypeVar("T3") -6 | -7 | class Foo(Generic[T1, T2]): # error: [invalid-type-param-order] - | ^^^^^^^^^^^^^^^^^^^^ -8 | pass - | + --> src/mdtest_snippet.py:14:7 + | +12 | pass +13 | +14 | class Foo(Generic[T1, T2]): # error: [invalid-type-param-order] + | ^^^^^^^^^^^^^^^^^^^^ +15 | pass + | info: rule `invalid-type-param-order` is enabled by default ``` ``` error[invalid-type-param-order]: Type parameter T3 without a default follows type parameter with a default - --> src/mdtest_snippet.py:10:7 + --> src/mdtest_snippet.py:17:7 | - 8 | pass - 9 | -10 | class Bar(Generic[T2, T1, T3]): # error: [invalid-type-param-order] +15 | pass +16 | +17 | class Bar(Generic[T2, T1, T3]): # error: [invalid-type-param-order] | ^^^^^^^^^^^^^^^^^^^^^^^^ -11 | pass +18 | pass | info: rule `invalid-type-param-order` is enabled by default diff --git a/crates/ty_python_semantic/src/types/infer/builder.rs b/crates/ty_python_semantic/src/types/infer/builder.rs index 022bd2f82c..fc0712d675 100644 --- a/crates/ty_python_semantic/src/types/infer/builder.rs +++ b/crates/ty_python_semantic/src/types/infer/builder.rs @@ -951,22 +951,23 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { } if self.context.is_lint_enabled(&INVALID_TYPE_PARAM_ORDER) { - let type_vars = class.typevars_referenced_in_definition(self.db()); - let mut seen_default = false; - for type_var in type_vars { - let has_default = type_var - .typevar(self.db()) - .default_type(self.db()) - .is_some(); - if seen_default && !has_default { - report_invalid_type_param_order( - &self.context, - class, - type_var.typevar(self.db()).name(self.db()).as_str(), - ); - } - if has_default { - seen_default = true; + if let Some(generic_context) = class.generic_context(self.db()) { + let mut seen_default = false; + + for bound_typevar in generic_context.variables(self.db()) { + let typevar = bound_typevar.typevar(self.db()); + let has_default = typevar.default_type(self.db()).is_some(); + + if seen_default && !has_default { + report_invalid_type_param_order( + &self.context, + class, + typevar.name(self.db()).as_str(), + ); + } + if has_default { + seen_default = true; + } } } }