Skip to content

Commit 141e8a6

Browse files
committed
Auto merge of #41716 - nikomatsakis:issue-41677, r=arielb1
enforce WF conditions after generalizing Add a `WF(T')` obligation after generalizing `T` to `T'`, if `T'` contains an unconstrained type variable in a bivariant context. Fixes #41677. Beta nominating -- regression. r? @arielb1
2 parents 39bcd6f + 2490ee5 commit 141e8a6

10 files changed

+249
-81
lines changed

src/librustc/infer/combine.rs

+143-41
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,8 @@ use super::{MiscVariable, TypeTrace};
4242
use ty::{IntType, UintType};
4343
use ty::{self, Ty, TyCtxt};
4444
use ty::error::TypeError;
45-
use ty::fold::TypeFoldable;
46-
use ty::relate::{RelateResult, TypeRelation};
47-
use traits::PredicateObligations;
45+
use ty::relate::{self, Relate, RelateResult, TypeRelation};
46+
use traits::{Obligation, PredicateObligations};
4847

4948
use syntax::ast;
5049
use syntax_pos::Span;
@@ -207,11 +206,16 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
207206
// `'?2` and `?3` are fresh region/type inference
208207
// variables. (Down below, we will relate `a_ty <: b_ty`,
209208
// adding constraints like `'x: '?2` and `?1 <: ?3`.)
210-
let b_ty = self.generalize(a_ty, b_vid, dir == EqTo)?;
209+
let Generalization { ty: b_ty, needs_wf } = self.generalize(a_ty, b_vid, dir)?;
211210
debug!("instantiate(a_ty={:?}, dir={:?}, b_vid={:?}, generalized b_ty={:?})",
212211
a_ty, dir, b_vid, b_ty);
213212
self.infcx.type_variables.borrow_mut().instantiate(b_vid, b_ty);
214213

214+
if needs_wf {
215+
self.obligations.push(Obligation::new(self.trace.cause.clone(),
216+
ty::Predicate::WellFormed(b_ty)));
217+
}
218+
215219
// Finally, relate `b_ty` to `a_ty`, as described in previous comment.
216220
//
217221
// FIXME(#16847): This code is non-ideal because all these subtype
@@ -230,50 +234,125 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
230234

231235
/// Attempts to generalize `ty` for the type variable `for_vid`.
232236
/// This checks for cycle -- that is, whether the type `ty`
233-
/// references `for_vid`. If `is_eq_relation` is false, it will
234-
/// also replace all regions/unbound-type-variables with fresh
235-
/// variables. Returns `TyError` in the case of a cycle, `Ok`
236-
/// 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).
237240
///
238241
/// Preconditions:
239242
///
240243
/// - `for_vid` is a "root vid"
241244
fn generalize(&self,
242245
ty: Ty<'tcx>,
243246
for_vid: ty::TyVid,
244-
is_eq_relation: bool)
245-
-> RelateResult<'tcx, Ty<'tcx>>
247+
dir: RelationDir)
248+
-> RelateResult<'tcx, Generalization<'tcx>>
246249
{
250+
// Determine the ambient variance within which `ty` appears.
251+
// The surrounding equation is:
252+
//
253+
// ty [op] ty2
254+
//
255+
// where `op` is either `==`, `<:`, or `:>`. This maps quite
256+
// naturally.
257+
let ambient_variance = match dir {
258+
RelationDir::EqTo => ty::Invariant,
259+
RelationDir::SubtypeOf => ty::Covariant,
260+
RelationDir::SupertypeOf => ty::Contravariant,
261+
};
262+
247263
let mut generalize = Generalizer {
248264
infcx: self.infcx,
249265
span: self.trace.cause.span,
250266
for_vid_sub_root: self.infcx.type_variables.borrow_mut().sub_root_var(for_vid),
251-
is_eq_relation: is_eq_relation,
252-
cycle_detected: false
267+
ambient_variance: ambient_variance,
268+
needs_wf: false,
253269
};
254-
let u = ty.fold_with(&mut generalize);
255-
if generalize.cycle_detected {
256-
Err(TypeError::CyclicTy)
257-
} else {
258-
Ok(u)
259-
}
270+
271+
let ty = generalize.relate(&ty, &ty)?;
272+
let needs_wf = generalize.needs_wf;
273+
Ok(Generalization { ty, needs_wf })
260274
}
261275
}
262276

263277
struct Generalizer<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
264278
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
265279
span: Span,
266280
for_vid_sub_root: ty::TyVid,
267-
is_eq_relation: bool,
268-
cycle_detected: bool,
281+
ambient_variance: ty::Variance,
282+
needs_wf: bool, // see the field `needs_wf` in `Generalization`
269283
}
270284

271-
impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx, 'tcx> {
272-
fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx> {
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,
317+
}
318+
319+
impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, 'tcx> {
320+
fn tcx(&self) -> TyCtxt<'cx, 'gcx, 'tcx> {
273321
self.infcx.tcx
274322
}
275323

