Skip to content

Commit a950c37

Browse files
committed
replace the type generalizer with one based on variance
1 parent 24ea08e commit a950c37

File tree

4 files changed

+146
-65
lines changed

4 files changed

+146
-65
lines changed

src/librustc/infer/combine.rs

+86-35
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ 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};
45+
use ty::relate::{self, Relate, RelateResult, TypeRelation};
4746
use traits::PredicateObligations;
4847

4948
use syntax::ast;
@@ -207,7 +206,7 @@ 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 b_ty = 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);
@@ -241,39 +240,77 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
241240
fn generalize(&self,
242241
ty: Ty<'tcx>,
243242
for_vid: ty::TyVid,
244-
is_eq_relation: bool)
243+
dir: RelationDir)
245244
-> RelateResult<'tcx, Ty<'tcx>>
246245
{
246+
// Determine the ambient variance within which `ty` appears.
247+
// The surrounding equation is:
248+
//
249+
// ty [op] ty2
250+
//
251+
// where `op` is either `==`, `<:`, or `:>`. This maps quite
252+
// naturally.
253+
let ambient_variance = match dir {
254+
RelationDir::EqTo => ty::Invariant,
255+
RelationDir::SubtypeOf => ty::Covariant,
256+
RelationDir::SupertypeOf => ty::Contravariant,
257+
};
258+
247259
let mut generalize = Generalizer {
248260
infcx: self.infcx,
249261
span: self.trace.cause.span,
250262
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
263+
ambient_variance: ambient_variance,
253264
};
254-
let u = ty.fold_with(&mut generalize);
255-
if generalize.cycle_detected {
256-
Err(TypeError::CyclicTy)
257-
} else {
258-
Ok(u)
259-
}
265+
266+
generalize.relate(&ty, &ty)
260267
}
261268
}
262269

263270
struct Generalizer<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
264271
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
265272
span: Span,
266273
for_vid_sub_root: ty::TyVid,
267-
is_eq_relation: bool,
268-
cycle_detected: bool,
274+
ambient_variance: ty::Variance,
269275
}
270276

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> {
277+
impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, 'tcx> {
278+
fn tcx(&self) -> TyCtxt<'cx, 'gcx, 'tcx> {
273279
self.infcx.tcx
274280
}
275281

276-
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
282+
fn tag(&self) -> &'static str {
283+
"Generalizer"
284+
}
285+
286+
fn a_is_expected(&self) -> bool {
287+
true
288+
}
289+
290+
fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
291+
-> RelateResult<'tcx, ty::Binder<T>>
292+
where T: Relate<'tcx>
293+
{
294+
Ok(ty::Binder(self.relate(a.skip_binder(), b.skip_binder())?))
295+
}
296+
297+
fn relate_with_variance<T: Relate<'tcx>>(&mut self,
298+
variance: ty::Variance,
299+
a: &T,
300+
b: &T)
301+
-> RelateResult<'tcx, T>
302+
{
303+
let old_ambient_variance = self.ambient_variance;
304+
self.ambient_variance = self.ambient_variance.xform(variance);
305+
306+
let result = self.relate(a, b);
307+
self.ambient_variance = old_ambient_variance;
308+
result
309+
}
310+
311+
fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
312+
assert_eq!(t, t2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
313+
277314
// Check to see whether the type we are genealizing references
278315
// any other type variable related to `vid` via
279316
// subtyping. This is basically our "occurs check", preventing
@@ -286,41 +323,54 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx
286323
if sub_vid == self.for_vid_sub_root {
287324
// If sub-roots are equal, then `for_vid` and
288325
// `vid` are related via subtyping.
289-
self.cycle_detected = true;
290-
self.tcx().types.err
326+
return Err(TypeError::CyclicTy);
291327
} else {
292328
match variables.probe_root(vid) {
293329
Some(u) => {
294330
drop(variables);
295-
self.fold_ty(u)
331+
self.relate(&u, &u)
296332
}
297333
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
334+
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+
}
307345
}
308346
}
309347
}
310348
}
311349
}
350+
ty::TyInfer(ty::IntVar(_)) |
351+
ty::TyInfer(ty::FloatVar(_)) => {
352+
// No matter what mode we are in,
353+
// integer/floating-point types must be equal to be
354+
// relatable.
355+
Ok(t)
356+
}
312357
_ => {
313-
t.super_fold_with(self)
358+
relate::super_relate_tys(self, t, t)
314359
}
315360
}
316361
}
317362

318-
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
363+
fn regions(&mut self, r: ty::Region<'tcx>, r2: ty::Region<'tcx>)
364+
-> RelateResult<'tcx, ty::Region<'tcx>> {
365+
assert_eq!(r, r2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
366+
319367
match *r {
320368
// Never make variables for regions bound within the type itself,
321369
// nor for erased regions.
322370
ty::ReLateBound(..) |
323-
ty::ReErased => { return r; }
371+
ty::ReErased => {
372+
return Ok(r);
373+
}
324374

325375
// Early-bound regions should really have been substituted away before
326376
// we get to this point.
@@ -342,15 +392,16 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx
342392
ty::ReScope(..) |
343393
ty::ReVar(..) |
344394
ty::ReFree(..) => {
345-
if self.is_eq_relation {
346-
return r;
395+
match self.ambient_variance {
396+
ty::Invariant => return Ok(r),
397+
ty::Bivariant | ty::Covariant | ty::Contravariant => (),
347398
}
348399
}
349400
}
350401

351402
// FIXME: This is non-ideal because we don't give a
352403
// very descriptive origin for this region variable.
353-
self.infcx.next_region_var(MiscVariable(self.span))
404+
Ok(self.infcx.next_region_var(MiscVariable(self.span)))
354405
}
355406
}
356407

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:

0 commit comments

Comments
 (0)