]> git.proxmox.com Git - rustc.git/blame - src/librustc/traits/query/normalize.rs
New upstream version 1.42.0+dfsg1
[rustc.git] / src / librustc / traits / query / normalize.rs
CommitLineData
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
5use crate::infer::at::At;
6use crate::infer::canonical::OriginalQueryValues;
7use crate::infer::{InferCtxt, InferOk};
9fa01778
XL
8use crate::traits::project::Normalized;
9use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
10use crate::ty::fold::{TypeFoldable, TypeFolder};
e1599b0c 11use crate::ty::subst::Subst;
9fa01778 12use crate::ty::{self, Ty, TyCtxt};
0531ce1d
XL
13
14use super::NoSolution;
15
dc9dc135 16impl<'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
64pub struct NormalizationResult<'tcx> {
65 /// Result of normalization.
66 pub normalized_ty: Ty<'tcx>,
67}
68
dc9dc135
XL
69struct 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
78impl<'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}