]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_borrowck/src/type_check/canonical.rs
Rollup merge of #106797 - FawazTirmizi:dev/issues/104284, r=bjorn3
[rust.git] / compiler / rustc_borrowck / src / type_check / canonical.rs
1 use std::fmt;
2
3 use rustc_infer::infer::{canonical::Canonical, InferOk};
4 use rustc_middle::mir::ConstraintCategory;
5 use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable};
6 use rustc_span::def_id::DefId;
7 use rustc_span::Span;
8 use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
9 use rustc_trait_selection::traits::query::{Fallible, NoSolution};
10 use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
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")]
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     ) -> Fallible<R>
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 } = op.fully_perform(self.infcx)?;
41
42         debug!(?output, ?constraints);
43
44         if let Some(data) = constraints {
45             self.push_region_constraints(locations, category, data);
46         }
47
48         let universe = self.infcx.universe();
49
50         if old_universe != universe {
51             let universe_info = match error_info {
52                 Some(error_info) => error_info.to_universe_info(old_universe),
53                 None => UniverseInfo::other(),
54             };
55             for u in (old_universe + 1)..=universe {
56                 self.borrowck_context.constraints.universe_causes.insert(u, universe_info.clone());
57             }
58         }
59
60         Ok(output)
61     }
62
63     pub(super) fn instantiate_canonical_with_fresh_inference_vars<T>(
64         &mut self,
65         span: Span,
66         canonical: &Canonical<'tcx, T>,
67     ) -> T
68     where
69         T: TypeFoldable<'tcx>,
70     {
71         let old_universe = self.infcx.universe();
72
73         let (instantiated, _) =
74             self.infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
75
76         for u in (old_universe + 1)..=self.infcx.universe() {
77             self.borrowck_context.constraints.universe_causes.insert(u, UniverseInfo::other());
78         }
79
80         instantiated
81     }
82
83     #[instrument(skip(self), level = "debug")]
84     pub(super) fn prove_trait_ref(
85         &mut self,
86         trait_ref: ty::TraitRef<'tcx>,
87         locations: Locations,
88         category: ConstraintCategory<'tcx>,
89     ) {
90         self.prove_predicate(
91             ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
92                 trait_ref,
93                 constness: ty::BoundConstness::NotConst,
94                 polarity: ty::ImplPolarity::Positive,
95             }))),
96             locations,
97             category,
98         );
99     }
100
101     #[instrument(level = "debug", skip(self))]
102     pub(super) fn normalize_and_prove_instantiated_predicates(
103         &mut self,
104         // Keep this parameter for now, in case we start using
105         // it in `ConstraintCategory` at some point.
106         _def_id: DefId,
107         instantiated_predicates: ty::InstantiatedPredicates<'tcx>,
108         locations: Locations,
109     ) {
110         for (predicate, span) in instantiated_predicates
111             .predicates
112             .into_iter()
113             .zip(instantiated_predicates.spans.into_iter())
114         {
115             debug!(?predicate);
116             let category = ConstraintCategory::Predicate(span);
117             let predicate = self.normalize_with_category(predicate, locations, category);
118             self.prove_predicate(predicate, locations, category);
119         }
120     }
121
122     pub(super) fn prove_predicates(
123         &mut self,
124         predicates: impl IntoIterator<Item = impl ToPredicate<'tcx> + std::fmt::Debug>,
125         locations: Locations,
126         category: ConstraintCategory<'tcx>,
127     ) {
128         for predicate in predicates {
129             self.prove_predicate(predicate, locations, category);
130         }
131     }
132
133     #[instrument(skip(self), level = "debug")]
134     pub(super) fn prove_predicate(
135         &mut self,
136         predicate: impl ToPredicate<'tcx> + std::fmt::Debug,
137         locations: Locations,
138         category: ConstraintCategory<'tcx>,
139     ) {
140         let param_env = self.param_env;
141         let predicate = predicate.to_predicate(self.tcx());
142         self.fully_perform_op(
143             locations,
144             category,
145             param_env.and(type_op::prove_predicate::ProvePredicate::new(predicate)),
146         )
147         .unwrap_or_else(|NoSolution| {
148             span_mirbug!(self, NoSolution, "could not prove {:?}", predicate);
149         })
150     }
151
152     pub(super) fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
153     where
154         T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
155     {
156         self.normalize_with_category(value, location, ConstraintCategory::Boring)
157     }
158
159     #[instrument(skip(self), level = "debug")]
160     pub(super) fn normalize_with_category<T>(
161         &mut self,
162         value: T,
163         location: impl NormalizeLocation,
164         category: ConstraintCategory<'tcx>,
165     ) -> T
166     where
167         T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
168     {
169         let param_env = self.param_env;
170         self.fully_perform_op(
171             location.to_locations(),
172             category,
173             param_env.and(type_op::normalize::Normalize::new(value)),
174         )
175         .unwrap_or_else(|NoSolution| {
176             span_mirbug!(self, NoSolution, "failed to normalize `{:?}`", value);
177             value
178         })
179     }
180
181     #[instrument(skip(self), level = "debug")]
182     pub(super) fn ascribe_user_type(
183         &mut self,
184         mir_ty: Ty<'tcx>,
185         user_ty: ty::UserType<'tcx>,
186         span: Span,
187     ) {
188         // FIXME: Ideally MIR types are normalized, but this is not always true.
189         let mir_ty = self.normalize(mir_ty, Locations::All(span));
190
191         self.fully_perform_op(
192             Locations::All(span),
193             ConstraintCategory::Boring,
194             self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(mir_ty, user_ty)),
195         )
196         .unwrap_or_else(|err| {
197             span_mirbug!(
198                 self,
199                 span,
200                 "ascribe_user_type `{mir_ty:?}=={user_ty:?}` failed with `{err:?}`",
201             );
202         });
203     }
204
205     /// *Incorrectly* skips the WF checks we normally do in `ascribe_user_type`.
206     ///
207     /// FIXME(#104478, #104477): This is a hack for backward-compatibility.
208     #[instrument(skip(self), level = "debug")]
209     pub(super) fn ascribe_user_type_skip_wf(
210         &mut self,
211         mir_ty: Ty<'tcx>,
212         user_ty: ty::UserType<'tcx>,
213         span: Span,
214     ) {
215         let ty::UserType::Ty(user_ty) = user_ty else { bug!() };
216
217         // A fast path for a common case with closure input/output types.
218         if let ty::Infer(_) = user_ty.kind() {
219             self.eq_types(user_ty, mir_ty, Locations::All(span), ConstraintCategory::Boring)
220                 .unwrap();
221             return;
222         }
223
224         let mir_ty = self.normalize(mir_ty, Locations::All(span));
225         let cause = ObligationCause::dummy_with_span(span);
226         let param_env = self.param_env;
227         let op = |infcx: &'_ _| {
228             let ocx = ObligationCtxt::new_in_snapshot(infcx);
229             let user_ty = ocx.normalize(&cause, param_env, user_ty);
230             ocx.eq(&cause, param_env, user_ty, mir_ty)?;
231             if !ocx.select_all_or_error().is_empty() {
232                 return Err(NoSolution);
233             }
234             Ok(InferOk { value: (), obligations: vec![] })
235         };
236
237         self.fully_perform_op(
238             Locations::All(span),
239             ConstraintCategory::Boring,
240             type_op::custom::CustomTypeOp::new(op, || "ascribe_user_type_skip_wf".to_string()),
241         )
242         .unwrap_or_else(|err| {
243             span_mirbug!(
244                 self,
245                 span,
246                 "ascribe_user_type_skip_wf `{mir_ty:?}=={user_ty:?}` failed with `{err:?}`",
247             );
248         });
249     }
250 }