use crate::{
    Db, ProgramEnvironment,
    reachability::ReachabilityConstraintsExtension,
    types::{
        KnownClass, KnownInstanceType, ParamSpecAttrKind, SubclassOfInner, SubclassOfType, Type,
        TypeContext, TypeVarKind, UnionType,
        constraints::ConstraintSetBuilder,
        diagnostic::{
            ABSTRACT_AND_FINAL_METHOD, FINAL_ON_NON_METHOD, INVALID_PARAMETER_DEFAULT,
            INVALID_PARAMSPEC, INVALID_TYPE_FORM, UNSOUND_RETURN_STATEMENT, USELESS_OVERLOAD_BODY,
            add_type_expression_reference_link, is_invalid_typed_dict_literal,
            report_implicit_return_type, report_invalid_generator_function_return_type,
            report_invalid_return_type, report_shadowed_type_variable,
            report_unsound_return_statement,
        },
        function::{
            FunctionBodyKind, FunctionDecorators, FunctionLiteral, FunctionType, KnownFunction,
            OverloadLiteral, function_body_kind, is_implicit_classmethod,
            same_module_uncached_raw_signature,
        },
        generics::{enclosing_generic_contexts, typing_self},
        infer::{
            InferenceFlags, TypeExpressionFlags, TypeInferenceBuilder,
            builder::{
                DeclaredAndInferredType, DeferredExpressionState, TypeAndRange,
                validate_paramspec_components,
            },
            function_known_decorator_flags, function_known_decorators, infer_statement_types,
            nearest_enclosing_function, original_class_type,
        },
        infer_scope_types,
        relation::TypeRelation,
        signatures::ReturnCallableTypeVarScope,
        tuple::{TupleSpecBuilder, TupleType},
        typed_dict::extract_unpacked_typed_dict_keys_from_kwargs_annotation,
        typevar::TypeVarSet,
    },
};
use ty_python_core::{
    UseDefMap,
    definition::{Definition, DefinitionKind},
    scope::NodeWithScopeRef,
};

use ruff_python_ast as ast;
use ruff_text_size::Ranged;

fn parameters_have_annotations(parameters: &ast::Parameters) -> bool {
    parameters
        .iter_non_variadic_params()
        .any(|param| param.parameter.annotation.is_some())
        || parameters
            .vararg
            .as_deref()
            .is_some_and(|param| param.annotation.is_some())
        || parameters
            .kwarg
            .as_deref()
            .is_some_and(|param| param.annotation.is_some())
}

/// Whether a non-static method receives an instance or the class itself.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum MethodReceiverKind {
    Instance,
    Class,
}

impl MethodReceiverKind {
    /// Classifies methods by their decorators and implicit class-receiver rules.
    ///
    /// Free functions and ordinary static methods have no receiver; `__new__` receives the class.
    ///
    /// ```python
    /// class Example:
    ///     def instance(self): ...
    ///     @classmethod
    ///     def class_method(cls): ...
    ///     @staticmethod
    ///     def static_method(): ...
    /// ```
    fn from_function<'db>(
        db: &'db dyn Db,
        definition: Definition<'db>,
        function: &ast::StmtFunctionDef,
    ) -> Option<Self> {
        if !definition.scope(db).scope(db).kind().is_class() {
            return None;
        }

        let decorators = function_known_decorator_flags(db, definition);
        if decorators.contains(FunctionDecorators::STATICMETHOD) && function.name.id != "__new__" {
            return None;
        }

        if decorators.contains(FunctionDecorators::CLASSMETHOD)
            || is_implicit_classmethod(&function.name)
            || function.name.id == "__new__"
        {
            Some(Self::Class)
        } else {
            Some(Self::Instance)
        }
    }

    /// Accepts only `Self` for an instance receiver and `type[Self]` for a class receiver.
    fn accepts_annotation(self, db: &dyn Db, annotation: Type<'_>) -> bool {
        match (self, annotation) {
            (Self::Instance, Type::TypeVar(typevar)) => typevar.typevar(db).is_self(db),
            (Self::Class, Type::SubclassOf(subclass)) => {
                matches!(
                    subclass.subclass_of(),
                    SubclassOfInner::TypeVar(typevar) if typevar.typevar(db).is_self(db)
                )
            }
            _ => false,
        }
    }
}

/// Return type policy for checking explicit `return` statements in a function body.
#[derive(Debug, Copy, Clone)]
struct ExpectedReturnType<'db> {
    /// The externally-visible return type.
    public: Type<'db>,
    /// The return type as seen from inside the function body.
    lexical: Type<'db>,
}

impl<'db> ExpectedReturnType<'db> {
    /// Creates the expected return type policy for `function`.
    fn from_function(db: &'db dyn Db, function: FunctionType<'db>) -> Self {
        /// Normalizes special return annotations to the type actually returned by expressions.
        fn normalize<'db>(
            db: &'db dyn Db,
            env: &ProgramEnvironment<'db>,
            ty: Type<'db>,
        ) -> Type<'db> {
            match ty.resolve_type_alias(db) {
                Type::TypeIs(_) | Type::TypeGuard(_) => KnownClass::Bool.to_instance(db, env),
                _ => ty,
            }
        }

        let env = ProgramEnvironment::from_file(function.program_file(db));
        let public = normalize(
            db,
            &env,
            same_module_uncached_raw_signature(db, function, ReturnCallableTypeVarScope::Public)
                .return_ty,
        );
        let lexical = normalize(
            db,
            &env,
            same_module_uncached_raw_signature(db, function, ReturnCallableTypeVarScope::Lexical)
                .return_ty,
        );

        Self { public, lexical }
    }

    /// Returns the externally-visible return type.
    fn public(self) -> Type<'db> {
        self.public
    }

    /// Returns `true` if `ty` is accepted by either the public return type or the lexical return
    /// type.
    fn accepts(
        self,
        db: &'db dyn Db,
        env: &ProgramEnvironment<'db>,
        ty: Type<'db>,
        relation: TypeRelation,
    ) -> bool {
        let builder = ConstraintSetBuilder::new();

        let check =
            |target| ty.has_relation_to(db, env, target, &builder, TypeVarSet::None, relation);

        check(self.public)
            .or(db, &builder, || check(self.lexical))
            .is_always_satisfied(db, env)
    }
}

impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
    pub(super) fn infer_function_body(&mut self, function: &ast::StmtFunctionDef) {
        fn can_implicitly_return_none<'db>(db: &'db dyn Db, use_def: &UseDefMap<'db>) -> bool {
            !use_def
                .reachability_constraints()
                .evaluate(
                    db,
                    use_def.predicates(),
                    use_def.end_of_scope_reachability(),
                )
                .is_always_false()
        }

        let env = self.program_environment();
        let db = self.db();

        // Parameters are odd: they are Definitions in the function body scope, but have no
        // constituent nodes that are part of the function body. In order to get diagnostics
        // merged/emitted for them, we need to explicitly infer their definitions here.
        for parameter in &function.parameters {
            self.infer_definition(parameter);
        }

        validate_paramspec_components(&self.context, self.index, &function.parameters, |expr| {
            self.file_expression_type(expr)
        });
        self.validate_unpacked_typed_dict_kwargs(&function.parameters);

        self.infer_body(&function.body);

        if let Some(returns) = function.returns.as_deref() {
            let has_empty_body = self.return_types_and_ranges.is_empty()
                && function_body_kind(db, env, function, |expr| self.expression_type(expr))
                    == FunctionBodyKind::Stub;

            let mut enclosing_class_context = None;

            if has_empty_body {
                if self.in_stub() {
                    return;
                }
                if self.in_function_overload_or_abstractmethod() {
                    return;
                }
                if self.is_in_type_checking_block(self.scope(), function) {
                    return;
                }
                if let Some(class) = self.class_context_of_current_method() {
                    enclosing_class_context = Some(class);
                    if class.is_protocol(db) {
                        return;
                    }
                }
            }

            let enclosing_function = nearest_enclosing_function(db, self.index, self.scope())
                .expect("should be in a function body scope");
            let declared_ty = same_module_uncached_raw_signature(
                db,
                enclosing_function,
                ReturnCallableTypeVarScope::Public,
            )
            .return_ty;
            let expected_return = ExpectedReturnType::from_function(db, enclosing_function);
            let expected_ty = expected_return.public();

            let scope_id = self.index.node_scope(NodeWithScopeRef::Function(function));
            if scope_id.is_generator_function(self.index) {
                // TODO: `AsyncGeneratorType` and `GeneratorType` are both generic classes.
                //
                // If type arguments are supplied to `(Async)Iterable`, `(Async)Iterator`,
                // `(Async)Generator` or `(Async)GeneratorType` in the return annotation,
                // we should iterate over the `yield` expressions and `return` statements
                // in the function to check that they are consistent with the type arguments
                // provided. Once we do this, the `.to_instance_unknown` call below should
                // be replaced with `.to_specialized_instance`.
                let inferred_return = if function.is_async {
                    KnownClass::AsyncGeneratorType
                } else {
                    KnownClass::GeneratorType
                };
                if !inferred_return
                    .to_instance_unknown(db, env)
                    .is_assignable_to(db, env, expected_ty)
                {
                    report_invalid_generator_function_return_type(
                        &self.context,
                        returns.range(),
                        inferred_return,
                        declared_ty,
                    );
                }

                if let Some(expected_return_ty) = declared_ty.generator_return_type(db, env) {
                    for &return_statement in &self.return_types_and_ranges {
                        if !return_statement
                            .ty
                            .is_assignable_to(db, env, expected_return_ty)
                        {
                            report_invalid_return_type(
                                &self.context,
                                return_statement.range,
                                returns.range(),
                                expected_return_ty,
                                return_statement.ty,
                            );
                        } else if self.context.is_lint_enabled(&UNSOUND_RETURN_STATEMENT)
                            && expected_return_ty.is_fully_static(db, env)
                            && !return_statement.ty.is_pure_redundant_with(
                                db,
                                env,
                                expected_return_ty,
                            )
                        {
                            report_unsound_return_statement(
                                &self.context,
                                return_statement.range,
                                returns.range(),
                                expected_return_ty,
                                return_statement.ty,
                            );
                        }
                    }

                    let use_def = self.index.use_def_map(scope_id);

                    if can_implicitly_return_none(db, use_def)
                        && !Type::none(db, env).is_assignable_to(db, env, expected_return_ty)
                    {
                        let no_return = self.return_types_and_ranges.is_empty();
                        report_implicit_return_type(
                            &self.context,
                            returns.range(),
                            expected_return_ty,
                            false,
                            None,
                            no_return,
                        );
                    }
                }

                return;
            }

            for return_statement in
                self.return_types_and_ranges
                    .iter()
                    .copied()
                    .filter_map(|ty_range| match ty_range.ty {
                        // We skip `is_assignable_to` checks for `NotImplemented`,
                        // so we remove it beforehand.
                        Type::Union(union) => Some(TypeAndRange {
                            ty: union.filter(db, |ty| !ty.is_notimplemented(db)),
                            range: ty_range.range,
                        }),
                        ty if ty.is_notimplemented(db) => None,
                        _ => Some(ty_range),
                    })
            {
                if !expected_return.accepts(
                    db,
                    env,
                    return_statement.ty,
                    TypeRelation::Assignability,
                ) {
                    report_invalid_return_type(
                        &self.context,
                        return_statement.range,
                        returns.range(),
                        declared_ty,
                        return_statement.ty,
                    );
                } else if self.context.is_lint_enabled(&UNSOUND_RETURN_STATEMENT)
                    && expected_return.public.is_fully_static(db, env)
                    && !expected_return.accepts(
                        db,
                        env,
                        return_statement.ty,
                        TypeRelation::Redundancy { pure: true },
                    )
                {
                    report_unsound_return_statement(
                        &self.context,
                        return_statement.range,
                        returns.range(),
                        declared_ty,
                        return_statement.ty,
                    );
                }
            }

            let use_def = self.index.use_def_map(scope_id);
            if can_implicitly_return_none(db, use_def)
                && !Type::none(db, env).is_assignable_to(db, env, expected_ty)
            {
                let no_return = self.return_types_and_ranges.is_empty();
                report_implicit_return_type(
                    &self.context,
                    returns.range(),
                    declared_ty,
                    has_empty_body,
                    enclosing_class_context,
                    no_return,
                );
            }
        }
    }

    pub(super) fn infer_function_definition_statement(&mut self, function: &ast::StmtFunctionDef) {
        self.infer_definition(function);
    }

    pub(super) fn infer_function_definition(
        &mut self,
        function: &ast::StmtFunctionDef,
        definition: Definition<'db>,
    ) {
        let ast::StmtFunctionDef {
            range: _,
            node_index: _,
            is_async: _,
            name,
            type_params,
            parameters,
            returns: _,
            body: _,
            decorator_list,
        } = function;

        let db = self.db();

        let decorator_inference =
            (!decorator_list.is_empty()).then(|| function_known_decorators(self.db(), definition));
        if let Some(decorator_inference) = decorator_inference.as_ref() {
            self.context.extend(decorator_inference.diagnostics());
            self.expressions
                .extend(decorator_inference.expression_types());
            self.bindings.extend(decorator_inference.bindings());
            self.called_functions
                .extend(decorator_inference.called_functions().iter().copied());
        }

        let mut decorator_types_and_nodes = Vec::with_capacity(decorator_list.len());
        let mut function_decorators = FunctionDecorators::empty();
        let mut dataclass_transformer_params = None;
        let mut final_decorator = None;

        for decorator in decorator_list {
            let decorator_type = decorator_inference
                .as_ref()
                .and_then(|decorator_inference| {
                    decorator_inference.expression_type(&decorator.expression)
                })
                .unwrap_or_else(Type::unknown);
            let decorator_function_decorator =
                FunctionDecorators::from_decorator_type(db, decorator_type);
            function_decorators |= decorator_function_decorator;

            match decorator_type {
                Type::FunctionLiteral(function) => match function.known(db) {
                    Some(KnownFunction::NoTypeCheck) => {
                        // If the function is decorated with the `no_type_check` decorator,
                        // we need to suppress any errors that come after the decorators.
                        self.context.inference_flags |= InferenceFlags::IN_NO_TYPE_CHECK;
                        continue;
                    }
                    Some(KnownFunction::Final) => {
                        final_decorator = Some(decorator);
                        continue;
                    }
                    _ => {}
                },
                Type::DataclassTransformer(params) => {
                    dataclass_transformer_params = Some(params);
                }
                _ => {}
            }
            if !decorator_function_decorator.is_empty() {
                continue;
            }

            decorator_types_and_nodes.push((decorator_type, decorator));
        }

        // Check for `@final` applied to non-method functions.
        // `@final` is only meaningful on methods and classes.
        if let Some(final_decorator) = final_decorator
            && !self
                .index
                .scope(self.scope().file_scope_id(db))
                .kind()
                .is_class()
            && let Some(builder) = self
                .context
                .report_lint(&FINAL_ON_NON_METHOD, final_decorator)
        {
            let mut diagnostic = builder.into_diagnostic(format_args!(
                "`@final` cannot be applied to non-method function `{name}`",
            ));
            diagnostic.info("`@final` is only meaningful on methods and classes");
        }

        if function_decorators
            .contains(FunctionDecorators::ABSTRACT_METHOD | FunctionDecorators::FINAL)
            && self
                .index
                .scope(self.scope().file_scope_id(db))
                .kind()
                .is_class()
            && let Some(builder) = self.context.report_lint(&ABSTRACT_AND_FINAL_METHOD, name)
        {
            builder.into_diagnostic(format_args!(
                "Method `{name}` cannot be both `@abstractmethod` and `@final`",
            ));
        }

        let has_defaults = parameters
            .iter_non_variadic_params()
            .any(|param| param.default.is_some());

        // If there are type params, parameters and returns are evaluated in that scope. Otherwise,
        // we defer the inference of any parameter and return annotations. That ensures that we do
        // not add any spurious salsa cycles when applying decorators below. (Applying a decorator
        // requires getting the signature of this function definition, which in turn requires
        // (lazily) inferring the parameter and return types.) If defaults exist, we also defer so
        // they can be inferred once with type context in the enclosing scope.
        let has_signature_annotations =
            function.returns.is_some() || parameters_have_annotations(parameters);
        if (type_params.is_none() && has_signature_annotations) || has_defaults {
            self.deferred.insert(definition);
        }

        let known_function = KnownFunction::try_from_definition_and_name(db, definition, name);

        // `type_check_only` is itself not available at runtime
        if known_function == Some(KnownFunction::TypeCheckOnly) {
            function_decorators |= FunctionDecorators::TYPE_CHECK_ONLY;
        }

        let body_scope = self
            .index
            .node_scope(NodeWithScopeRef::Function(function))
            .to_scope_id(db, self.program_file());

        let overload_literal = OverloadLiteral::new(
            db,
            &name.id,
            known_function,
            body_scope,
            function_decorators,
            None,
            dataclass_transformer_params,
            function.returns.is_some(),
        );
        let function_literal = FunctionLiteral::new(db, overload_literal);
        let function_type = FunctionType::new(db, function_literal, None);
        let is_decorated_overload_implementation = !decorator_types_and_nodes.is_empty()
            && function_literal.has_separate_implementation(db);
        let is_decorated_overload =
            !decorator_types_and_nodes.is_empty() && overload_literal.is_overload(db);

        let mut inferred_ty = Type::FunctionLiteral(
            if is_decorated_overload_implementation || is_decorated_overload {
                FunctionType::new(db, function_literal.without_overloads(), None)
            } else {
                function_type
            },
        );
        if !decorator_list.is_empty() {
            self.undecorated_type = Some(inferred_ty);
        }

        // Check that the function's own type parameters don't shadow
        // type variables from enclosing scopes (by name).
        if let Some(type_params) = &function.type_params {
            let current_scope = self.scope().file_scope_id(db);
            for type_param in type_params.iter() {
                let param_name = type_param.name();
                for enclosing in enclosing_generic_contexts(self.db(), self.index, current_scope) {
                    if let Some(other_typevar) = enclosing.binds_named_typevar(db, &param_name.id) {
                        let kind = match type_param {
                            ast::TypeParam::TypeVar(_) => TypeVarKind::Pep695TypeVar,
                            ast::TypeParam::ParamSpec(_) => TypeVarKind::Pep695ParamSpec,
                            ast::TypeParam::TypeVarTuple(_) => TypeVarKind::Pep695TypeVarTuple,
                        };
                        report_shadowed_type_variable(
                            &self.context,
                            &param_name.id,
                            "function",
                            &function.name.id,
                            function.name.range(),
                            kind,
                            other_typevar,
                        );
                    }
                }
            }
        }

        for (decorator_ty, decorator_node) in decorator_types_and_nodes.iter().rev() {
            inferred_ty = if let Type::KnownInstance(KnownInstanceType::Deprecated(deprecated)) =
                decorator_ty
                && let Type::FunctionLiteral(function) = inferred_ty
            {
                Type::FunctionLiteral(function.with_deprecated(db, *deprecated))
            } else {
                self.apply_decorator(*decorator_ty, inferred_ty, decorator_node)
            };
        }

        if is_decorated_overload_implementation {
            let function_type = if let Type::FunctionLiteral(function) = inferred_ty {
                FunctionType::new(
                    db,
                    function_literal
                        .with_last_definition_metadata(db, function.literal(db).last_definition),
                    None,
                )
            } else {
                function_type
            };
            let implementation_callables = inferred_ty
                .try_upcast_to_callable(db, self.program_environment())
                .map_or_else(Box::default, |callables| {
                    callables.iter().copied().collect()
                });
            inferred_ty = Type::FunctionLiteral(
                function_type.with_implementation_callables(db, implementation_callables),
            );
        } else if is_decorated_overload && let Type::FunctionLiteral(function) = inferred_ty {
            inferred_ty = Type::FunctionLiteral(FunctionType::new(
                db,
                function_literal
                    .with_last_definition_metadata(db, function.literal(db).last_definition),
                None,
            ));
        }

        self.add_declaration_with_binding(
            function.into(),
            definition,
            &DeclaredAndInferredType::are_the_same_type(inferred_ty),
        );

        if function_decorators.contains(FunctionDecorators::OVERLOAD) {
            for stmt in &function.body {
                match stmt {
                    ast::Stmt::Pass(_) => continue,
                    ast::Stmt::Expr(ast::StmtExpr { value, .. }) => {
                        if matches!(
                            &**value,
                            ast::Expr::StringLiteral(_) | ast::Expr::EllipsisLiteral(_)
                        ) {
                            continue;
                        }
                    }
                    _ => {}
                }
                let Some(builder) = self.context.report_lint(&USELESS_OVERLOAD_BODY, stmt) else {
                    continue;
                };
                let mut diagnostic = builder.into_diagnostic(format_args!(
                    "Useless body for `@overload`-decorated function `{}`",
                    function.name
                ));
                diagnostic.set_primary_annotation_message("This statement will never be executed");
                diagnostic.info(
                    "`@overload`-decorated functions are solely for type checkers \
                    and must be overwritten at runtime by a non-`@overload`-decorated implementation",
                );
                diagnostic.help("Consider replacing this function body with `...` or `pass`");
                break;
            }
        }
    }

    pub(super) fn infer_function_deferred(
        &mut self,
        definition: Definition<'db>,
        function: &ast::StmtFunctionDef,
    ) {
        let db = self.db();
        let mut prev_in_no_type_check = self
            .context
            .inference_flags
            .replace(InferenceFlags::IN_NO_TYPE_CHECK, true);
        for decorator in &function.decorator_list {
            let decorator_type = self.infer_decorator(decorator);
            if let Type::FunctionLiteral(function) = decorator_type
                && let Some(KnownFunction::NoTypeCheck) = function.known(db)
            {
                // If the function is decorated with the `no_type_check` decorator,
                // we need to suppress any errors that come after the decorators.
                prev_in_no_type_check = true;
                break;
            }
        }
        self.context
            .inference_flags
            .set(InferenceFlags::IN_NO_TYPE_CHECK, prev_in_no_type_check);

        let has_type_params = function.type_params.is_some();
        let has_defaults = function
            .parameters
            .iter_non_variadic_params()
            .any(|param| param.default.is_some());

        let previous_typevar_binding_context = self.typevar_binding_context.replace(definition);

        if !has_type_params {
            self.infer_function_signature_annotations(function, definition);
        }

        if has_defaults {
            // In stub files, default values may reference names that are defined later in the file.
            let in_stub = self.in_stub();
            let previous_deferred_state =
                std::mem::replace(&mut self.deferred_state, in_stub.into());

            // For generic functions, only defaults are inferred here; annotation types come from
            // the type-params scope.
            if has_type_params {
                let type_params_scope = self
                    .index
                    .node_scope(NodeWithScopeRef::FunctionTypeParameters(function))
                    .to_scope_id(db, self.program_file());
                let type_params_inference =
                    infer_scope_types(self.db(), type_params_scope, TypeContext::default());

                for param_with_default in function.parameters.iter_non_variadic_params() {
                    let Some(default) = param_with_default.default.as_deref() else {
                        continue;
                    };
                    let tcx = param_with_default
                        .parameter
                        .annotation
                        .as_deref()
                        .map(|annotation| {
                            TypeContext::new(Some(
                                type_params_inference.expression_type(annotation),
                            ))
                        })
                        .unwrap_or_else(TypeContext::default);
                    self.infer_expression(default, tcx);
                }
            } else {
                for param_with_default in function.parameters.iter_non_variadic_params() {
                    let Some(default) = param_with_default.default.as_deref() else {
                        continue;
                    };
                    let tcx = param_with_default
                        .parameter
                        .annotation
                        .as_deref()
                        .map(|annotation| TypeContext::new(Some(self.expression_type(annotation))))
                        .unwrap_or_else(TypeContext::default);
                    self.infer_expression(default, tcx);
                }
            }

            self.deferred_state = previous_deferred_state;
        }

        self.typevar_binding_context = previous_typevar_binding_context;
    }

    fn infer_return_type_annotation(&mut self, returns: Option<&ast::Expr>) {
        if let Some(returns) = returns {
            self.context.inference_flags |= InferenceFlags::IN_RETURN_TYPE;
            self.infer_type_expression_with_state(
                returns,
                DeferredExpressionState::from(self.defer_annotations()),
            );
            self.context
                .inference_flags
                .remove(InferenceFlags::IN_RETURN_TYPE);
        }
    }

    pub(super) fn infer_function_type_params(&mut self, function: &ast::StmtFunctionDef) {
        let binding_context = self.index.expect_single_definition(function);
        let previous_typevar_binding_context =
            self.typevar_binding_context.replace(binding_context);
        self.infer_function_signature_annotations(function, binding_context);
        self.typevar_binding_context = previous_typevar_binding_context;
    }

    /// Infer an annotated method receiver before the rest of its signature so `Self` can be
    /// validated where it occurs, including inside parsed string annotations.
    ///
    /// ```python
    /// class Example:
    ///     def method(self: object) -> "Self | object": ...
    /// ```
    fn infer_function_signature_annotations(
        &mut self,
        function: &ast::StmtFunctionDef,
        definition: Definition<'db>,
    ) {
        let receiver_is_incompatible = self.infer_method_receiver_annotation(function, definition);
        let previous_incompatible_receiver = self.context.inference_flags.replace(
            InferenceFlags::HAS_INCOMPATIBLE_SELF_RECEIVER,
            receiver_is_incompatible == Some(true),
        );

        self.infer_return_type_annotation(function.returns.as_deref());
        if let Some(type_params) = function.type_params.as_deref() {
            self.infer_type_parameters(type_params);
        }
        self.infer_parameters(&function.parameters, receiver_is_incompatible.is_some());

        self.context.inference_flags.set(
            InferenceFlags::HAS_INCOMPATIBLE_SELF_RECEIVER,
            previous_incompatible_receiver,
        );
    }

    /// Infers an explicitly annotated method receiver before the rest of its signature.
    ///
    /// Returns whether the annotation is incompatible with `Self`, or `None` for functions without
    /// an annotated instance or class receiver.
    fn infer_method_receiver_annotation(
        &mut self,
        function: &ast::StmtFunctionDef,
        definition: Definition<'db>,
    ) -> Option<bool> {
        let receiver = function
            .parameters
            .posonlyargs
            .first()
            .or_else(|| function.parameters.args.first())?;
        let annotation = receiver.parameter.annotation.as_deref()?;
        let receiver_kind = MethodReceiverKind::from_function(self.db(), definition, function)?;

        let previously_in_parameter_annotation = self
            .context
            .inference_flags
            .replace(InferenceFlags::IN_PARAMETER_ANNOTATION, true);
        let annotation_type = self.infer_type_expression_with_state(
            annotation,
            DeferredExpressionState::from(self.defer_annotations()),
        );
        self.context.inference_flags.set(
            InferenceFlags::IN_PARAMETER_ANNOTATION,
            previously_in_parameter_annotation,
        );

        Some(!receiver_kind.accepts_annotation(self.db(), annotation_type))
    }

    fn infer_parameters(
        &mut self,
        parameters: &ast::Parameters,
        first_annotation_already_inferred: bool,
    ) {
        let ast::Parameters {
            range: _,
            node_index: _,
            posonlyargs: _,
            args: _,
            vararg,
            kwonlyargs: _,
            kwarg,
        } = parameters;

        self.context.inference_flags |= InferenceFlags::IN_PARAMETER_ANNOTATION;
        for param_with_default in parameters
            .iter_non_variadic_params()
            .skip(usize::from(first_annotation_already_inferred))
        {
            self.infer_parameter_with_default(param_with_default);
        }
        if let Some(vararg) = vararg {
            self.context.inference_flags |= InferenceFlags::IN_VARARG_ANNOTATION;
            self.infer_parameter(vararg);
            self.context
                .inference_flags
                .remove(InferenceFlags::IN_VARARG_ANNOTATION);
        }
        if let Some(kwarg) = kwarg {
            self.context.inference_flags |= InferenceFlags::IN_KWARG_ANNOTATION;
            self.infer_parameter(kwarg);
            self.context
                .inference_flags
                .remove(InferenceFlags::IN_KWARG_ANNOTATION);
        }
        self.context
            .inference_flags
            .remove(InferenceFlags::IN_PARAMETER_ANNOTATION);
    }

    fn validate_unpacked_typed_dict_kwargs(&mut self, parameters: &ast::Parameters) {
        let db = self.db();
        let env = self.program_environment();
        let Some(kwargs) = parameters.kwarg.as_ref() else {
            return;
        };
        let Some(annotation) = kwargs.annotation.as_deref() else {
            return;
        };
        let annotation_flags = self.file_type_expression_flags(annotation);
        if !annotation_flags.contains(TypeExpressionFlags::UNPACK) {
            return;
        }

        let annotated_type = self.file_expression_type(annotation);
        let Some(unpacked_keys) = extract_unpacked_typed_dict_keys_from_kwargs_annotation(
            db,
            annotated_type,
            annotation_flags,
        ) else {
            if !annotated_type.is_unknown()
                && let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, annotation)
            {
                let diag = builder.into_diagnostic(format_args!(
                    "Unpacked value for `**kwargs` must be a TypedDict, not `{}`",
                    annotated_type.display(db, env)
                ));
                add_type_expression_reference_link(diag);
            }
            return;
        };

        // Legacy PEP 484 positional-only parameters like `def f(__x: int, **kwargs:
        // Unpack[TD])` are not callable by keyword, so they do not overlap with keys
        // accepted through `**kwargs`. The convention only applies to the leading
        // positional-or-keyword parameters that are actually converted to positional-only
        // parameters by `Parameters::from_parameters`.
        let pep_484_positional_only_count = if parameters.posonlyargs.is_empty() {
            parameters
                .args
                .iter()
                .take_while(|parameter| parameter.uses_pep_484_positional_only_convention())
                .count()
        } else {
            0
        };

        let overlapping = parameters
            .iter_non_variadic_params()
            .skip(parameters.posonlyargs.len() + pep_484_positional_only_count)
            .map(|parameter| &parameter.parameter)
            .filter(|parameter| unpacked_keys.contains_key(&parameter.name.id))
            .collect::<Vec<_>>();

        if overlapping.is_empty() {
            return;
        }

        let overlapping_names = overlapping
            .iter()
            .map(|parameter| format!("`{}`", parameter.name.id))
            .collect::<Vec<_>>()
            .join(", ");

        if let Some(builder) = self
            .context
            .report_lint(&INVALID_TYPE_FORM, kwargs.as_ref())
        {
            if overlapping.len() == 1 {
                builder.into_diagnostic(format_args!(
                    "Parameter {overlapping_names} overlaps with unpacked TypedDict key in \
                     `**kwargs` annotation",
                ));
            } else {
                builder.into_diagnostic(format_args!(
                    "Parameters {overlapping_names} overlap with unpacked TypedDict keys in \
                     `**kwargs` annotation",
                ));
            }
        }
    }

    fn infer_parameter_with_default(&mut self, parameter_with_default: &ast::ParameterWithDefault) {
        let ast::ParameterWithDefault {
            range: _,
            node_index: _,
            parameter,
            default: _,
        } = parameter_with_default;

        if let Some(annotation) = parameter.annotation.as_deref() {
            self.infer_type_expression_with_state(
                annotation,
                DeferredExpressionState::from(self.defer_annotations()),
            );
        }
    }

    fn infer_parameter(&mut self, parameter: &ast::Parameter) {
        let ast::Parameter {
            range: _,
            node_index: _,
            name: _,
            annotation,
        } = parameter;

        if let Some(annotation) = annotation.as_deref() {
            self.infer_type_expression_with_state(
                annotation,
                DeferredExpressionState::from(self.defer_annotations()),
            );
        }
    }

    /// Set initial declared type (if annotated) and inferred type for a function-parameter symbol,
    /// in the function body scope.
    ///
    /// The declared type is the annotated type, if any, or `Unknown`.
    ///
    /// The inferred type is the annotated type, if any. If there is no annotation, it is the union
    /// of `Unknown` and the type of the default value, if any.
    ///
    /// Parameter definitions are odd in that they define a symbol in the function-body scope, so
    /// the Definition belongs to the function body scope, but the expressions (annotation and
    /// default value) both belong to outer scopes. (The default value always belongs to the outer
    /// scope in which the function is defined, the annotation belongs either to the outer scope,
    /// or maybe to an intervening type-params scope, if it's a generic function.) So we don't use
    /// `self.infer_expression` or store any expression types here, we just query for the types of
    /// the expressions from their respective scopes.
    ///
    /// It is safe (non-cycle-causing) to query the annotation type via `file_expression_type`
    /// here, because an outer scope can't depend on a definition from an inner scope, so we
    /// shouldn't be in-process of inferring the outer scope here.
    pub(super) fn infer_parameter_definition(
        &mut self,
        parameter_with_default: &'ast ast::ParameterWithDefault,
        definition: Definition<'db>,
    ) {
        let env = self.program_environment();
        let ast::ParameterWithDefault {
            parameter,
            default,
            range: _,
            node_index: _,
        } = parameter_with_default;

        let db = self.db();

        let default_expr = default.as_ref();
        if let Some(annotation) = parameter.annotation.as_ref() {
            let declared_ty = self.file_expression_type(annotation);

            // P.args and P.kwargs are only valid as annotations on *args and **kwargs,
            // not on regular parameters.
            if let Type::TypeVar(typevar) = declared_ty
                && typevar.is_paramspec(db)
                && let Some(attr) = typevar.paramspec_attr(db)
            {
                let name = typevar.name(db);
                let (attr_name, variadic) = match attr {
                    ParamSpecAttrKind::Args => ("args", "*args"),
                    ParamSpecAttrKind::Kwargs => ("kwargs", "**kwargs"),
                };
                if let Some(builder) = self
                    .context
                    .report_lint(&INVALID_PARAMSPEC, annotation.as_ref())
                {
                    builder.into_diagnostic(format_args!(
                        "`{name}.{attr_name}` is only valid for annotating `{variadic}`",
                    ));
                }
            }

            if let Some(default_expr) = default_expr {
                let default_expr = default_expr.as_ref();
                let default_ty = self.file_expression_type(default_expr);

                // Avoid duplicate diagnostics: invalid TypedDict literals already emit specific errors.
                let suppress_invalid_default =
                    is_invalid_typed_dict_literal(db, declared_ty, default_expr.into());
                if !default_ty.is_assignable_to(db, env, declared_ty)
                    && !suppress_invalid_default
                    && !((self.in_stub()
                        || self.in_function_overload_or_abstractmethod()
                        || self.is_in_type_checking_block(self.scope(), default_expr)
                        || self
                            .class_context_of_current_method()
                            .is_some_and(|class| class.is_protocol(db)))
                        && default
                            .as_ref()
                            .is_some_and(|d| d.is_ellipsis_literal_expr()))
                {
                    if let Some(builder) = self
                        .context
                        .report_lint(&INVALID_PARAMETER_DEFAULT, parameter_with_default)
                    {
                        builder.into_diagnostic(format_args!(
                            "Default value of type `{}` is not assignable \
                             to annotated parameter type `{}`",
                            default_ty.display(db, env),
                            declared_ty.display(db, env)
                        ));
                    }
                }
            }

            self.add_declaration_with_binding(
                parameter.into(),
                definition,
                &DeclaredAndInferredType::are_the_same_type(declared_ty),
            );
        } else {
            let ty = if let Some(default_expr) = default_expr {
                let default_ty = self.file_expression_type(default_expr);
                UnionType::from_two_elements(db, env, Type::unknown(), default_ty)
            } else if let Some(ty) = self.special_first_method_parameter_type(parameter) {
                ty
            } else {
                Type::unknown()
            };

            self.add_binding(parameter.into(), definition)
                .insert(self, ty);
        }
    }

    /// Set initial declared/inferred types for a `*args` variadic positional parameter.
    ///
    /// The annotated type is implicitly wrapped in a homogeneous tuple.
    ///
    /// See [`infer_parameter_definition`] doc comment for some relevant observations about scopes.
    ///
    /// [`infer_parameter_definition`]: Self::infer_parameter_definition
    pub(super) fn infer_variadic_positional_parameter_definition(
        &mut self,
        parameter: &'ast ast::Parameter,
        definition: Definition<'db>,
    ) {
        let db = self.db();

        if let Some(annotation) = parameter.annotation() {
            let annotated_type = self.file_expression_type(annotation);
            let has_unpacked_annotation = self
                .file_type_expression_flags(annotation)
                .contains(TypeExpressionFlags::UNPACK);
            let ty = match annotated_type {
                Type::TypeVar(typevar)
                    if has_unpacked_annotation && typevar.is_typevartuple(db) =>
                {
                    Type::tuple(TupleType::new(
                        db,
                        self.program_environment(),
                        &TupleSpecBuilder::with_capacity(0)
                            .concat_variadic_typevar(db, self.program_environment(), typevar)
                            .build(),
                    ))
                }
                _ if has_unpacked_annotation => annotated_type,
                Type::TypeVar(typevar) if typevar.is_paramspec(db) => {
                    match typevar.paramspec_attr(db) {
                        // `*args: P.args`
                        Some(ParamSpecAttrKind::Args) => annotated_type,

                        // `*args: P.kwargs`
                        Some(ParamSpecAttrKind::Kwargs) => {
                            // TODO: Should this diagnostic be raised as part of
                            // `ArgumentTypeChecker`?
                            if let Some(builder) =
                                self.context.report_lint(&INVALID_TYPE_FORM, annotation)
                            {
                                let name = typevar.name(db);
                                let mut diag = builder.into_diagnostic(format_args!(
                                    "`{name}.kwargs` is valid only in `**kwargs` annotation",
                                ));
                                diag.set_primary_annotation_message(format_args!(
                                    "Did you mean `{name}.args`?"
                                ));
                                add_type_expression_reference_link(diag);
                            }
                            Type::homogeneous_tuple(db, self.program_environment(), Type::unknown())
                        }

                        // `*args: P`
                        None => {
                            // The diagnostic for this case is handled in `in_type_expression`.
                            Type::homogeneous_tuple(db, self.program_environment(), Type::unknown())
                        }
                    }
                }
                _ => Type::homogeneous_tuple(db, self.program_environment(), annotated_type),
            };

            self.add_declaration_with_binding(
                parameter.into(),
                definition,
                &DeclaredAndInferredType::are_the_same_type(ty),
            );
        } else {
            let inferred_ty =
                Type::homogeneous_tuple(db, self.program_environment(), Type::unknown());
            self.add_binding(parameter.into(), definition)
                .insert(self, inferred_ty);
        }
    }

    /// Special case for unannotated `cls` and `self` arguments to class methods and instance methods.
    fn special_first_method_parameter_type(
        &mut self,
        parameter: &ast::Parameter,
    ) -> Option<Type<'db>> {
        let env = self.program_environment();
        let db = self.db();
        let file = self.program_file();

        let function_scope_id = self.scope();
        let function_scope = function_scope_id.scope(db);
        let function = function_scope.node().as_function()?;

        let parent_file_scope_id = function_scope.parent()?;
        let mut parent_scope_id = parent_file_scope_id.to_scope_id(db, file);

        // Skip type parameter scopes, if the method itself is generic.
        if parent_scope_id.is_annotation(db) {
            let parent_scope = parent_scope_id.scope(db);
            parent_scope_id = parent_scope.parent()?.to_scope_id(db, file);
        }

        // Return early if this is not a method inside a class.
        let class = parent_scope_id.scope(db).node().as_class()?;

        let method_definition = self.index.expect_single_definition(function);
        let DefinitionKind::Function(function_definition) = method_definition.kind(db) else {
            return None;
        };

        if function_definition
            .node(self.module())
            .parameters
            .index(parameter.name())
            .is_none_or(|index| index != 0)
        {
            return None;
        }

        let function_node = function_definition.node(self.module());
        let receiver_kind =
            MethodReceiverKind::from_function(db, method_definition, function_node)?;

        let class_definition = self.index.expect_single_definition(class);
        let class_literal = original_class_type(db, class_definition)?;
        let typing_self = typing_self(db, self.scope(), Some(method_definition), class_literal);
        match receiver_kind {
            MethodReceiverKind::Class => typing_self.map(|typing_self| {
                SubclassOfType::from(db, env, SubclassOfInner::TypeVar(typing_self))
            }),
            MethodReceiverKind::Instance => typing_self.map(Type::TypeVar),
        }
    }

    /// Set initial declared/inferred types for a `**kwargs` keyword-variadic parameter.
    ///
    /// The annotated type is implicitly wrapped in a string-keyed dictionary.
    ///
    /// See [`infer_parameter_definition`] doc comment for some relevant observations about scopes.
    ///
    /// [`infer_parameter_definition`]: Self::infer_parameter_definition
    pub(super) fn infer_variadic_keyword_parameter_definition(
        &mut self,
        parameter: &'ast ast::Parameter,
        definition: Definition<'db>,
    ) {
        let env = self.program_environment();
        let db = self.db();

        if let Some(annotation) = parameter.annotation() {
            let annotated_type = self.file_expression_type(annotation);
            let ty = if let Type::TypeVar(typevar) = annotated_type
                && typevar.is_paramspec(db)
            {
                match typevar.paramspec_attr(db) {
                    // `**kwargs: P.args`
                    Some(ParamSpecAttrKind::Args) => {
                        // TODO: Should this diagnostic be raised as part of `ArgumentTypeChecker`?
                        if let Some(builder) =
                            self.context.report_lint(&INVALID_TYPE_FORM, annotation)
                        {
                            let name = typevar.name(db);
                            let mut diag = builder.into_diagnostic(format_args!(
                                "`{name}.args` is valid only in `*args` annotation",
                            ));
                            diag.set_primary_annotation_message(format_args!(
                                "Did you mean `{name}.kwargs`?"
                            ));
                            add_type_expression_reference_link(diag);
                        }
                        KnownClass::Dict.to_specialized_instance(
                            db,
                            env,
                            &[KnownClass::Str.to_instance(db, env), Type::unknown()],
                        )
                    }

                    // `**kwargs: P.kwargs`
                    Some(ParamSpecAttrKind::Kwargs) => annotated_type,

                    // `**kwargs: P`
                    None => {
                        // The diagnostic for this case is handled in `in_type_expression`.
                        KnownClass::Dict.to_specialized_instance(
                            db,
                            env,
                            &[KnownClass::Str.to_instance(db, env), Type::unknown()],
                        )
                    }
                }
            } else if extract_unpacked_typed_dict_keys_from_kwargs_annotation(
                db,
                annotated_type,
                self.file_type_expression_flags(annotation),
            )
            .is_some()
            {
                annotated_type
            } else {
                KnownClass::Dict.to_specialized_instance(
                    db,
                    env,
                    &[KnownClass::Str.to_instance(db, env), annotated_type],
                )
            };
            self.add_declaration_with_binding(
                parameter.into(),
                definition,
                &DeclaredAndInferredType::are_the_same_type(ty),
            );
        } else {
            let inferred_ty = KnownClass::Dict.to_specialized_instance(
                db,
                env,
                &[KnownClass::Str.to_instance(db, env), Type::unknown()],
            );

            self.add_binding(parameter.into(), definition)
                .insert(self, inferred_ty);
        }
    }

    /// Set initial declared type (if annotated) and inferred type for a lambda-parameter symbol,
    /// in the lambda body scope.
    pub(super) fn infer_lambda_parameter_definition(
        &mut self,
        index: u32,
        parameter_with_default: &'ast ast::ParameterWithDefault,
        lambda: &'ast ast::ExprLambda,
        definition: Definition<'db>,
    ) {
        let db = self.db();
        let ast::ParameterWithDefault {
            parameter,
            default,
            range: _,
            node_index: _,
        } = parameter_with_default;

        let default_expr = default.as_ref();
        let ty = if let Some(parameter_type) = self.annotated_lambda_parameter_type(index, lambda) {
            parameter_type
        } else if let Some(default_expr) = default_expr {
            let default_ty = self.file_expression_type(default_expr);
            UnionType::from_two_elements(
                db,
                self.program_environment(),
                Type::unknown(),
                default_ty,
            )
        } else {
            Type::unknown()
        };

        self.add_binding(parameter.into(), definition)
            .insert(self, ty);
    }

    /// Set initial declared/inferred types for a `*args` variadic positional parameter
    /// in a lambda expression.
    pub(super) fn infer_variadic_positional_lambda_parameter_definition(
        &mut self,
        index: u32,
        parameter: &'ast ast::Parameter,
        lambda: &'ast ast::ExprLambda,
        definition: Definition<'db>,
    ) {
        let db = self.db();
        // Note that this currently always returns `None` because we do not support `Unpack`
        // annotations for callable types.
        let ty = if let Some(parameter_type) = self.annotated_lambda_parameter_type(index, lambda) {
            parameter_type
        } else {
            Type::homogeneous_tuple(db, self.program_environment(), Type::unknown())
        };
        self.add_binding(parameter.into(), definition)
            .insert(self, ty);
    }

    /// Set initial declared/inferred types for a `**kwargs` keyword-variadic parameter
    /// in a lambda expression.
    pub(super) fn infer_variadic_keyword_lambda_parameter_definition(
        &mut self,
        parameter: &'ast ast::Parameter,
        definition: Definition<'db>,
    ) {
        let db = self.db();
        let env = self.program_environment();
        let inferred_ty = KnownClass::Dict.to_specialized_instance(
            db,
            env,
            &[KnownClass::Str.to_instance(db, env), Type::unknown()],
        );

        self.add_binding(parameter.into(), definition)
            .insert(self, inferred_ty);
    }

    /// Returns the annotated type of the lambda parameter at the given index in the provided
    /// lambda expression, based on a `Callable` type annotation, if present.
    fn annotated_lambda_parameter_type(
        &mut self,
        index: u32,
        lambda: &'ast ast::ExprLambda,
    ) -> Option<Type<'db>> {
        let db = self.db();
        let enclosing_stmt = infer_statement_types(
            self.db(),
            self.index.enclosing_lambda_statement(lambda.into())?,
        );
        let callable = enclosing_stmt.expression_type(lambda).as_callable()?;
        let [signature] = callable.signatures(self.db()).overloads.as_slice() else {
            // TODO: If there are multiple applicable overloads, we could attempt multi-inference.
            return None;
        };

        let parameter_type = signature.parameters().as_slice()[index as usize].annotated_type();
        if parameter_type.is_unknown()
            || parameter_type.has_unspecialized_type_var(db, self.program_environment())
        {
            None
        } else {
            Some(parameter_type)
        }
    }
}