276-
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
324+
fn tag(&self) -> &'static str {
325+
"Generalizer"
326+
}
327+
328+
fn a_is_expected(&self) -> bool {
329+
true
330+
}
331+
332+
fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
333+
-> RelateResult<'tcx, ty::Binder<T>>
334+
where T: Relate<'tcx>
335+
{
336+
Ok(ty::Binder(self.relate(a.skip_binder(), b.skip_binder())?))
337+
}
338+
339+
fn relate_with_variance<T: Relate<'tcx>>(&mut self,
340+
variance: ty::Variance,
341+
a: &T,
342+
b: &T)
343+
-> RelateResult<'tcx, T>
344+
{
345+
let old_ambient_variance = self.ambient_variance;
346+
self.ambient_variance = self.ambient_variance.xform(variance);
347+
348+
let result = self.relate(a, b);
349+
self.ambient_variance = old_ambient_variance;
350+
result
351+
}
352+
353+
fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
354+
assert_eq!(t, t2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
355+
277356
// Check to see whether the type we are genealizing references
278357
// any other type variable related to `vid` via
279358
// subtyping. This is basically our "occurs check", preventing
@@ -286,41 +365,63 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx
286365
if sub_vid == self.for_vid_sub_root {
287366
// If sub-roots are equal, then `for_vid` and
288367
// `vid` are related via subtyping.
289-
self.cycle_detected = true;
290-
self.tcx().types.err
368+
return Err(TypeError::CyclicTy);
291369
} else {
292370
match variables.probe_root(vid) {
293371
Some(u) => {
294372
drop(variables);
295-
self.fold_ty(u)
373+
self.relate(&u, &u)
296374
}
297375
None => {
298-
if !self.is_eq_relation {
299-
let origin = variables.origin(vid);
300-
let new_var_id = variables.new_var(false, origin, None);
301-
let u = self.tcx().mk_var(new_var_id);
302-
debug!("generalize: replacing original vid={:?} with new={:?}",
303-
vid, u);
304-
u
305-
} else {
306-
t
376+
match self.ambient_variance {
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 => (),
307389
}
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);
308397
}
309398
}
310399
}
311400
}
401+
ty::TyInfer(ty::IntVar(_)) |
402+
ty::TyInfer(ty::FloatVar(_)) => {
403+
// No matter what mode we are in,
404+
// integer/floating-point types must be equal to be
405+
// relatable.
406+
Ok(t)
407+
}
312408
_ => {
313-
t.super_fold_with(self)
409+
relate::super_relate_tys(self, t, t)
314410
}
315411
}
316412
}
317413

