@@ -58,7 +58,7 @@ pub fn trait_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
58
58
-> Vec < traits:: PredicateObligation < ' tcx > >
59
59
{
60
60
let mut wf = WfPredicates { infcx, param_env, body_id, span, out : vec ! [ ] } ;
61
- wf. compute_trait_ref ( trait_ref) ;
61
+ wf. compute_trait_ref ( trait_ref, Elaborate :: All ) ;
62
62
wf. normalize ( )
63
63
}
64
64
@@ -74,7 +74,7 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
74
74
// (*) ok to skip binders, because wf code is prepared for it
75
75
match * predicate {
76
76
ty:: Predicate :: Trait ( ref t) => {
77
- wf. compute_trait_ref ( & t. skip_binder ( ) . trait_ref ) ; // (*)
77
+ wf. compute_trait_ref ( & t. skip_binder ( ) . trait_ref , Elaborate :: None ) ; // (*)
78
78
}
79
79
ty:: Predicate :: Equate ( ref t) => {
80
80
wf. compute ( t. skip_binder ( ) . 0 ) ;
@@ -114,6 +114,35 @@ struct WfPredicates<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
114
114
out : Vec < traits:: PredicateObligation < ' tcx > > ,
115
115
}
116
116
117
+ /// Controls whether we "elaborate" supertraits and so forth on the WF
118
+ /// predicates. This is a kind of hack to address #43784. The
119
+ /// underlying problem in that issue was a trait structure like:
120
+ ///
121
+ /// ```
122
+ /// trait Foo: Copy { }
123
+ /// trait Bar: Foo { }
124
+ /// impl<T: Bar> Foo for T { }
125
+ /// impl<T> Bar for T { }
126
+ /// ```
127
+ ///
128
+ /// Here, in the `Foo` impl, we will check that `T: Copy` holds -- but
129
+ /// we decide that this is true because `T: Bar` is in the
130
+ /// where-clauses (and we can elaborate that to include `T:
131
+ /// Copy`). This wouldn't be a problem, except that when we check the
132
+ /// `Bar` impl, we decide that `T: Foo` must hold because of the `Foo`
133
+ /// impl. And so nowhere did we check that `T: Copy` holds!
134
+ ///
135
+ /// To resolve this, we elaborate the WF requirements that must be
136
+ /// proven when checking impls. This means that (e.g.) the `impl Bar
137
+ /// for T` will be forced to prove not only that `T: Foo` but also `T:
138
+ /// Copy` (which it won't be able to do, because there is no `Copy`
139
+ /// impl for `T`).
140
+ #[ derive( Debug , PartialEq , Eq , Copy , Clone ) ]
141
+ enum Elaborate {
142
+ All ,
143
+ None ,
144
+ }
145
+
117
146
impl < ' a , ' gcx , ' tcx > WfPredicates < ' a , ' gcx , ' tcx > {
118
147
fn cause ( & mut self , code : traits:: ObligationCauseCode < ' tcx > ) -> traits:: ObligationCause < ' tcx > {
119
148
traits:: ObligationCause :: new ( self . span , self . body_id , code)
@@ -135,12 +164,25 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
135
164
136
165
/// Pushes the obligations required for `trait_ref` to be WF into
137
166
/// `self.out`.
138
- fn compute_trait_ref ( & mut self , trait_ref : & ty:: TraitRef < ' tcx > ) {
167
+ fn compute_trait_ref ( & mut self , trait_ref : & ty:: TraitRef < ' tcx > , elaborate : Elaborate ) {
139
168
let obligations = self . nominal_obligations ( trait_ref. def_id , trait_ref. substs ) ;
140
- self . out . extend ( obligations) ;
141
169
142
170
let cause = self . cause ( traits:: MiscObligation ) ;
143
171
let param_env = self . param_env ;
172
+
173
+ if let Elaborate :: All = elaborate {
174
+ let predicates = obligations. iter ( )
175
+ . map ( |obligation| obligation. predicate . clone ( ) )
176
+ . collect ( ) ;
177
+ let implied_obligations = traits:: elaborate_predicates ( self . infcx . tcx , predicates) ;
178
+ let implied_obligations = implied_obligations. map ( |pred| {
179
+ traits:: Obligation :: new ( cause. clone ( ) , param_env, pred)
180
+ } ) ;
181
+ self . out . extend ( implied_obligations) ;
182
+ }
183
+
184
+ self . out . extend ( obligations) ;
185
+
144
186
self . out . extend (
145
187
trait_ref. substs . types ( )
146
188
. filter ( |ty| !ty. has_escaping_regions ( ) )
@@ -156,7 +198,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
156
198
// WF and (b) the trait-ref holds. (It may also be
157
199
// normalizable and be WF that way.)
158
200
let trait_ref = data. trait_ref ( self . infcx . tcx ) ;
159
- self . compute_trait_ref ( & trait_ref) ;
201
+ self . compute_trait_ref ( & trait_ref, Elaborate :: None ) ;
160
202
161
203
if !data. has_escaping_regions ( ) {
162
204
let predicate = trait_ref. to_predicate ( ) ;
0 commit comments