88//! or constant found within. (This underlying query is what is cached.)
99
1010use crate :: mir;
11+ use crate :: traits:: query:: NoSolution ;
1112use crate :: ty:: fold:: { TypeFoldable , TypeFolder } ;
1213use crate :: ty:: subst:: { Subst , SubstsRef } ;
1314use crate :: ty:: { self , Ty , TyCtxt } ;
1415
16+ #[ derive( Debug , Copy , Clone , HashStable , TyEncodable , TyDecodable ) ]
17+ pub enum NormalizationError < ' tcx > {
18+ Type ( Ty < ' tcx > ) ,
19+ Const ( ty:: Const < ' tcx > ) ,
20+ ConstantKind ( mir:: ConstantKind < ' tcx > ) ,
21+ }
22+
23+ impl < ' tcx > NormalizationError < ' tcx > {
24+ pub fn get_type_for_failure ( & self ) -> String {
25+ match self {
26+ NormalizationError :: Type ( t) => format ! ( "{}" , t) ,
27+ NormalizationError :: Const ( c) => format ! ( "{}" , c) ,
28+ NormalizationError :: ConstantKind ( ck) => format ! ( "{}" , ck) ,
29+ }
30+ }
31+ }
32+
1533impl < ' tcx > TyCtxt < ' tcx > {
1634 /// Erase the regions in `value` and then fully normalize all the
1735 /// types found within. The result will also have regions erased.
@@ -32,6 +50,8 @@ impl<'tcx> TyCtxt<'tcx> {
3250 // Erase first before we do the real query -- this keeps the
3351 // cache from being too polluted.
3452 let value = self . erase_regions ( value) ;
53+ debug ! ( ?value) ;
54+
3555 if !value. has_projections ( ) {
3656 value
3757 } else {
@@ -41,6 +61,39 @@ impl<'tcx> TyCtxt<'tcx> {
4161 }
4262 }
4363
64+ /// Tries to erase the regions in `value` and then fully normalize all the
65+ /// types found within. The result will also have regions erased.
66+ ///
67+ /// Contrary to `normalize_erasing_regions` this function does not assume that normalization
68+ /// succeeds.
69+ pub fn try_normalize_erasing_regions < T > (
70+ self ,
71+ param_env : ty:: ParamEnv < ' tcx > ,
72+ value : T ,
73+ ) -> Result < T , NormalizationError < ' tcx > >
74+ where
75+ T : TypeFoldable < ' tcx > ,
76+ {
77+ debug ! (
78+ "try_normalize_erasing_regions::<{}>(value={:?}, param_env={:?})" ,
79+ std:: any:: type_name:: <T >( ) ,
80+ value,
81+ param_env,
82+ ) ;
83+
84+ // Erase first before we do the real query -- this keeps the
85+ // cache from being too polluted.
86+ let value = self . erase_regions ( value) ;
87+ debug ! ( ?value) ;
88+
89+ if !value. has_projections ( ) {
90+ Ok ( value)
91+ } else {
92+ let mut folder = TryNormalizeAfterErasingRegionsFolder :: new ( self , param_env) ;
93+ value. fold_with ( & mut folder)
94+ }
95+ }
96+
4497 /// If you have a `Binder<'tcx, T>`, you can do this to strip out the
4598 /// late-bound regions and then normalize the result, yielding up
4699 /// a `T` (with regions erased). This is appropriate when the
@@ -91,11 +144,14 @@ struct NormalizeAfterErasingRegionsFolder<'tcx> {
91144}
92145
93146impl < ' tcx > NormalizeAfterErasingRegionsFolder < ' tcx > {
147+ #[ instrument( skip( self ) , level = "debug" ) ]
94148 fn normalize_generic_arg_after_erasing_regions (
95149 & self ,
96150 arg : ty:: GenericArg < ' tcx > ,
97151 ) -> ty:: GenericArg < ' tcx > {
98152 let arg = self . param_env . and ( arg) ;
153+ debug ! ( ?arg) ;
154+
99155 self . tcx . normalize_generic_arg_after_erasing_regions ( arg)
100156 }
101157}
@@ -126,3 +182,62 @@ impl TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> {
126182 Ok ( self . tcx . normalize_mir_const_after_erasing_regions ( arg) )
127183 }
128184}
185+
186+ struct TryNormalizeAfterErasingRegionsFolder < ' tcx > {
187+ tcx : TyCtxt < ' tcx > ,
188+ param_env : ty:: ParamEnv < ' tcx > ,
189+ }
190+
191+ impl < ' tcx > TryNormalizeAfterErasingRegionsFolder < ' tcx > {
192+ fn new ( tcx : TyCtxt < ' tcx > , param_env : ty:: ParamEnv < ' tcx > ) -> Self {
193+ TryNormalizeAfterErasingRegionsFolder { tcx, param_env }
194+ }
195+
196+ #[ instrument( skip( self ) , level = "debug" ) ]
197+ fn try_normalize_generic_arg_after_erasing_regions (
198+ & self ,
199+ arg : ty:: GenericArg < ' tcx > ,
200+ ) -> Result < ty:: GenericArg < ' tcx > , NoSolution > {
201+ let arg = self . param_env . and ( arg) ;
202+ debug ! ( ?arg) ;
203+
204+ self . tcx . try_normalize_generic_arg_after_erasing_regions ( arg)
205+ }
206+ }
207+
208+ impl TypeFolder < ' tcx > for TryNormalizeAfterErasingRegionsFolder < ' tcx > {
209+ type Error = NormalizationError < ' tcx > ;
210+
211+ fn tcx ( & self ) -> TyCtxt < ' tcx > {
212+ self . tcx
213+ }
214+
215+ fn fold_ty ( & mut self , ty : Ty < ' tcx > ) -> Result < Ty < ' tcx > , Self :: Error > {
216+ match self . try_normalize_generic_arg_after_erasing_regions ( ty. into ( ) ) {
217+ Ok ( t) => Ok ( t. expect_ty ( ) ) ,
218+ Err ( _) => Err ( NormalizationError :: Type ( ty) ) ,
219+ }
220+ }
221+
222+ fn fold_const (
223+ & mut self ,
224+ c : & ' tcx ty:: Const < ' tcx > ,
225+ ) -> Result < & ' tcx ty:: Const < ' tcx > , Self :: Error > {
226+ match self . try_normalize_generic_arg_after_erasing_regions ( c. into ( ) ) {
227+ Ok ( t) => Ok ( t. expect_const ( ) ) ,
228+ Err ( _) => Err ( NormalizationError :: Const ( * c) ) ,
229+ }
230+ }
231+
232+ fn fold_mir_const (
233+ & mut self ,
234+ c : mir:: ConstantKind < ' tcx > ,
235+ ) -> Result < mir:: ConstantKind < ' tcx > , Self :: Error > {
236+ // FIXME: This *probably* needs canonicalization too!
237+ let arg = self . param_env . and ( c) ;
238+ match self . tcx . try_normalize_mir_const_after_erasing_regions ( arg) {
239+ Ok ( c) => Ok ( c) ,
240+ Err ( _) => Err ( NormalizationError :: ConstantKind ( c) ) ,
241+ }
242+ }
243+ }
0 commit comments