blob: 1d7ea9fe00a3fe82ebe52d54aed87df6a1c6b2ad [file] [log] [blame]
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
use rustc_infer::traits::PredicateObligations;
use rustc_middle::query::Providers;
use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
use rustc_trait_selection::infer::InferCtxtBuilderExt;
use rustc_trait_selection::traits::query::normalize::NormalizationResult;
use rustc_trait_selection::traits::query::{CanonicalAliasGoal, NoSolution};
use rustc_trait_selection::traits::{self, ObligationCause, ScrubbedTraitError, SelectionContext};
use tracing::debug;
pub(crate) fn provide(p: &mut Providers) {
*p = Providers {
normalize_canonicalized_projection,
normalize_canonicalized_free_alias,
normalize_canonicalized_inherent_projection,
..*p
};
}
fn normalize_canonicalized_projection<'tcx>(
tcx: TyCtxt<'tcx>,
goal: CanonicalAliasGoal<'tcx>,
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> {
debug!("normalize_canonicalized_projection(goal={:#?})", goal);
tcx.infer_ctxt().enter_canonical_trait_query(
&goal,
|ocx, ParamEnvAnd { param_env, value: goal }| {
debug_assert!(!ocx.infcx.next_trait_solver());
let selcx = &mut SelectionContext::new(ocx.infcx);
let cause = ObligationCause::dummy();
let mut obligations = PredicateObligations::new();
let normalized_term = traits::normalize_projection_term(
selcx,
param_env,
goal.into(),
cause,
0,
&mut obligations,
);
ocx.register_obligations(obligations);
// #112047: With projections and opaques, we are able to create opaques that
// are recursive (given some generic parameters of the opaque's type variables).
// In that case, we may only realize a cycle error when calling
// `normalize_erasing_regions` in mono.
let errors = ocx.try_evaluate_obligations();
if !errors.is_empty() {
// Rustdoc may attempt to normalize type alias types which are not
// well-formed. Rustdoc also normalizes types that are just not
// well-formed, since we don't do as much HIR analysis (checking
// that impl vars are constrained by the signature, for example).
if !tcx.sess.opts.actually_rustdoc {
for error in &errors {
if let ScrubbedTraitError::Cycle(cycle) = &error {
ocx.infcx.err_ctxt().report_overflow_obligation_cycle(cycle);
}
}
}
return Err(NoSolution);
}
Ok(NormalizationResult { normalized_term })
},
)
}
fn normalize_canonicalized_free_alias<'tcx>(
tcx: TyCtxt<'tcx>,
goal: CanonicalAliasGoal<'tcx>,
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> {
debug!("normalize_canonicalized_free_alias(goal={:#?})", goal);
tcx.infer_ctxt().enter_canonical_trait_query(
&goal,
|ocx, ParamEnvAnd { param_env, value: goal }| {
let obligations = tcx.predicates_of(goal.def_id).instantiate_own(tcx, goal.args).map(
|(predicate, span)| {
traits::Obligation::new(
tcx,
ObligationCause::dummy_with_span(span),
param_env,
predicate,
)
},
);
ocx.register_obligations(obligations);
let normalized_term = if goal.kind(tcx).is_type() {
tcx.type_of(goal.def_id).instantiate(tcx, goal.args).into()
} else {
tcx.const_of_item(goal.def_id).instantiate(tcx, goal.args).into()
};
Ok(NormalizationResult { normalized_term })
},
)
}
fn normalize_canonicalized_inherent_projection<'tcx>(
tcx: TyCtxt<'tcx>,
goal: CanonicalAliasGoal<'tcx>,
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> {
debug!("normalize_canonicalized_inherent_projection(goal={:#?})", goal);
tcx.infer_ctxt().enter_canonical_trait_query(
&goal,
|ocx, ParamEnvAnd { param_env, value: goal }| {
let selcx = &mut SelectionContext::new(ocx.infcx);
let cause = ObligationCause::dummy();
let mut obligations = PredicateObligations::new();
let normalized_term = traits::normalize_inherent_projection(
selcx,
param_env,
goal.into(),
cause,
0,
&mut obligations,
);
ocx.register_obligations(obligations);
Ok(NormalizationResult { normalized_term })
},
)
}