]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_borrowck/src/type_check/canonical.rs
7ff74e4b96e97305fe9878b2319ebc3bdc056bd2
[rust.git] / compiler / rustc_borrowck / src / type_check / canonical.rs
1 use std::fmt;
2
3 use rustc_infer::infer::canonical::Canonical;
4 use rustc_infer::traits::query::NoSolution;
5 use rustc_middle::mir::ConstraintCategory;
6 use rustc_middle::ty::{self, ToPredicate, 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::query::Fallible;
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     pub(super) fn fully_perform_op<R, Op>(
28         &mut self,
29         locations: Locations,
30         category: ConstraintCategory,
31         op: Op,
32     ) -> Fallible<R>
33     where
34         Op: type_op::TypeOp<'tcx, Output = R>,
35         Canonical<'tcx, Op>: ToUniverseInfo<'tcx>,
36     {
37         let old_universe = self.infcx.universe();
38
39         let TypeOpOutput { output, constraints, canonicalized_query } =
40             op.fully_perform(self.infcx)?;
41
42         if let Some(data) = &constraints {
43             self.push_region_constraints(locations, category, data);
44         }
45
46         let universe = self.infcx.universe();
47
48         if old_universe != universe {
49             let universe_info = match canonicalized_query {
50                 Some(canonicalized_query) => canonicalized_query.to_universe_info(old_universe),
51                 None => UniverseInfo::other(),
52             };
53             for u in old_universe..universe {
54                 self.borrowck_context
55                     .constraints
56                     .universe_causes
57                     .insert(u + 1, universe_info.clone());
58             }
59         }
60
61         Ok(output)
62     }
63
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<'tcx>,
71     {
72         let (instantiated, _) =
73             self.infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
74
75         for u in 0..canonical.max_universe.as_u32() {
76             let info = UniverseInfo::other();
77             self.borrowck_context
78                 .constraints
79                 .universe_causes
80                 .insert(ty::UniverseIndex::from_u32(u), info);
81         }
82
83         instantiated
84     }
85
86     pub(super) fn prove_trait_ref(
87         &mut self,
88         trait_ref: ty::TraitRef<'tcx>,
89         locations: Locations,
90         category: ConstraintCategory,
91     ) {
92         self.prove_predicates(
93             Some(ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
94                 trait_ref,
95                 constness: ty::BoundConstness::NotConst,
96             }))),
97             locations,
98             category,
99         );
100     }
101
102     pub(super) fn normalize_and_prove_instantiated_predicates(
103         &mut self,
104         def_id: DefId,
105         instantiated_predicates: ty::InstantiatedPredicates<'tcx>,
106         locations: Locations,
107     ) {
108         for (predicate, span) in instantiated_predicates
109             .predicates
110             .into_iter()
111             .zip(instantiated_predicates.spans.into_iter())
112         {
113             let predicate = self.normalize(predicate, locations);
114             self.prove_predicate(predicate, locations, ConstraintCategory::Predicate(def_id, span));
115         }
116     }
117
118     pub(super) fn prove_predicates(
119         &mut self,
120         predicates: impl IntoIterator<Item = impl ToPredicate<'tcx>>,
121         locations: Locations,
122         category: ConstraintCategory,
123     ) {
124         for predicate in predicates {
125             let predicate = predicate.to_predicate(self.tcx());
126             debug!("prove_predicates(predicate={:?}, locations={:?})", predicate, locations,);
127
128             self.prove_predicate(predicate, locations, category);
129         }
130     }
131
132     pub(super) fn prove_predicate(
133         &mut self,
134         predicate: ty::Predicate<'tcx>,
135         locations: Locations,
136         category: ConstraintCategory,
137     ) {
138         debug!("prove_predicate(predicate={:?}, location={:?})", predicate, locations,);
139
140         let param_env = self.param_env;
141         self.fully_perform_op(
142             locations,
143             category,
144             param_env.and(type_op::prove_predicate::ProvePredicate::new(predicate)),
145         )
146         .unwrap_or_else(|NoSolution| {
147             span_mirbug!(self, NoSolution, "could not prove {:?}", predicate);
148         })
149     }
150
151     pub(super) fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
152     where
153         T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
154     {
155         debug!("normalize(value={:?}, location={:?})", value, location);
156         let param_env = self.param_env;
157         self.fully_perform_op(
158             location.to_locations(),
159             ConstraintCategory::Boring,
160             param_env.and(type_op::normalize::Normalize::new(value)),
161         )
162         .unwrap_or_else(|NoSolution| {
163             span_mirbug!(self, NoSolution, "failed to normalize `{:?}`", value);
164             value
165         })
166     }
167 }