rustc_traits/
normalize_projection_ty.rs

1use rustc_infer::infer::TyCtxtInferExt;
2use rustc_infer::infer::canonical::{Canonical, QueryResponse};
3use rustc_infer::traits::PredicateObligations;
4use rustc_middle::query::Providers;
5use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
6use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
7use rustc_trait_selection::infer::InferCtxtBuilderExt;
8use rustc_trait_selection::traits::query::normalize::NormalizationResult;
9use rustc_trait_selection::traits::query::{CanonicalAliasGoal, NoSolution};
10use rustc_trait_selection::traits::{self, ObligationCause, ScrubbedTraitError, SelectionContext};
11use tracing::debug;
12
13pub(crate) fn provide(p: &mut Providers) {
14    *p = Providers {
15        normalize_canonicalized_projection_ty,
16        normalize_canonicalized_weak_ty,
17        normalize_canonicalized_inherent_projection_ty,
18        ..*p
19    };
20}
21
22fn normalize_canonicalized_projection_ty<'tcx>(
23    tcx: TyCtxt<'tcx>,
24    goal: CanonicalAliasGoal<'tcx>,
25) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> {
26    debug!("normalize_canonicalized_projection_ty(goal={:#?})", goal);
27
28    tcx.infer_ctxt().enter_canonical_trait_query(
29        &goal,
30        |ocx, ParamEnvAnd { param_env, value: goal }| {
31            debug_assert!(!ocx.infcx.next_trait_solver());
32            let selcx = &mut SelectionContext::new(ocx.infcx);
33            let cause = ObligationCause::dummy();
34            let mut obligations = PredicateObligations::new();
35            let answer =
36                traits::normalize_projection_ty(selcx, param_env, goal, cause, 0, &mut obligations);
37            ocx.register_obligations(obligations);
38            // #112047: With projections and opaques, we are able to create opaques that
39            // are recursive (given some generic parameters of the opaque's type variables).
40            // In that case, we may only realize a cycle error when calling
41            // `normalize_erasing_regions` in mono.
42            let errors = ocx.select_where_possible();
43            if !errors.is_empty() {
44                // Rustdoc may attempt to normalize type alias types which are not
45                // well-formed. Rustdoc also normalizes types that are just not
46                // well-formed, since we don't do as much HIR analysis (checking
47                // that impl vars are constrained by the signature, for example).
48                if !tcx.sess.opts.actually_rustdoc {
49                    for error in &errors {
50                        if let ScrubbedTraitError::Cycle(cycle) = &error {
51                            ocx.infcx.err_ctxt().report_overflow_obligation_cycle(cycle);
52                        }
53                    }
54                }
55                return Err(NoSolution);
56            }
57
58            // FIXME(associated_const_equality): All users of normalize_canonicalized_projection_ty
59            // expected a type, but there is the possibility it could've been a const now.
60            // Maybe change it to a Term later?
61            Ok(NormalizationResult { normalized_ty: answer.expect_type() })
62        },
63    )
64}
65
66fn normalize_canonicalized_weak_ty<'tcx>(
67    tcx: TyCtxt<'tcx>,
68    goal: CanonicalAliasGoal<'tcx>,
69) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> {
70    debug!("normalize_canonicalized_weak_ty(goal={:#?})", goal);
71
72    tcx.infer_ctxt().enter_canonical_trait_query(
73        &goal,
74        |ocx, ParamEnvAnd { param_env, value: goal }| {
75            let obligations = tcx.predicates_of(goal.def_id).instantiate_own(tcx, goal.args).map(
76                |(predicate, span)| {
77                    traits::Obligation::new(
78                        tcx,
79                        ObligationCause::dummy_with_span(span),
80                        param_env,
81                        predicate,
82                    )
83                },
84            );
85            ocx.register_obligations(obligations);
86            let normalized_ty = tcx.type_of(goal.def_id).instantiate(tcx, goal.args);
87            Ok(NormalizationResult { normalized_ty })
88        },
89    )
90}
91
92fn normalize_canonicalized_inherent_projection_ty<'tcx>(
93    tcx: TyCtxt<'tcx>,
94    goal: CanonicalAliasGoal<'tcx>,
95) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> {
96    debug!("normalize_canonicalized_inherent_projection_ty(goal={:#?})", goal);
97
98    tcx.infer_ctxt().enter_canonical_trait_query(
99        &goal,
100        |ocx, ParamEnvAnd { param_env, value: goal }| {
101            let selcx = &mut SelectionContext::new(ocx.infcx);
102            let cause = ObligationCause::dummy();
103            let mut obligations = PredicateObligations::new();
104            let answer = traits::normalize_inherent_projection(
105                selcx,
106                param_env,
107                goal,
108                cause,
109                0,
110                &mut obligations,
111            );
112            ocx.register_obligations(obligations);
113
114            Ok(NormalizationResult { normalized_ty: answer })
115        },
116    )
117}