318-
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
414+
fn regions(&mut self, r: ty::Region<'tcx>, r2: ty::Region<'tcx>)
415+
-> RelateResult<'tcx, ty::Region<'tcx>> {
416+
assert_eq!(r, r2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
417+
319418
match *r {
320419
// Never make variables for regions bound within the type itself,
321420
// nor for erased regions.
322421
ty::ReLateBound(..) |
323-
ty::ReErased => { return r; }
422+
ty::ReErased => {
423+
return Ok(r);
424+
}
324425

325426
// Early-bound regions should really have been substituted away before
326427
// we get to this point.
@@ -342,15 +443,16 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx
342443
ty::ReScope(..) |
343444
ty::ReVar(..) |
344445
ty::ReFree(..) => {
345-
if self.is_eq_relation {
346-
return r;
446+
match self.ambient_variance {
447+
ty::Invariant => return Ok(r),
448+
ty::Bivariant | ty::Covariant | ty::Contravariant => (),
347449
}
348450
}
349451
}
350452

351453
// FIXME: This is non-ideal because we don't give a
352454
// very descriptive origin for this region variable.
353-
self.infcx.next_region_var(MiscVariable(self.span))
455+
Ok(self.infcx.next_region_var(MiscVariable(self.span)))
354456
}
355457
}
356458

src/librustc/ty/mod.rs

+60
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,66 @@ pub struct CrateVariancesMap {
330330
pub empty_variance: Rc<Vec<ty::Variance>>,
331331
}
332332

333+
impl Variance {
334+
/// `a.xform(b)` combines the variance of a context with the
335+
/// variance of a type with the following meaning. If we are in a
336+
/// context with variance `a`, and we encounter a type argument in
337+
/// a position with variance `b`, then `a.xform(b)` is the new
338+
/// variance with which the argument appears.
339+
///
340+
/// Example 1:
341+
///
342+
/// *mut Vec<i32>
343+
///
344+
/// Here, the "ambient" variance starts as covariant. `*mut T` is
345+
/// invariant with respect to `T`, so the variance in which the
346+
/// `Vec<i32>` appears is `Covariant.xform(Invariant)`, which
347+
/// yields `Invariant`. Now, the type `Vec<T>` is covariant with
348+
/// respect to its type argument `T`, and hence the variance of
349+
/// the `i32` here is `Invariant.xform(Covariant)`, which results
350+
/// (again) in `Invariant`.
351+
///
352+
/// Example 2:
353+
///
354+
/// fn(*const Vec<i32>, *mut Vec<i32)
355+
///
356+
/// The ambient variance is covariant. A `fn` type is
357+
/// contravariant with respect to its parameters, so the variance
358+
/// within which both pointer types appear is
359+
/// `Covariant.xform(Contravariant)`, or `Contravariant`. `*const
360+
/// T` is covariant with respect to `T`, so the variance within
361+
/// which the first `Vec<i32>` appears is
362+
/// `Contravariant.xform(Covariant)` or `Contravariant`. The same
363+
/// is true for its `i32` argument. In the `*mut T` case, the
364+
/// variance of `Vec<i32>` is `Contravariant.xform(Invariant)`,
365+
/// and hence the outermost type is `Invariant` with respect to
366+
/// `Vec<i32>` (and its `i32` argument).
367+
///
368+
/// Source: Figure 1 of "Taming the Wildcards:
369+
/// Combining Definition- and Use-Site Variance" published in PLDI'11.
370+
pub fn xform(self, v: ty::Variance) -> ty::Variance {
371+
match (self, v) {
372+
// Figure 1, column 1.
373+
(ty::Covariant, ty::Covariant) => ty::Covariant,
374+
(ty::Covariant, ty::Contravariant) => ty::Contravariant,
375+
(ty::Covariant, ty::Invariant) => ty::Invariant,
376+
(ty::Covariant, ty::Bivariant) => ty::Bivariant,
377+
378+
// Figure 1, column 2.
379+
(ty::Contravariant, ty::Covariant) => ty::Contravariant,
380+
(ty::Contravariant, ty::Contravariant) => ty::Covariant,
381+
(ty::Contravariant, ty::Invariant) => ty::Invariant,
382+
(ty::Contravariant, ty::Bivariant) => ty::Bivariant,
383+
384+
// Figure 1, column 3.
385+
(ty::Invariant, _) => ty::Invariant,
386+
387+
// Figure 1, column 4.
388+
(ty::Bivariant, _) => ty::Bivariant,
389+
}
390+
}
391+
}
392+
333393
#[derive(Clone, Copy, Debug, RustcDecodable, RustcEncodable)]
334394
pub struct MethodCallee<'tcx> {
335395
/// Impl method ID, for inherent methods, or trait method ID, otherwise.

src/librustc_typeck/variance/constraints.rs

-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ use rustc_data_structures::transitive_relation::TransitiveRelation;
2727

2828
use super::terms::*;
2929
use super::terms::VarianceTerm::*;
30-
use super::xform::*;
3130

3231
pub struct ConstraintContext<'a, 'tcx: 'a> {
3332
pub terms_cx: TermsContext<'a, 'tcx>,

src/librustc_typeck/variance/xform.rs

-29
Original file line numberDiff line numberDiff line change
@@ -10,35 +10,6 @@
1010

1111
use rustc::ty;
1212

13-
pub trait Xform {
14-
fn xform(self, v: Self) -> Self;
15-
}
16-
17-
impl Xform for ty::Variance {
18-
fn xform(self, v: ty::Variance) -> ty::Variance {
19-
// "Variance transformation", Figure 1 of The Paper
20-
match (self, v) {
21-
// Figure 1, column 1.
22-
(ty::Covariant, ty::Covariant) => ty::Covariant,
23-
(ty::Covariant, ty::Contravariant) => ty::Contravariant,
24-
(ty::Covariant, ty::Invariant) => ty::Invariant,
25-
(ty::Covariant, ty::Bivariant) => ty::Bivariant,
26-
27-
// Figure 1, column 2.
28-
(ty::Contravariant, ty::Covariant) => ty::Contravariant,
29-
(ty::Contravariant, ty::Contravariant) => ty::Covariant,
30-
(ty::Contravariant, ty::Invariant) => ty::Invariant,
31-
(ty::Contravariant, ty::Bivariant) => ty::Bivariant,
32-
33-
// Figure 1, column 3.
34-
(ty::Invariant, _) => ty::Invariant,
35-
36-
// Figure 1, column 4.
37-
(ty::Bivariant, _) => ty::Bivariant,
38-
}
39-
}
40-
}
41-
4213
pub fn glb(v1: ty::Variance, v2: ty::Variance) -> ty::Variance {
4314
// Greatest lower bound of the variance lattice as
4415
// defined in The Paper:

src/test/compile-fail/region-invariant-static-error-reporting.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,8 @@
1313
// over time, but this test used to exhibit some pretty bogus messages
1414
// that were not remotely helpful.
1515

16-
// error-pattern:cannot infer
17-
// error-pattern:cannot outlive the lifetime 'a
18-
// error-pattern:must be valid for the static lifetime
16+
// error-pattern:the lifetime 'a
17+
// error-pattern:the static lifetime
1918

2019
struct Invariant<'a>(Option<&'a mut &'a mut ()>);
2120

0 commit comments

Comments
 (0)