1
+ use smallvec:: SmallVec ;
2
+
1
3
use crate :: ty:: context:: TyCtxt ;
2
4
use crate :: ty:: { self , DefId , ParamEnv , Ty } ;
3
5
@@ -31,27 +33,31 @@ impl<'tcx> InhabitedPredicate<'tcx> {
31
33
/// Returns true if the corresponding type is inhabited in the given
32
34
/// `ParamEnv` and module
33
35
pub fn apply ( self , tcx : TyCtxt < ' tcx > , param_env : ParamEnv < ' tcx > , module_def_id : DefId ) -> bool {
34
- let Ok ( result) = self
35
- . apply_inner :: < !> ( tcx, param_env, & |id| Ok ( tcx. is_descendant_of ( module_def_id, id) ) ) ;
36
+ let Ok ( result) = self . apply_inner :: < !> ( tcx, param_env, & mut Default :: default ( ) , & |id| {
37
+ Ok ( tcx. is_descendant_of ( module_def_id, id) )
38
+ } ) ;
36
39
result
37
40
}
38
41
39
42
/// Same as `apply`, but returns `None` if self contains a module predicate
40
43
pub fn apply_any_module ( self , tcx : TyCtxt < ' tcx > , param_env : ParamEnv < ' tcx > ) -> Option < bool > {
41
- self . apply_inner ( tcx, param_env, & |_| Err ( ( ) ) ) . ok ( )
44
+ self . apply_inner ( tcx, param_env, & mut Default :: default ( ) , & |_| Err ( ( ) ) ) . ok ( )
42
45
}
43
46
44
47
/// Same as `apply`, but `NotInModule(_)` predicates yield `false`. That is,
45
48
/// privately uninhabited types are considered always uninhabited.
46
49
pub fn apply_ignore_module ( self , tcx : TyCtxt < ' tcx > , param_env : ParamEnv < ' tcx > ) -> bool {
47
- let Ok ( result) = self . apply_inner :: < !> ( tcx, param_env, & |_| Ok ( true ) ) ;
50
+ let Ok ( result) =
51
+ self . apply_inner :: < !> ( tcx, param_env, & mut Default :: default ( ) , & |_| Ok ( true ) ) ;
48
52
result
49
53
}
50
54
51
- fn apply_inner < E > (
55
+ #[ instrument( level = "debug" , skip( tcx, param_env, in_module) , ret) ]
56
+ fn apply_inner < E : std:: fmt:: Debug > (
52
57
self ,
53
58
tcx : TyCtxt < ' tcx > ,
54
59
param_env : ParamEnv < ' tcx > ,
60
+ eval_stack : & mut SmallVec < [ Ty < ' tcx > ; 1 ] > , // for cycle detection
55
61
in_module : & impl Fn ( DefId ) -> Result < bool , E > ,
56
62
) -> Result < bool , E > {
57
63
match self {
@@ -71,11 +77,25 @@ impl<'tcx> InhabitedPredicate<'tcx> {
71
77
match normalized_pred {
72
78
// We don't have more information than we started with, so consider inhabited.
73
79
Self :: GenericType ( _) => Ok ( true ) ,
74
- pred => pred. apply_inner ( tcx, param_env, in_module) ,
80
+ pred => {
81
+ // A type which is cyclic when monomorphized can happen here since the
82
+ // layout error would only trigger later. See e.g. `tests/ui/sized/recursive-type-2.rs`.
83
+ if eval_stack. contains ( & t) {
84
+ return Ok ( true ) ; // Recover; this will error later.
85
+ }
86
+ eval_stack. push ( t) ;
87
+ let ret = pred. apply_inner ( tcx, param_env, eval_stack, in_module) ;
88
+ eval_stack. pop ( ) ;
89
+ ret
90
+ }
75
91
}
76
92
}
77
- Self :: And ( [ a, b] ) => try_and ( a, b, |x| x. apply_inner ( tcx, param_env, in_module) ) ,
78
- Self :: Or ( [ a, b] ) => try_or ( a, b, |x| x. apply_inner ( tcx, param_env, in_module) ) ,
93
+ Self :: And ( [ a, b] ) => {
94
+ try_and ( a, b, |x| x. apply_inner ( tcx, param_env, eval_stack, in_module) )
95
+ }
96
+ Self :: Or ( [ a, b] ) => {
97
+ try_or ( a, b, |x| x. apply_inner ( tcx, param_env, eval_stack, in_module) )
98
+ }
79
99
}
80
100
}
81
101
@@ -197,7 +217,7 @@ impl<'tcx> InhabitedPredicate<'tcx> {
197
217
198
218
// this is basically like `f(a)? && f(b)?` but different in the case of
199
219
// `Ok(false) && Err(_) -> Ok(false)`
200
- fn try_and < T , E > ( a : T , b : T , f : impl Fn ( T ) -> Result < bool , E > ) -> Result < bool , E > {
220
+ fn try_and < T , E > ( a : T , b : T , mut f : impl FnMut ( T ) -> Result < bool , E > ) -> Result < bool , E > {
201
221
let a = f ( a) ;
202
222
if matches ! ( a, Ok ( false ) ) {
203
223
return Ok ( false ) ;
@@ -209,7 +229,7 @@ fn try_and<T, E>(a: T, b: T, f: impl Fn(T) -> Result<bool, E>) -> Result<bool, E
209
229
}
210
230
}
211
231
212
- fn try_or < T , E > ( a : T , b : T , f : impl Fn ( T ) -> Result < bool , E > ) -> Result < bool , E > {
232
+ fn try_or < T , E > ( a : T , b : T , mut f : impl FnMut ( T ) -> Result < bool , E > ) -> Result < bool , E > {
213
233
let a = f ( a) ;
214
234
if matches ! ( a, Ok ( true ) ) {
215
235
return Ok ( true ) ;
0 commit comments