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,44 @@ 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+ let result = value. fold_with ( & mut folder) ;
94+
95+ match folder. found_normalization_error ( ) {
96+ Some ( e) => Err ( e) ,
97+ None => Ok ( result) ,
98+ }
99+ }
100+ }
101+
44102 /// If you have a `Binder<'tcx, T>`, you can do this to strip out the
45103 /// late-bound regions and then normalize the result, yielding up
46104 /// a `T` (with regions erased). This is appropriate when the
@@ -91,11 +149,14 @@ struct NormalizeAfterErasingRegionsFolder<'tcx> {
91149}
92150
93151impl < ' tcx > NormalizeAfterErasingRegionsFolder < ' tcx > {
152+ #[ instrument( skip( self ) , level = "debug" ) ]
94153 fn normalize_generic_arg_after_erasing_regions (
95154 & self ,
96155 arg : ty:: GenericArg < ' tcx > ,
97156 ) -> ty:: GenericArg < ' tcx > {
98157 let arg = self . param_env . and ( arg) ;
158+ debug ! ( ?arg) ;
159+
99160 self . tcx . normalize_generic_arg_after_erasing_regions ( arg)
100161 }
101162}
@@ -126,3 +187,69 @@ impl TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> {
126187 Ok ( self . tcx . normalize_mir_const_after_erasing_regions ( arg) )
127188 }
128189}
190+
191+ struct TryNormalizeAfterErasingRegionsFolder < ' tcx > {
192+ tcx : TyCtxt < ' tcx > ,
193+ param_env : ty:: ParamEnv < ' tcx > ,
194+ normalization_error : Option < NormalizationError < ' tcx > > ,
195+ }
196+
197+ impl < ' tcx > TryNormalizeAfterErasingRegionsFolder < ' tcx > {
198+ fn new ( tcx : TyCtxt < ' tcx > , param_env : ty:: ParamEnv < ' tcx > ) -> Self {
199+ TryNormalizeAfterErasingRegionsFolder { tcx, param_env, normalization_error : None }
200+ }
201+
202+ #[ instrument( skip( self ) , level = "debug" ) ]
203+ fn try_normalize_generic_arg_after_erasing_regions (
204+ & self ,
205+ arg : ty:: GenericArg < ' tcx > ,
206+ ) -> Result < ty:: GenericArg < ' tcx > , NoSolution > {
207+ let arg = self . param_env . and ( arg) ;
208+ debug ! ( ?arg) ;
209+
210+ self . tcx . try_normalize_generic_arg_after_erasing_regions ( arg)
211+ }
212+
213+ pub fn found_normalization_error ( & self ) -> Option < NormalizationError < ' tcx > > {
214+ self . normalization_error
215+ }
216+ }
217+
218+ impl TypeFolder < ' tcx > for TryNormalizeAfterErasingRegionsFolder < ' tcx > {
219+ fn tcx ( & self ) -> TyCtxt < ' tcx > {
220+ self . tcx
221+ }
222+
223+ fn fold_ty ( & mut self , ty : Ty < ' tcx > ) -> Ty < ' tcx > {
224+ match self . try_normalize_generic_arg_after_erasing_regions ( ty. into ( ) ) {
225+ Ok ( t) => t. expect_ty ( ) ,
226+ Err ( _) => {
227+ self . normalization_error = Some ( NormalizationError :: Type ( ty) ) ;
228+ ty
229+ }
230+ }
231+ }
232+
233+ fn fold_const ( & mut self , c : & ' tcx ty:: Const < ' tcx > ) -> & ' tcx ty:: Const < ' tcx > {
234+ match self . try_normalize_generic_arg_after_erasing_regions ( c. into ( ) ) {
235+ Ok ( t) => t. expect_const ( ) ,
236+ Err ( _) => {
237+ self . normalization_error = Some ( NormalizationError :: Const ( * c) ) ;
238+ c
239+ }
240+ }
241+ }
242+
243+ #[ inline]
244+ fn fold_mir_const ( & mut self , c : mir:: ConstantKind < ' tcx > ) -> mir:: ConstantKind < ' tcx > {
245+ // FIXME: This *probably* needs canonicalization too!
246+ let arg = self . param_env . and ( c) ;
247+ match self . tcx . try_normalize_mir_const_after_erasing_regions ( arg) {
248+ Ok ( c) => c,
249+ Err ( _) => {
250+ self . normalization_error = Some ( NormalizationError :: ConstantKind ( c) ) ;
251+ c
252+ }
253+ }
254+ }
255+ }
0 commit comments