rustc_trait_selection/traits/query/type_op/
ascribe_user_type.rs

1use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
2use rustc_infer::traits::Obligation;
3use rustc_middle::traits::query::NoSolution;
4pub use rustc_middle::traits::query::type_op::AscribeUserType;
5use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
6use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, UserArgs, UserSelfTy, UserTypeKind};
7use rustc_span::{DUMMY_SP, Span};
8use tracing::{debug, instrument};
9
10use crate::infer::canonical::{CanonicalQueryInput, CanonicalQueryResponse};
11use crate::traits::ObligationCtxt;
12
13impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> {
14    type QueryResponse = ();
15
16    fn try_fast_path(
17        _tcx: TyCtxt<'tcx>,
18        _key: &ParamEnvAnd<'tcx, Self>,
19    ) -> Option<Self::QueryResponse> {
20        None
21    }
22
23    fn perform_query(
24        tcx: TyCtxt<'tcx>,
25        canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Self>>,
26    ) -> Result<CanonicalQueryResponse<'tcx, ()>, NoSolution> {
27        tcx.type_op_ascribe_user_type(canonicalized)
28    }
29
30    fn perform_locally_with_next_solver(
31        ocx: &ObligationCtxt<'_, 'tcx>,
32        key: ParamEnvAnd<'tcx, Self>,
33        span: Span,
34    ) -> Result<Self::QueryResponse, NoSolution> {
35        type_op_ascribe_user_type_with_span(ocx, key, span)
36    }
37}
38
39/// The core of the `type_op_ascribe_user_type` query: for diagnostics purposes in NLL HRTB errors,
40/// this query can be re-run to better track the span of the obligation cause, and improve the error
41/// message. Do not call directly unless you're in that very specific context.
42pub fn type_op_ascribe_user_type_with_span<'tcx>(
43    ocx: &ObligationCtxt<'_, 'tcx>,
44    key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>,
45    span: Span,
46) -> Result<(), NoSolution> {
47    let (param_env, AscribeUserType { mir_ty, user_ty }) = key.into_parts();
48    debug!("type_op_ascribe_user_type: mir_ty={:?} user_ty={:?}", mir_ty, user_ty);
49    match user_ty.kind {
50        UserTypeKind::Ty(user_ty) => relate_mir_and_user_ty(ocx, param_env, span, mir_ty, user_ty)?,
51        UserTypeKind::TypeOf(def_id, user_args) => {
52            relate_mir_and_user_args(ocx, param_env, span, mir_ty, def_id, user_args)?
53        }
54    };
55
56    // Enforce any bounds that come from impl trait in bindings.
57    ocx.register_obligations(user_ty.bounds.iter().map(|clause| {
58        Obligation::new(ocx.infcx.tcx, ObligationCause::dummy_with_span(span), param_env, clause)
59    }));
60
61    Ok(())
62}
63
64#[instrument(level = "debug", skip(ocx, param_env, span))]
65fn relate_mir_and_user_ty<'tcx>(
66    ocx: &ObligationCtxt<'_, 'tcx>,
67    param_env: ty::ParamEnv<'tcx>,
68    span: Span,
69    mir_ty: Ty<'tcx>,
70    user_ty: Ty<'tcx>,
71) -> Result<(), NoSolution> {
72    let cause = ObligationCause::dummy_with_span(span);
73    ocx.register_obligation(Obligation::new(
74        ocx.infcx.tcx,
75        cause.clone(),
76        param_env,
77        ty::ClauseKind::WellFormed(user_ty.into()),
78    ));
79
80    let user_ty = ocx.normalize(&cause, param_env, user_ty);
81    ocx.eq(&cause, param_env, mir_ty, user_ty)?;
82
83    Ok(())
84}
85
86#[instrument(level = "debug", skip(ocx, param_env, span))]
87fn relate_mir_and_user_args<'tcx>(
88    ocx: &ObligationCtxt<'_, 'tcx>,
89    param_env: ty::ParamEnv<'tcx>,
90    span: Span,
91    mir_ty: Ty<'tcx>,
92    def_id: DefId,
93    user_args: UserArgs<'tcx>,
94) -> Result<(), NoSolution> {
95    let UserArgs { user_self_ty, args } = user_args;
96    let tcx = ocx.infcx.tcx;
97    let cause = ObligationCause::dummy_with_span(span);
98
99    let ty = tcx.type_of(def_id).instantiate(tcx, args);
100    let ty = ocx.normalize(&cause, param_env, ty);
101    debug!("relate_type_and_user_type: ty of def-id is {:?}", ty);
102
103    ocx.eq(&cause, param_env, mir_ty, ty)?;
104
105    // Prove the predicates coming along with `def_id`.
106    //
107    // Also, normalize the `instantiated_predicates`
108    // because otherwise we wind up with duplicate "type
109    // outlives" error messages.
110    let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, args);
111
112    debug!(?instantiated_predicates);
113    for (instantiated_predicate, predicate_span) in instantiated_predicates {
114        let span = if span == DUMMY_SP { predicate_span } else { span };
115        let cause = ObligationCause::new(
116            span,
117            CRATE_DEF_ID,
118            ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span),
119        );
120        let instantiated_predicate = ocx.normalize(&cause, param_env, instantiated_predicate);
121
122        ocx.register_obligation(Obligation::new(tcx, cause, param_env, instantiated_predicate));
123    }
124
125    // Now prove the well-formedness of `def_id` with `args`.
126    // Note for some items, proving the WF of `ty` is not sufficient because the
127    // well-formedness of an item may depend on the WF of gneneric args not present in the
128    // item's type. Currently this is true for associated consts, e.g.:
129    // ```rust
130    // impl<T> MyTy<T> {
131    //     const CONST: () = { /* arbitrary code that depends on T being WF */ };
132    // }
133    // ```
134    for term in args.iter().filter_map(ty::GenericArg::as_term) {
135        ocx.register_obligation(Obligation::new(
136            tcx,
137            cause.clone(),
138            param_env,
139            ty::ClauseKind::WellFormed(term),
140        ));
141    }
142
143    if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
144        ocx.register_obligation(Obligation::new(
145            tcx,
146            cause.clone(),
147            param_env,
148            ty::ClauseKind::WellFormed(self_ty.into()),
149        ));
150
151        let self_ty = ocx.normalize(&cause, param_env, self_ty);
152        let impl_self_ty = tcx.type_of(impl_def_id).instantiate(tcx, args);
153        let impl_self_ty = ocx.normalize(&cause, param_env, impl_self_ty);
154
155        ocx.eq(&cause, param_env, self_ty, impl_self_ty)?;
156    }
157
158    Ok(())
159}