]>
Commit | Line | Data |
---|---|---|
0531ce1d XL |
1 | //! Code for the 'normalization' query. This consists of a wrapper |
2 | //! which folds deeply, invoking the underlying | |
3 | //! `normalize_projection_ty` query when it encounters projections. | |
4 | ||
9fa01778 XL |
5 | use crate::infer::at::At; |
6 | use crate::infer::canonical::OriginalQueryValues; | |
7 | use crate::infer::{InferCtxt, InferOk}; | |
9fa01778 XL |
8 | use crate::traits::project::Normalized; |
9 | use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; | |
10 | use crate::ty::fold::{TypeFoldable, TypeFolder}; | |
e1599b0c | 11 | use crate::ty::subst::Subst; |
9fa01778 | 12 | use crate::ty::{self, Ty, TyCtxt}; |
0531ce1d XL |
13 | |
14 | use super::NoSolution; | |
15 | ||
dc9dc135 | 16 | impl<'cx, 'tcx> At<'cx, 'tcx> { |
0531ce1d XL |
17 | /// Normalize `value` in the context of the inference context, |
18 | /// yielding a resulting type, or an error if `value` cannot be | |
19 | /// normalized. If you don't care about regions, you should prefer | |
20 | /// `normalize_erasing_regions`, which is more efficient. | |
21 | /// | |
94b46f34 | 22 | /// If the normalization succeeds and is unambiguous, returns back |
0531ce1d XL |
23 | /// the normalized value along with various outlives relations (in |
24 | /// the form of obligations that must be discharged). | |
25 | /// | |
9fa01778 | 26 | /// N.B., this will *eventually* be the main means of |
0531ce1d XL |
27 | /// normalizing, but for now should be used only when we actually |
28 | /// know that normalization will succeed, since error reporting | |
29 | /// and other details are still "under development". | |
30 | pub fn normalize<T>(&self, value: &T) -> Result<Normalized<'tcx, T>, NoSolution> | |
31 | where | |
32 | T: TypeFoldable<'tcx>, | |
33 | { | |
34 | debug!( | |
35 | "normalize::<{}>(value={:?}, param_env={:?})", | |
416331ca | 36 | ::std::any::type_name::<T>(), |
0531ce1d XL |
37 | value, |
38 | self.param_env, | |
39 | ); | |
0bf4aa26 | 40 | if !value.has_projections() { |
dfeec247 | 41 | return Ok(Normalized { value: value.clone(), obligations: vec![] }); |
0bf4aa26 XL |
42 | } |
43 | ||
0531ce1d XL |
44 | let mut normalizer = QueryNormalizer { |
45 | infcx: self.infcx, | |
46 | cause: self.cause, | |
47 | param_env: self.param_env, | |
48 | obligations: vec![], | |
49 | error: false, | |
50 | anon_depth: 0, | |
51 | }; | |
0531ce1d XL |
52 | |
53 | let value1 = value.fold_with(&mut normalizer); | |
54 | if normalizer.error { | |
55 | Err(NoSolution) | |
56 | } else { | |
dfeec247 | 57 | Ok(Normalized { value: value1, obligations: normalizer.obligations }) |
0531ce1d XL |
58 | } |
59 | } | |
60 | } | |
61 | ||
62 | /// Result from the `normalize_projection_ty` query. | |
60c5eb7d | 63 | #[derive(Clone, Debug, HashStable, TypeFoldable, Lift)] |
0531ce1d XL |
64 | pub struct NormalizationResult<'tcx> { |
65 | /// Result of normalization. | |
66 | pub normalized_ty: Ty<'tcx>, | |
67 | } | |
68 | ||
dc9dc135 XL |
69 | struct QueryNormalizer<'cx, 'tcx> { |
70 | infcx: &'cx InferCtxt<'cx, 'tcx>, | |
0531ce1d XL |
71 | cause: &'cx ObligationCause<'tcx>, |
72 | param_env: ty::ParamEnv<'tcx>, | |
73 | obligations: Vec<PredicateObligation<'tcx>>, | |
74 | error: bool, | |
75 | anon_depth: usize, | |
76 | } | |
77 | ||
dc9dc135 XL |
78 | impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { |
79 | fn tcx<'c>(&'c self) -> TyCtxt<'tcx> { | |
0531ce1d XL |
80 | self.infcx.tcx |
81 | } | |
82 | ||
83 | fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { | |
84 | let ty = ty.super_fold_with(self); | |
e74abb32 | 85 | match ty.kind { |
a1dfa0c6 | 86 | ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { |
0531ce1d | 87 | // (*) |
94b46f34 | 88 | // Only normalize `impl Trait` after type-checking, usually in codegen. |
0531ce1d XL |
89 | match self.param_env.reveal { |
90 | Reveal::UserFacing => ty, | |
91 | ||
92 | Reveal::All => { | |
83c7162d | 93 | let recursion_limit = *self.tcx().sess.recursion_limit.get(); |
0531ce1d XL |
94 | if self.anon_depth >= recursion_limit { |
95 | let obligation = Obligation::with_depth( | |
96 | self.cause.clone(), | |
97 | recursion_limit, | |
98 | self.param_env, | |
99 | ty, | |
100 | ); | |
101 | self.infcx.report_overflow_error(&obligation, true); | |
102 | } | |
103 | ||
104 | let generic_ty = self.tcx().type_of(def_id); | |
105 | let concrete_ty = generic_ty.subst(self.tcx(), substs); | |
106 | self.anon_depth += 1; | |
94b46f34 | 107 | if concrete_ty == ty { |
b7449926 XL |
108 | bug!( |
109 | "infinite recursion generic_ty: {:#?}, substs: {:#?}, \ | |
110 | concrete_ty: {:#?}, ty: {:#?}", | |
111 | generic_ty, | |
112 | substs, | |
113 | concrete_ty, | |
114 | ty | |
115 | ); | |
94b46f34 | 116 | } |
0531ce1d XL |
117 | let folded_ty = self.fold_ty(concrete_ty); |
118 | self.anon_depth -= 1; | |
119 | folded_ty | |
120 | } | |
121 | } | |
122 | } | |
123 | ||
a1dfa0c6 | 124 | ty::Projection(ref data) if !data.has_escaping_bound_vars() => { |
0531ce1d XL |
125 | // (*) |
126 | // (*) This is kind of hacky -- we need to be able to | |
127 | // handle normalization within binders because | |
128 | // otherwise we wind up a need to normalize when doing | |
129 | // trait matching (since you can have a trait | |
130 | // obligation like `for<'a> T::B : Fn(&'a int)`), but | |
131 | // we can't normalize with bound regions in scope. So | |
132 | // far now we just ignore binders but only normalize | |
133 | // if all bound regions are gone (and then we still | |
134 | // have to renormalize whenever we instantiate a | |
135 | // binder). It would be better to normalize in a | |
136 | // binding-aware fashion. | |
137 | ||
e74abb32 | 138 | let tcx = self.infcx.tcx; |
0531ce1d | 139 | |
0bf4aa26 | 140 | let mut orig_values = OriginalQueryValues::default(); |
dc9dc135 XL |
141 | // HACK(matthewjasper) `'static` is special-cased in selection, |
142 | // so we cannot canonicalize it. | |
dfeec247 XL |
143 | let c_data = self |
144 | .infcx | |
145 | .canonicalize_hr_query_hack(&self.param_env.and(*data), &mut orig_values); | |
0531ce1d XL |
146 | debug!("QueryNormalizer: c_data = {:#?}", c_data); |
147 | debug!("QueryNormalizer: orig_values = {:#?}", orig_values); | |
e74abb32 | 148 | match tcx.normalize_projection_ty(c_data) { |
0531ce1d XL |
149 | Ok(result) => { |
150 | // We don't expect ambiguity. | |
151 | if result.is_ambiguous() { | |
152 | self.error = true; | |
153 | return ty; | |
154 | } | |
155 | ||
0bf4aa26 | 156 | match self.infcx.instantiate_query_response_and_region_obligations( |
0531ce1d XL |
157 | self.cause, |
158 | self.param_env, | |
159 | &orig_values, | |
dfeec247 XL |
160 | &result, |
161 | ) { | |
0bf4aa26 | 162 | Ok(InferOk { value: result, obligations }) => { |
0531ce1d XL |
163 | debug!("QueryNormalizer: result = {:#?}", result); |
164 | debug!("QueryNormalizer: obligations = {:#?}", obligations); | |
165 | self.obligations.extend(obligations); | |
166 | return result.normalized_ty; | |
167 | } | |
168 | ||
169 | Err(_) => { | |
170 | self.error = true; | |
171 | return ty; | |
172 | } | |
173 | } | |
174 | } | |
175 | ||
176 | Err(NoSolution) => { | |
177 | self.error = true; | |
178 | ty | |
179 | } | |
180 | } | |
181 | } | |
182 | ||
183 | _ => ty, | |
184 | } | |
185 | } | |
186 | ||
532ac7d7 | 187 | fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { |
e1599b0c | 188 | constant.eval(self.infcx.tcx, self.param_env) |
0531ce1d XL |
189 | } |
190 | } |