@@ -43,7 +43,7 @@ use ty::{IntType, UintType};
4343use ty:: { self , Ty , TyCtxt } ;
4444use ty:: error:: TypeError ;
4545use ty:: relate:: { self , Relate , RelateResult , TypeRelation } ;
46- use traits:: PredicateObligations ;
46+ use traits:: { Obligation , PredicateObligations } ;
4747
4848use syntax:: ast;
4949use syntax_pos:: Span ;
@@ -206,11 +206,16 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
206206 // `'?2` and `?3` are fresh region/type inference
207207 // variables. (Down below, we will relate `a_ty <: b_ty`,
208208 // adding constraints like `'x: '?2` and `?1 <: ?3`.)
209- let b_ty = self . generalize ( a_ty, b_vid, dir) ?;
209+ let Generalization { ty : b_ty, needs_wf } = self . generalize ( a_ty, b_vid, dir) ?;
210210 debug ! ( "instantiate(a_ty={:?}, dir={:?}, b_vid={:?}, generalized b_ty={:?})" ,
211211 a_ty, dir, b_vid, b_ty) ;
212212 self . infcx . type_variables . borrow_mut ( ) . instantiate ( b_vid, b_ty) ;
213213
214+ if needs_wf {
215+ self . obligations . push ( Obligation :: new ( self . trace . cause . clone ( ) ,
216+ ty:: Predicate :: WellFormed ( b_ty) ) ) ;
217+ }
218+
214219 // Finally, relate `b_ty` to `a_ty`, as described in previous comment.
215220 //
216221 // FIXME(#16847): This code is non-ideal because all these subtype
@@ -229,10 +234,9 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
229234
230235 /// Attempts to generalize `ty` for the type variable `for_vid`.
231236 /// This checks for cycle -- that is, whether the type `ty`
232- /// references `for_vid`. If `is_eq_relation` is false, it will
233- /// also replace all regions/unbound-type-variables with fresh
234- /// variables. Returns `TyError` in the case of a cycle, `Ok`
235- /// otherwise.
237+ /// references `for_vid`. The `dir` is the "direction" for which we
238+ /// a performing the generalization (i.e., are we producing a type
239+ /// that can be used as a supertype etc).
236240 ///
237241 /// Preconditions:
238242 ///
@@ -241,7 +245,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
241245 ty : Ty < ' tcx > ,
242246 for_vid : ty:: TyVid ,
243247 dir : RelationDir )
244- -> RelateResult < ' tcx , Ty < ' tcx > >
248+ -> RelateResult < ' tcx , Generalization < ' tcx > >
245249 {
246250 // Determine the ambient variance within which `ty` appears.
247251 // The surrounding equation is:
@@ -261,9 +265,12 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
261265 span : self . trace . cause . span ,
262266 for_vid_sub_root : self . infcx . type_variables . borrow_mut ( ) . sub_root_var ( for_vid) ,
263267 ambient_variance : ambient_variance,
268+ needs_wf : false ,
264269 } ;
265270
266- generalize. relate ( & ty, & ty)
271+ let ty = generalize. relate ( & ty, & ty) ?;
272+ let needs_wf = generalize. needs_wf ;
273+ Ok ( Generalization { ty, needs_wf } )
267274 }
268275}
269276
@@ -272,6 +279,41 @@ struct Generalizer<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
272279 span : Span ,
273280 for_vid_sub_root : ty:: TyVid ,
274281 ambient_variance : ty:: Variance ,
282+ needs_wf : bool , // see the field `needs_wf` in `Generalization`
283+ }
284+
285+ /// Result from a generalization operation. This includes
286+ /// not only the generalized type, but also a bool flag
287+ /// indicating whether further WF checks are needed.q
288+ struct Generalization < ' tcx > {
289+ ty : Ty < ' tcx > ,
290+
291+ /// If true, then the generalized type may not be well-formed,
292+ /// even if the source type is well-formed, so we should add an
293+ /// additional check to enforce that it is. This arises in
294+ /// particular around 'bivariant' type parameters that are only
295+ /// constrained by a where-clause. As an example, imagine a type:
296+ ///
297+ /// struct Foo<A, B> where A: Iterator<Item=B> {
298+ /// data: A
299+ /// }
300+ ///
301+ /// here, `A` will be covariant, but `B` is
302+ /// unconstrained. However, whatever it is, for `Foo` to be WF, it
303+ /// must be equal to `A::Item`. If we have an input `Foo<?A, ?B>`,
304+ /// then after generalization we will wind up with a type like
305+ /// `Foo<?C, ?D>`. When we enforce that `Foo<?A, ?B> <: Foo<?C,
306+ /// ?D>` (or `>:`), we will wind up with the requirement that `?A
307+ /// <: ?C`, but no particular relationship between `?B` and `?D`
308+ /// (after all, we do not know the variance of the normalized form
309+ /// of `A::Item` with respect to `A`). If we do nothing else, this
310+ /// may mean that `?D` goes unconstrained (as in #41677). So, in
311+ /// this scenario where we create a new type variable in a
312+ /// bivariant context, we set the `needs_wf` flag to true. This
313+ /// will force the calling code to check that `WF(Foo<?C, ?D>)`
314+ /// holds, which in turn implies that `?C::Item == ?D`. So once
315+ /// `?C` is constrained, that should suffice to restrict `?D`.
316+ needs_wf : bool ,
275317}
276318
277319impl < ' cx , ' gcx , ' tcx > TypeRelation < ' cx , ' gcx , ' tcx > for Generalizer < ' cx , ' gcx , ' tcx > {
@@ -332,17 +374,26 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
332374 }
333375 None => {
334376 match self . ambient_variance {
335- ty:: Invariant => Ok ( t) ,
336-
337- ty:: Bivariant | ty:: Covariant | ty:: Contravariant => {
338- let origin = variables. origin ( vid) ;
339- let new_var_id = variables. new_var ( false , origin, None ) ;
340- let u = self . tcx ( ) . mk_var ( new_var_id) ;
341- debug ! ( "generalize: replacing original vid={:?} with new={:?}" ,
342- vid, u) ;
343- Ok ( u)
344- }
377+ // Invariant: no need to make a fresh type variable.
378+ ty:: Invariant => return Ok ( t) ,
379+
380+ // Bivariant: make a fresh var, but we
381+ // may need a WF predicate. See
382+ // comment on `needs_wf` field for
383+ // more info.
384+ ty:: Bivariant => self . needs_wf = true ,
385+
386+ // Co/contravariant: this will be
387+ // sufficiently constrained later on.
388+ ty:: Covariant | ty:: Contravariant => ( ) ,
345389 }
390+
391+ let origin = variables. origin ( vid) ;
392+ let new_var_id = variables. new_var ( false , origin, None ) ;
393+ let u = self . tcx ( ) . mk_var ( new_var_id) ;
394+ debug ! ( "generalize: replacing original vid={:?} with new={:?}" ,
395+ vid, u) ;
396+ return Ok ( u) ;
346397 }
347398 }
348399 }
0 commit comments