8
8
//! or constant found within. (This underlying query is what is cached.)
9
9
10
10
use crate :: mir;
11
+ use crate :: traits:: query:: NoSolution ;
11
12
use crate :: ty:: fold:: { TypeFoldable , TypeFolder } ;
12
13
use crate :: ty:: subst:: { Subst , SubstsRef } ;
13
14
use crate :: ty:: { self , Ty , TyCtxt } ;
14
15
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
+
15
33
impl < ' tcx > TyCtxt < ' tcx > {
16
34
/// Erase the regions in `value` and then fully normalize all the
17
35
/// types found within. The result will also have regions erased.
@@ -32,6 +50,8 @@ impl<'tcx> TyCtxt<'tcx> {
32
50
// Erase first before we do the real query -- this keeps the
33
51
// cache from being too polluted.
34
52
let value = self . erase_regions ( value) ;
53
+ debug ! ( ?value) ;
54
+
35
55
if !value. has_projections ( ) {
36
56
value
37
57
} else {
@@ -41,6 +61,44 @@ impl<'tcx> TyCtxt<'tcx> {
41
61
}
42
62
}
43
63
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
+
44
102
/// If you have a `Binder<'tcx, T>`, you can do this to strip out the
45
103
/// late-bound regions and then normalize the result, yielding up
46
104
/// a `T` (with regions erased). This is appropriate when the
@@ -91,11 +149,14 @@ struct NormalizeAfterErasingRegionsFolder<'tcx> {
91
149
}
92
150
93
151
impl < ' tcx > NormalizeAfterErasingRegionsFolder < ' tcx > {
152
+ #[ instrument( skip( self ) , level = "debug" ) ]
94
153
fn normalize_generic_arg_after_erasing_regions (
95
154
& self ,
96
155
arg : ty:: GenericArg < ' tcx > ,
97
156
) -> ty:: GenericArg < ' tcx > {
98
157
let arg = self . param_env . and ( arg) ;
158
+ debug ! ( ?arg) ;
159
+
99
160
self . tcx . normalize_generic_arg_after_erasing_regions ( arg)
100
161
}
101
162
}
@@ -126,3 +187,69 @@ impl TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> {
126
187
Ok ( self . tcx . normalize_mir_const_after_erasing_regions ( arg) )
127
188
}
128
189
}
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