@@ -58,7 +58,7 @@ pub fn trait_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
5858 -> Vec < traits:: PredicateObligation < ' tcx > >
5959{
6060 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 ) ;
6262 wf. normalize ( )
6363}
6464
@@ -74,7 +74,7 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
7474 // (*) ok to skip binders, because wf code is prepared for it
7575 match * predicate {
7676 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 ) ; // (*)
7878 }
7979 ty:: Predicate :: Equate ( ref t) => {
8080 wf. compute ( t. skip_binder ( ) . 0 ) ;
@@ -114,6 +114,35 @@ struct WfPredicates<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
114114 out : Vec < traits:: PredicateObligation < ' tcx > > ,
115115}
116116
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+
117146impl < ' a , ' gcx , ' tcx > WfPredicates < ' a , ' gcx , ' tcx > {
118147 fn cause ( & mut self , code : traits:: ObligationCauseCode < ' tcx > ) -> traits:: ObligationCause < ' tcx > {
119148 traits:: ObligationCause :: new ( self . span , self . body_id , code)
@@ -135,12 +164,25 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
135164
136165 /// Pushes the obligations required for `trait_ref` to be WF into
137166 /// `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 ) {
139168 let obligations = self . nominal_obligations ( trait_ref. def_id , trait_ref. substs ) ;
140- self . out . extend ( obligations) ;
141169
142170 let cause = self . cause ( traits:: MiscObligation ) ;
143171 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+
144186 self . out . extend (
145187 trait_ref. substs . types ( )
146188 . filter ( |ty| !ty. has_escaping_regions ( ) )
@@ -156,7 +198,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
156198 // WF and (b) the trait-ref holds. (It may also be
157199 // normalizable and be WF that way.)
158200 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 ) ;
160202
161203 if !data. has_escaping_regions ( ) {
162204 let predicate = trait_ref. to_predicate ( ) ;
0 commit comments