1
1
use rustc_data_structures:: fx:: FxHashSet ;
2
+ use rustc_data_structures:: stack:: ensure_sufficient_stack;
2
3
use rustc_middle:: ty:: visit:: { TypeSuperVisitable , TypeVisitable , TypeVisitor } ;
3
4
use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
4
5
use rustc_span:: Span ;
@@ -27,12 +28,13 @@ impl From<ty::ParamConst> for Parameter {
27
28
28
29
/// Returns the set of parameters constrained by the impl header.
29
30
pub fn parameters_for_impl < ' tcx > (
31
+ tcx : TyCtxt < ' tcx > ,
30
32
impl_self_ty : Ty < ' tcx > ,
31
33
impl_trait_ref : Option < ty:: TraitRef < ' tcx > > ,
32
34
) -> FxHashSet < Parameter > {
33
35
let vec = match impl_trait_ref {
34
- Some ( tr) => parameters_for ( & tr, false ) ,
35
- None => parameters_for ( & impl_self_ty, false ) ,
36
+ Some ( tr) => parameters_for ( tcx , & tr, false ) ,
37
+ None => parameters_for ( tcx , & impl_self_ty, false ) ,
36
38
} ;
37
39
vec. into_iter ( ) . collect ( )
38
40
}
@@ -43,26 +45,47 @@ pub fn parameters_for_impl<'tcx>(
43
45
/// of parameters whose values are needed in order to constrain `ty` - these
44
46
/// differ, with the latter being a superset, in the presence of projections.
45
47
pub fn parameters_for < ' tcx > (
48
+ tcx : TyCtxt < ' tcx > ,
46
49
t : & impl TypeVisitable < TyCtxt < ' tcx > > ,
47
50
include_nonconstraining : bool ,
48
51
) -> Vec < Parameter > {
49
- let mut collector = ParameterCollector { parameters : vec ! [ ] , include_nonconstraining } ;
52
+ let mut collector =
53
+ ParameterCollector { tcx, parameters : vec ! [ ] , include_nonconstraining, depth : 0 } ;
50
54
t. visit_with ( & mut collector) ;
51
55
collector. parameters
52
56
}
53
57
54
- struct ParameterCollector {
58
+ struct ParameterCollector < ' tcx > {
59
+ tcx : TyCtxt < ' tcx > ,
55
60
parameters : Vec < Parameter > ,
56
61
include_nonconstraining : bool ,
62
+ depth : usize ,
57
63
}
58
64
59
- impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for ParameterCollector {
65
+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for ParameterCollector < ' tcx > {
60
66
fn visit_ty ( & mut self , t : Ty < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
61
67
match * t. kind ( ) {
62
- ty:: Alias ( ..) if !self . include_nonconstraining => {
63
- // projections are not injective
68
+ ty:: Alias ( ty:: Projection | ty:: Inherent | ty:: Opaque , _)
69
+ if !self . include_nonconstraining =>
70
+ {
71
+ // Projections are not injective in general.
64
72
return ControlFlow :: Continue ( ( ) ) ;
65
73
}
74
+ ty:: Alias ( ty:: Weak , alias) if !self . include_nonconstraining => {
75
+ if !self . tcx . recursion_limit ( ) . value_within_limit ( self . depth ) {
76
+ // Other constituent types may still constrain some generic params, consider
77
+ // `<T> (Overflow, T)` for example. Therefore we want to continue instead of
78
+ // breaking. Only affects diagnostics.
79
+ return ControlFlow :: Continue ( ( ) ) ;
80
+ }
81
+ self . depth += 1 ;
82
+ return ensure_sufficient_stack ( || {
83
+ self . tcx
84
+ . type_of ( alias. def_id )
85
+ . instantiate ( self . tcx , alias. args )
86
+ . visit_with ( self )
87
+ } ) ;
88
+ }
66
89
ty:: Param ( data) => {
67
90
self . parameters . push ( Parameter :: from ( data) ) ;
68
91
}
@@ -82,7 +105,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParameterCollector {
82
105
fn visit_const ( & mut self , c : ty:: Const < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
83
106
match c. kind ( ) {
84
107
ty:: ConstKind :: Unevaluated ( ..) if !self . include_nonconstraining => {
85
- // Constant expressions are not injective
108
+ // Constant expressions are not injective in general.
86
109
return c. ty ( ) . visit_with ( self ) ;
87
110
}
88
111
ty:: ConstKind :: Param ( data) => {
@@ -201,12 +224,12 @@ pub fn setup_constraining_predicates<'tcx>(
201
224
// `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
202
225
// Then the projection only applies if `T` is known, but it still
203
226
// does not determine `U`.
204
- let inputs = parameters_for ( & projection. projection_ty , true ) ;
227
+ let inputs = parameters_for ( tcx , & projection. projection_ty , true ) ;
205
228
let relies_only_on_inputs = inputs. iter ( ) . all ( |p| input_parameters. contains ( p) ) ;
206
229
if !relies_only_on_inputs {
207
230
continue ;
208
231
}
209
- input_parameters. extend ( parameters_for ( & projection. term , false ) ) ;
232
+ input_parameters. extend ( parameters_for ( tcx , & projection. term , false ) ) ;
210
233
} else {
211
234
continue ;
212
235
}
0 commit comments