• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::fmt;
2 
3 use rustc_errors::ErrorGuaranteed;
4 use rustc_infer::infer::canonical::Canonical;
5 use rustc_middle::mir::ConstraintCategory;
6 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
7 use rustc_span::def_id::DefId;
8 use rustc_span::Span;
9 use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
10 use rustc_trait_selection::traits::ObligationCause;
11 
12 use crate::diagnostics::{ToUniverseInfo, UniverseInfo};
13 
14 use super::{Locations, NormalizeLocation, TypeChecker};
15 
16 impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
17     /// Given some operation `op` that manipulates types, proves
18     /// predicates, or otherwise uses the inference context, executes
19     /// `op` and then executes all the further obligations that `op`
20     /// returns. This will yield a set of outlives constraints amongst
21     /// regions which are extracted and stored as having occurred at
22     /// `locations`.
23     ///
24     /// **Any `rustc_infer::infer` operations that might generate region
25     /// constraints should occur within this method so that those
26     /// constraints can be properly localized!**
27     #[instrument(skip(self, op), level = "trace")]
fully_perform_op<R: fmt::Debug, Op>( &mut self, locations: Locations, category: ConstraintCategory<'tcx>, op: Op, ) -> Result<R, ErrorGuaranteed> where Op: type_op::TypeOp<'tcx, Output = R>, Op::ErrorInfo: ToUniverseInfo<'tcx>,28     pub(super) fn fully_perform_op<R: fmt::Debug, Op>(
29         &mut self,
30         locations: Locations,
31         category: ConstraintCategory<'tcx>,
32         op: Op,
33     ) -> Result<R, ErrorGuaranteed>
34     where
35         Op: type_op::TypeOp<'tcx, Output = R>,
36         Op::ErrorInfo: ToUniverseInfo<'tcx>,
37     {
38         let old_universe = self.infcx.universe();
39 
40         let TypeOpOutput { output, constraints, error_info } =
41             op.fully_perform(self.infcx, locations.span(self.body))?;
42 
43         debug!(?output, ?constraints);
44 
45         if let Some(data) = constraints {
46             self.push_region_constraints(locations, category, data);
47         }
48 
49         let universe = self.infcx.universe();
50 
51         if old_universe != universe {
52             let universe_info = match error_info {
53                 Some(error_info) => error_info.to_universe_info(old_universe),
54                 None => UniverseInfo::other(),
55             };
56             for u in (old_universe + 1)..=universe {
57                 self.borrowck_context.constraints.universe_causes.insert(u, universe_info.clone());
58             }
59         }
60 
61         Ok(output)
62     }
63 
instantiate_canonical_with_fresh_inference_vars<T>( &mut self, span: Span, canonical: &Canonical<'tcx, T>, ) -> T where T: TypeFoldable<TyCtxt<'tcx>>,64     pub(super) fn instantiate_canonical_with_fresh_inference_vars<T>(
65         &mut self,
66         span: Span,
67         canonical: &Canonical<'tcx, T>,
68     ) -> T
69     where
70         T: TypeFoldable<TyCtxt<'tcx>>,
71     {
72         let old_universe = self.infcx.universe();
73 
74         let (instantiated, _) =
75             self.infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
76 
77         for u in (old_universe + 1)..=self.infcx.universe() {
78             self.borrowck_context.constraints.universe_causes.insert(u, UniverseInfo::other());
79         }
80 
81         instantiated
82     }
83 
84     #[instrument(skip(self), level = "debug")]
prove_trait_ref( &mut self, trait_ref: ty::TraitRef<'tcx>, locations: Locations, category: ConstraintCategory<'tcx>, )85     pub(super) fn prove_trait_ref(
86         &mut self,
87         trait_ref: ty::TraitRef<'tcx>,
88         locations: Locations,
89         category: ConstraintCategory<'tcx>,
90     ) {
91         self.prove_predicate(
92             ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Trait(
93                 ty::TraitPredicate {
94                     trait_ref,
95                     constness: ty::BoundConstness::NotConst,
96                     polarity: ty::ImplPolarity::Positive,
97                 },
98             ))),
99             locations,
100             category,
101         );
102     }
103 
104     #[instrument(level = "debug", skip(self))]
normalize_and_prove_instantiated_predicates( &mut self, _def_id: DefId, instantiated_predicates: ty::InstantiatedPredicates<'tcx>, locations: Locations, )105     pub(super) fn normalize_and_prove_instantiated_predicates(
106         &mut self,
107         // Keep this parameter for now, in case we start using
108         // it in `ConstraintCategory` at some point.
109         _def_id: DefId,
110         instantiated_predicates: ty::InstantiatedPredicates<'tcx>,
111         locations: Locations,
112     ) {
113         for (predicate, span) in instantiated_predicates {
114             debug!(?predicate);
115             let category = ConstraintCategory::Predicate(span);
116             let predicate = self.normalize_with_category(predicate, locations, category);
117             self.prove_predicate(predicate, locations, category);
118         }
119     }
120 
prove_predicates( &mut self, predicates: impl IntoIterator<Item: ToPredicate<'tcx> + std::fmt::Debug>, locations: Locations, category: ConstraintCategory<'tcx>, )121     pub(super) fn prove_predicates(
122         &mut self,
123         predicates: impl IntoIterator<Item: ToPredicate<'tcx> + std::fmt::Debug>,
124         locations: Locations,
125         category: ConstraintCategory<'tcx>,
126     ) {
127         for predicate in predicates {
128             self.prove_predicate(predicate, locations, category);
129         }
130     }
131 
132     #[instrument(skip(self), level = "debug")]
prove_predicate( &mut self, predicate: impl ToPredicate<'tcx> + std::fmt::Debug, locations: Locations, category: ConstraintCategory<'tcx>, )133     pub(super) fn prove_predicate(
134         &mut self,
135         predicate: impl ToPredicate<'tcx> + std::fmt::Debug,
136         locations: Locations,
137         category: ConstraintCategory<'tcx>,
138     ) {
139         let param_env = self.param_env;
140         let predicate = predicate.to_predicate(self.tcx());
141         let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
142             locations,
143             category,
144             param_env.and(type_op::prove_predicate::ProvePredicate::new(predicate)),
145         );
146     }
147 
normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T where T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,148     pub(super) fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
149     where
150         T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
151     {
152         self.normalize_with_category(value, location, ConstraintCategory::Boring)
153     }
154 
155     #[instrument(skip(self), level = "debug")]
normalize_with_category<T>( &mut self, value: T, location: impl NormalizeLocation, category: ConstraintCategory<'tcx>, ) -> T where T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,156     pub(super) fn normalize_with_category<T>(
157         &mut self,
158         value: T,
159         location: impl NormalizeLocation,
160         category: ConstraintCategory<'tcx>,
161     ) -> T
162     where
163         T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
164     {
165         let param_env = self.param_env;
166         let result: Result<_, ErrorGuaranteed> = self.fully_perform_op(
167             location.to_locations(),
168             category,
169             param_env.and(type_op::normalize::Normalize::new(value)),
170         );
171         result.unwrap_or(value)
172     }
173 
174     #[instrument(skip(self), level = "debug")]
ascribe_user_type( &mut self, mir_ty: Ty<'tcx>, user_ty: ty::UserType<'tcx>, span: Span, )175     pub(super) fn ascribe_user_type(
176         &mut self,
177         mir_ty: Ty<'tcx>,
178         user_ty: ty::UserType<'tcx>,
179         span: Span,
180     ) {
181         let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
182             Locations::All(span),
183             ConstraintCategory::Boring,
184             self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(mir_ty, user_ty)),
185         );
186     }
187 
188     /// *Incorrectly* skips the WF checks we normally do in `ascribe_user_type`.
189     ///
190     /// FIXME(#104478, #104477): This is a hack for backward-compatibility.
191     #[instrument(skip(self), level = "debug")]
ascribe_user_type_skip_wf( &mut self, mir_ty: Ty<'tcx>, user_ty: ty::UserType<'tcx>, span: Span, )192     pub(super) fn ascribe_user_type_skip_wf(
193         &mut self,
194         mir_ty: Ty<'tcx>,
195         user_ty: ty::UserType<'tcx>,
196         span: Span,
197     ) {
198         let ty::UserType::Ty(user_ty) = user_ty else { bug!() };
199 
200         // A fast path for a common case with closure input/output types.
201         if let ty::Infer(_) = user_ty.kind() {
202             self.eq_types(user_ty, mir_ty, Locations::All(span), ConstraintCategory::Boring)
203                 .unwrap();
204             return;
205         }
206 
207         // FIXME: Ideally MIR types are normalized, but this is not always true.
208         let mir_ty = self.normalize(mir_ty, Locations::All(span));
209 
210         let cause = ObligationCause::dummy_with_span(span);
211         let param_env = self.param_env;
212         let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
213             Locations::All(span),
214             ConstraintCategory::Boring,
215             type_op::custom::CustomTypeOp::new(
216                 |ocx| {
217                     let user_ty = ocx.normalize(&cause, param_env, user_ty);
218                     ocx.eq(&cause, param_env, user_ty, mir_ty)?;
219                     Ok(())
220                 },
221                 "ascribe_user_type_skip_wf",
222             ),
223         );
224     }
225 }
226