Repository: astral-sh/ruff
File: crates/ruff_python_parser/src/semantic_errors.rs (Rust)

Code before:
                // def f[T, *T](): ...    # star is still duplicate
                // def f[T, **T](): ...   # as is double star
                Self::add_error(
                    ctx,
                    SemanticSyntaxErrorKind::DuplicateTypeParameter,
                    type_param.range(),
                );
            }
        }
    }

    fn type_parameter_default_order<Ctx: SemanticSyntaxContext>(
        type_params: &ast::TypeParams,
        ctx: &Ctx,
    ) {
        let mut seen_default = false;
        for type_param in type_params.iter() {
            let has_default = match type_param {
                ast::TypeParam::TypeVar(ast::TypeParamTypeVar { default, .. })
                | ast::TypeParam::TypeVarTuple(ast::TypeParamTypeVarTuple { default, .. })
                | ast::TypeParam::ParamSpec(ast::TypeParamParamSpec { default, .. }) => {
                    default.is_some()
                }
            };

            if seen_default && !has_default {
                // test_err type_parameter_default_order
                // class C[T = int, U]: ...
                Self::add_error(
                    ctx,
                    SemanticSyntaxErrorKind::TypeParameterDefaultOrder(
                        type_param.name().id.to_string(),
                    ),
                    type_param.range(),
                );
            }
            if has_default {
                seen_default = true;
            }
        }
    }

    fn duplicate_parameter_name<Ctx: SemanticSyntaxContext>(
        parameters: &ast::Parameters,
        ctx: &Ctx,
    ) {
        if parameters.len() < 2 {
            return;
        }

        let mut all_arg_names =

Review comment (suggestion):
Let's add some cases where the default is not at the start of the list and it has multiple non-default type parameter following a type parameter with default like:
```py
class C[T1, T2 = int, T3, T4]: ...
```

Code after:
                Self::add_error(
                    ctx,
                    SemanticSyntaxErrorKind::DuplicateTypeParameter,
                    type_param.range(),
                );
            }
        }
    }

    fn type_parameter_default_order<Ctx: SemanticSyntaxContext>(
        type_params: &ast::TypeParams,
        ctx: &Ctx,
    ) {
        let mut seen_default = false;
        for type_param in type_params.iter() {
            let has_default = match type_param {
                ast::TypeParam::TypeVar(ast::TypeParamTypeVar { default, .. })
                | ast::TypeParam::TypeVarTuple(ast::TypeParamTypeVarTuple { default, .. })
                | ast::TypeParam::ParamSpec(ast::TypeParamParamSpec { default, .. }) => {
                    default.is_some()
                }
            };

            if seen_default && !has_default {
                // test_err type_parameter_default_order
                // class C[T = int, U]: ...
                // class C[T1, T2 = int, T3, T4]: ...
                // type Alias[T = int, U] = ...
                Self::add_error(
                    ctx,
                    SemanticSyntaxErrorKind::TypeParameterDefaultOrder(
                        type_param.name().id.to_string(),
                    ),
                    type_param.range(),
                );
            }
            if has_default {
                seen_default = true;
            }
        }
    }

    fn duplicate_parameter_name<Ctx: SemanticSyntaxContext>(
        parameters: &ast::Parameters,
        ctx: &Ctx,
    ) {
        if parameters.len() < 2 {
            return;
        }

        let mut all_arg_names =