Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/librustc/ich/impls_ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ impl_stable_hash_for!(enum ty::Visibility {
impl_stable_hash_for!(struct ty::TraitRef<'tcx> { def_id, substs });
impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref });
impl_stable_hash_for!(tuple_struct ty::EquatePredicate<'tcx> { t1, t2 });
impl_stable_hash_for!(struct ty::SubtypePredicate<'tcx> { a_is_expected, a, b });

impl<'a, 'tcx, A, B> HashStable<StableHashingContext<'a, 'tcx>> for ty::OutlivesPredicate<A, B>
where A: HashStable<StableHashingContext<'a, 'tcx>>,
Expand Down Expand Up @@ -200,6 +201,9 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::Predicate<'tcx
ty::Predicate::Equate(ref pred) => {
pred.hash_stable(hcx, hasher);
}
ty::Predicate::Subtype(ref pred) => {
pred.hash_stable(hcx, hasher);
}
ty::Predicate::RegionOutlives(ref pred) => {
pred.hash_stable(hcx, hasher);
}
Expand Down
123 changes: 0 additions & 123 deletions src/librustc/infer/bivariate.rs

This file was deleted.

68 changes: 44 additions & 24 deletions src/librustc/infer/combine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,12 @@
// is also useful to track which value is the "expected" value in
// terms of error reporting.

use super::bivariate::Bivariate;
use super::equate::Equate;
use super::glb::Glb;
use super::lub::Lub;
use super::sub::Sub;
use super::InferCtxt;
use super::{MiscVariable, TypeTrace};
use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf};

use ty::{IntType, UintType};
use ty::{self, Ty, TyCtxt};
Expand All @@ -60,6 +58,11 @@ pub struct CombineFields<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
pub obligations: PredicateObligations<'tcx>,
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum RelationDir {
SubtypeOf, SupertypeOf, EqTo
}

impl<'infcx, 'gcx, 'tcx> InferCtxt<'infcx, 'gcx, 'tcx> {
pub fn super_combine_tys<R>(&self,
relation: &mut R,
Expand Down Expand Up @@ -159,10 +162,6 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
Equate::new(self, a_is_expected)
}

pub fn bivariate<'a>(&'a mut self, a_is_expected: bool) -> Bivariate<'a, 'infcx, 'gcx, 'tcx> {
Bivariate::new(self, a_is_expected)
}

pub fn sub<'a>(&'a mut self, a_is_expected: bool) -> Sub<'a, 'infcx, 'gcx, 'tcx> {
Sub::new(self, a_is_expected)
}
Expand All @@ -182,6 +181,8 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
a_is_expected: bool)
-> RelateResult<'tcx, ()>
{
use self::RelationDir::*;

// We use SmallVector here instead of Vec because this code is hot and
// it's rare that the stack length exceeds 1.
let mut stack = SmallVector::new();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: do we even need the stack and the loop here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, yeah, I think I meant to remove that! Thanks.

Expand Down Expand Up @@ -223,22 +224,24 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
// Check whether `vid` has been instantiated yet. If not,
// make a generalized form of `ty` and instantiate with
// that.
//
// FIXME(#18653) -- we need to generalize nested type
// variables too.
let b_ty = match b_ty {
Some(t) => t, // ...already instantiated.
None => { // ...not yet instantiated:
// Generalize type if necessary.
let generalized_ty = match dir {
EqTo => self.generalize(a_ty, b_vid, false),
BiTo | SupertypeOf | SubtypeOf => self.generalize(a_ty, b_vid, true),
SupertypeOf | SubtypeOf => self.generalize(a_ty, b_vid, true),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a FIXME(#18653) to generalize?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is not needed anymore.

}?;
debug!("instantiate(a_ty={:?}, dir={:?}, \
b_vid={:?}, generalized_ty={:?})",
a_ty, dir, b_vid,
generalized_ty);
self.infcx.type_variables
.borrow_mut()
.instantiate_and_push(
b_vid, generalized_ty, &mut stack);
.instantiate(b_vid, generalized_ty);
generalized_ty
}
};
Expand All @@ -251,7 +254,6 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
// to associate causes/spans with each of the relations in
// the stack to get this right.
match dir {
BiTo => self.bivariate(a_is_expected).relate(&a_ty, &b_ty),
EqTo => self.equate(a_is_expected).relate(&a_ty, &b_ty),
SubtypeOf => self.sub(a_is_expected).relate(&a_ty, &b_ty),
SupertypeOf => self.sub(a_is_expected).relate_with_variance(
Expand All @@ -262,20 +264,27 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
Ok(())
}

/// Attempts to generalize `ty` for the type variable `for_vid`. This checks for cycle -- that
/// is, whether the type `ty` references `for_vid`. If `make_region_vars` is true, it will also
/// replace all regions with fresh variables. Returns `TyError` in the case of a cycle, `Ok`
/// otherwise.
/// Attempts to generalize `ty` for the type variable `for_vid`.
/// This checks for cycle -- that is, whether the type `ty`
/// references `for_vid`. If `make_region_vars` is true, it will
/// also replace all regions with fresh variables. Returns
/// `TyError` in the case of a cycle, `Ok` otherwise.
///
/// Preconditions:
///
/// - `for_vid` is a "root vid"
fn generalize(&self,
ty: Ty<'tcx>,
for_vid: ty::TyVid,
make_region_vars: bool)
-> RelateResult<'tcx, Ty<'tcx>>
{
debug_assert!(self.infcx.type_variables.borrow_mut().root_var(for_vid) == for_vid);

let mut generalize = Generalizer {
infcx: self.infcx,
span: self.trace.cause.span,
for_vid: for_vid,
for_vid_sub_root: self.infcx.type_variables.borrow_mut().sub_root_var(for_vid),
make_region_vars: make_region_vars,
cycle_detected: false
};
Expand All @@ -291,7 +300,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
struct Generalizer<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
span: Span,
for_vid: ty::TyVid,
for_vid_sub_root: ty::TyVid,
make_region_vars: bool,
cycle_detected: bool,
}
Expand All @@ -303,17 +312,17 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx

fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
// Check to see whether the type we are genealizing references
// `vid`. At the same time, also update any type variables to
// the values that they are bound to. This is needed to truly
// check for cycles, but also just makes things readable.
//
// (In particular, you could have something like `$0 = Box<$1>`
// where `$1` has already been instantiated with `Box<$0>`)
// any other type variable related to `vid` via
// subtyping. This is basically our "occurs check", preventing
// us from creating infinitely sized types.
match t.sty {
ty::TyInfer(ty::TyVar(vid)) => {
let mut variables = self.infcx.type_variables.borrow_mut();
let vid = variables.root_var(vid);
if vid == self.for_vid {
let sub_vid = variables.sub_root_var(vid);
if sub_vid == self.for_vid_sub_root {
// If sub-roots are equal, then `for_vid` and
// `vid` are related via subtyping.
self.cycle_detected = true;
self.tcx().types.err
} else {
Expand All @@ -322,7 +331,18 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx
drop(variables);
self.fold_ty(u)
}
None => t,
None => {
if self.make_region_vars {
let origin = variables.origin(vid);
let new_var_id = variables.new_var(false, origin, None);
let u = self.tcx().mk_var(new_var_id);
debug!("generalize: replacing original vid={:?} with new={:?}",
vid, u);
u
} else {
t
}
}
}
}
}
Expand Down
9 changes: 4 additions & 5 deletions src/librustc/infer/equate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use super::combine::CombineFields;
use super::combine::{CombineFields, RelationDir};
use super::{Subtype};
use super::type_variable::{EqTo};

use ty::{self, Ty, TyCtxt};
use ty::TyVar;
Expand Down Expand Up @@ -58,17 +57,17 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
let b = infcx.type_variables.borrow_mut().replace_if_possible(b);
match (&a.sty, &b.sty) {
(&ty::TyInfer(TyVar(a_id)), &ty::TyInfer(TyVar(b_id))) => {
infcx.type_variables.borrow_mut().relate_vars(a_id, EqTo, b_id);
infcx.type_variables.borrow_mut().equate(a_id, b_id);
Ok(a)
}

(&ty::TyInfer(TyVar(a_id)), _) => {
self.fields.instantiate(b, EqTo, a_id, self.a_is_expected)?;
self.fields.instantiate(b, RelationDir::EqTo, a_id, self.a_is_expected)?;
Ok(a)
}

(_, &ty::TyInfer(TyVar(b_id))) => {
self.fields.instantiate(a, EqTo, b_id, self.a_is_expected)?;
self.fields.instantiate(a, RelationDir::EqTo, b_id, self.a_is_expected)?;
Ok(a)
}

Expand Down
Loading