rustc_trait_selection/traits/query/type_op/
ascribe_user_type.rs1use 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
39pub 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 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 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 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}