@@ -19,15 +19,20 @@ pub enum Parameter {
19
19
Region ( ty:: EarlyBoundRegion ) ,
20
20
}
21
21
22
- /// Returns the list of parameters that are constrained by the type `ty`
23
- /// - i.e. the value of each parameter in the list is uniquely determined
24
- /// by `ty` (see RFC 447).
25
- pub fn parameters_for_type < ' tcx > ( ty : Ty < ' tcx > ) -> Vec < Parameter > {
22
+ /// If `include_projections` is false, returns the list of parameters that are
23
+ /// constrained by the type `ty` - i.e. the value of each parameter in the list is
24
+ /// uniquely determined by `ty` (see RFC 447). If it is true, return the list
25
+ /// of parameters whose values are needed in order to constrain `ty` - these
26
+ /// differ, with the latter being a superset, in the presence of projections.
27
+ pub fn parameters_for_type < ' tcx > ( ty : Ty < ' tcx > ,
28
+ include_projections : bool ) -> Vec < Parameter > {
26
29
let mut result = vec ! [ ] ;
27
- ty. maybe_walk ( |t| {
28
- if let ty:: TyProjection ( ..) = t. sty {
30
+ ty. maybe_walk ( |t| match t. sty {
31
+ ty:: TyProjection ( ..) if !include_projections => {
32
+
29
33
false // projections are not injective.
30
- } else {
34
+ }
35
+ _ => {
31
36
result. append ( & mut parameters_for_type_shallow ( t) ) ;
32
37
// non-projection type constructors are injective.
33
38
true
@@ -36,13 +41,16 @@ pub fn parameters_for_type<'tcx>(ty: Ty<'tcx>) -> Vec<Parameter> {
36
41
result
37
42
}
38
43
39
- pub fn parameters_for_trait_ref < ' tcx > ( trait_ref : & ty:: TraitRef < ' tcx > ) -> Vec < Parameter > {
44
+ pub fn parameters_for_trait_ref < ' tcx > ( trait_ref : & ty:: TraitRef < ' tcx > ,
45
+ include_projections : bool ) -> Vec < Parameter > {
40
46
let mut region_parameters =
41
47
parameters_for_regions_in_substs ( & trait_ref. substs ) ;
42
48
43
49
let type_parameters =
44
- trait_ref. substs . types . iter ( )
45
- . flat_map ( |ty| parameters_for_type ( ty) ) ;
50
+ trait_ref. substs
51
+ . types
52
+ . iter ( )
53
+ . flat_map ( |ty| parameters_for_type ( ty, include_projections) ) ;
46
54
47
55
region_parameters. extend ( type_parameters) ;
48
56
@@ -60,8 +68,14 @@ fn parameters_for_type_shallow<'tcx>(ty: Ty<'tcx>) -> Vec<Parameter> {
60
68
parameters_for_regions_in_substs ( substs) ,
61
69
ty:: TyTrait ( ref data) =>
62
70
parameters_for_regions_in_substs ( & data. principal . skip_binder ( ) . substs ) ,
63
- _ =>
64
- vec ! [ ] ,
71
+ ty:: TyProjection ( ref pi) =>
72
+ parameters_for_regions_in_substs ( & pi. trait_ref . substs ) ,
73
+ ty:: TyBool | ty:: TyChar | ty:: TyInt ( ..) | ty:: TyUint ( ..) |
74
+ ty:: TyFloat ( ..) | ty:: TyBox ( ..) | ty:: TyStr |
75
+ ty:: TyArray ( ..) | ty:: TySlice ( ..) | ty:: TyBareFn ( ..) |
76
+ ty:: TyTuple ( ..) | ty:: TyRawPtr ( ..) |
77
+ ty:: TyInfer ( ..) | ty:: TyClosure ( ..) | ty:: TyError =>
78
+ vec ! [ ]
65
79
}
66
80
}
67
81
@@ -113,6 +127,22 @@ pub fn identify_constrained_type_params<'tcx>(_tcx: &ty::ctxt<'tcx>,
113
127
/// pass, we want the projection to come first. In fact, as projections
114
128
/// can (acyclically) depend on one another - see RFC447 for details - we
115
129
/// need to topologically sort them.
130
+ ///
131
+ /// We *do* have to be somewhat careful when projection targets contain
132
+ /// projections themselves, for example in
133
+ /// impl<S,U,V,W> Trait for U where
134
+ /// /* 0 */ S: Iterator<Item=U>,
135
+ /// /* - */ U: Iterator,
136
+ /// /* 1 */ <U as Iterator>::Item: ToOwned<Owned=(W,<V as Iterator>::Item)>
137
+ /// /* 2 */ W: Iterator<Item=V>
138
+ /// /* 3 */ V: Debug
139
+ /// we have to evaluate the projections in the order I wrote them:
140
+ /// `V: Debug` requires `V` to be evaluated. The only projection that
141
+ /// *determines* `V` is 2 (1 contains it, but *does not determine it*,
142
+ /// as it is only contained within a projection), but that requires `W`
143
+ /// which is determined by 1, which requires `U`, that is determined
144
+ /// by 0. I should probably pick a less tangled example, but I can't
145
+ /// think of any.
116
146
pub fn setup_constraining_predicates < ' tcx > ( _tcx : & ty:: ctxt < ' tcx > ,
117
147
predicates : & mut [ ty:: Predicate < ' tcx > ] ,
118
148
impl_trait_ref : Option < ty:: TraitRef < ' tcx > > ,
@@ -157,12 +187,18 @@ pub fn setup_constraining_predicates<'tcx>(_tcx: &ty::ctxt<'tcx>,
157
187
continue ;
158
188
}
159
189
160
- let inputs = parameters_for_trait_ref ( & projection. projection_ty . trait_ref ) ;
190
+ // A projection depends on its input types and determines its output
191
+ // type. For example, if we have
192
+ // `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
193
+ // Then the projection only applies if `T` is known, but it still
194
+ // does not determine `U`.
195
+
196
+ let inputs = parameters_for_trait_ref ( & projection. projection_ty . trait_ref , true ) ;
161
197
let relies_only_on_inputs = inputs. iter ( ) . all ( |p| input_parameters. contains ( & p) ) ;
162
198
if !relies_only_on_inputs {
163
199
continue ;
164
200
}
165
- input_parameters. extend ( parameters_for_type ( projection. ty ) ) ;
201
+ input_parameters. extend ( parameters_for_type ( projection. ty , false ) ) ;
166
202
} else {
167
203
continue ;
168
204
}
0 commit comments