use rustc_middle::traits::ObligationCause;
use rustc_middle::ty;

use super::InferCtxt;
use crate::infer::Term;
use crate::traits::{Obligation, PredicateObligations};

impl<'tcx> InferCtxt<'tcx> {
    /// Instead of normalizing an associated type projection,
    /// this function generates an inference variable and registers
    /// an obligation that this inference variable must be the result
    /// of the given projection. This allows us to proceed with projections
    /// while they cannot be resolved yet due to missing information or
    /// simply due to the lack of access to the trait resolution machinery.
    pub fn projection_term_to_infer(
        &self,
        param_env: ty::ParamEnv<'tcx>,
        alias_term: ty::AliasTerm<'tcx>,
        cause: ObligationCause<'tcx>,
        recursion_depth: usize,
        obligations: &mut PredicateObligations<'tcx>,
    ) -> Term<'tcx> {
        debug_assert!(!self.next_trait_solver());

        let span = self.tcx.def_span(alias_term.def_id());
        let infer_var = if alias_term.kind(self.tcx).is_type() {
            self.next_ty_var(span).into()
        } else {
            self.next_const_var(span).into()
        };

        let projection =
            ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate {
                projection_term: alias_term,
                term: infer_var,
            }));
        let obligation =
            Obligation::with_depth(self.tcx, cause, recursion_depth, param_env, projection);
        obligations.push(obligation);

        infer_var
    }
}
