1
Fork 0

Rollup merge of #23895 - nikomatsakis:fn-trait-inheritance-add-impls, r=pnkfelix

The primary purpose of this PR is to add blanket impls for the `Fn` traits of the following (simplified) form:

    impl<F:Fn> Fn for &F
    impl<F:FnMut> FnMut for &mut F

However, this wound up requiring two changes:

1. A slight hack so that `x()` where `x: &mut F` is translated to `FnMut::call_mut(&mut *x, ())` vs `FnMut::call_mut(&mut x, ())`. This is achieved by just autoderef'ing one time when calling something whose type is `&F` or `&mut F`.
2. Making the infinite recursion test in trait matching a bit more tailored. This involves adding a notion of "matching" types that looks to see if types are potentially unifiable (it's an approximation).

The PR also includes various small refactorings to the inference code that are aimed at moving the unification and other code into a library (I've got that particular change in a branch, these changes just lead the way there by removing unnecessary dependencies between the compiler and the more general unification code). 

Note that per rust-lang/rfcs#1023, adding impls like these would be a breaking change in the future. 

cc @japaric
cc @alexcrichton 
cc @aturon 

Fixes #23015.
This commit is contained in:
Manish Goregaokar 2015-04-02 00:40:39 +05:30
commit debac97a10
35 changed files with 1635 additions and 1278 deletions

View file

@ -1145,3 +1145,52 @@ pub trait FnOnce<Args> {
/// This is called when the call operator is used. /// This is called when the call operator is used.
extern "rust-call" fn call_once(self, args: Args) -> Self::Output; extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
} }
#[cfg(not(stage0))]
mod impls {
use marker::Sized;
use super::{Fn, FnMut, FnOnce};
impl<'a,A,F:?Sized> Fn<A> for &'a F
where F : Fn<A>
{
extern "rust-call" fn call(&self, args: A) -> F::Output {
(**self).call(args)
}
}
impl<'a,A,F:?Sized> FnMut<A> for &'a F
where F : Fn<A>
{
extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
(**self).call(args)
}
}
impl<'a,A,F:?Sized> FnOnce<A> for &'a F
where F : Fn<A>
{
type Output = F::Output;
extern "rust-call" fn call_once(self, args: A) -> F::Output {
(*self).call(args)
}
}
impl<'a,A,F:?Sized> FnMut<A> for &'a mut F
where F : FnMut<A>
{
extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
(*self).call_mut(args)
}
}
impl<'a,A,F:?Sized> FnOnce<A> for &'a mut F
where F : FnMut<A>
{
type Output = F::Output;
extern "rust-call" fn call_once(mut self, args: A) -> F::Output {
(*self).call_mut(args)
}
}
}

View file

@ -120,6 +120,8 @@ pub mod middle {
pub mod traits; pub mod traits;
pub mod ty; pub mod ty;
pub mod ty_fold; pub mod ty_fold;
pub mod ty_match;
pub mod ty_relate;
pub mod ty_walk; pub mod ty_walk;
pub mod weak_lang_items; pub mod weak_lang_items;
} }

View file

@ -25,66 +25,54 @@
//! In particular, it might be enough to say (A,B) are bivariant for //! In particular, it might be enough to say (A,B) are bivariant for
//! all (A,B). //! all (A,B).
use middle::ty::BuiltinBounds; use super::combine::{self, CombineFields};
use super::type_variable::{BiTo};
use middle::ty::{self, Ty}; use middle::ty::{self, Ty};
use middle::ty::TyVar; use middle::ty::TyVar;
use middle::infer::combine::*; use middle::ty_relate::{Relate, RelateResult, TypeRelation};
use middle::infer::cres; use util::ppaux::{Repr};
use middle::infer::type_variable::BiTo;
use util::ppaux::Repr;
pub struct Bivariate<'f, 'tcx: 'f> { pub struct Bivariate<'a, 'tcx: 'a> {
fields: CombineFields<'f, 'tcx> fields: CombineFields<'a, 'tcx>
} }
#[allow(non_snake_case)] impl<'a, 'tcx> Bivariate<'a, 'tcx> {
pub fn Bivariate<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Bivariate<'f, 'tcx> { pub fn new(fields: CombineFields<'a, 'tcx>) -> Bivariate<'a, 'tcx> {
Bivariate { fields: cf } Bivariate { fields: fields }
}
} }
impl<'f, 'tcx> Combine<'tcx> for Bivariate<'f, 'tcx> { impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Bivariate<'a, 'tcx> {
fn tag(&self) -> String { "Bivariate".to_string() } fn tag(&self) -> &'static str { "Bivariate" }
fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() }
-> cres<'tcx, Ty<'tcx>>
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
variance: ty::Variance,
a: &T,
b: &T)
-> RelateResult<'tcx, T>
{ {
match v { match variance {
ty::Invariant => self.equate().tys(a, b), // If we have Foo<A> and Foo is invariant w/r/t A,
ty::Covariant => self.tys(a, b), // and we want to assert that
ty::Contravariant => self.tys(a, b), //
ty::Bivariant => self.tys(a, b), // Foo<A> <: Foo<B> ||
// Foo<B> <: Foo<A>
//
// then still A must equal B.
ty::Invariant => self.relate(a, b),
ty::Covariant => self.relate(a, b),
ty::Bivariant => self.relate(a, b),
ty::Contravariant => self.relate(a, b),
} }
} }
fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region) fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-> cres<'tcx, ty::Region>
{
match v {
ty::Invariant => self.equate().regions(a, b),
ty::Covariant => self.regions(a, b),
ty::Contravariant => self.regions(a, b),
ty::Bivariant => self.regions(a, b),
}
}
fn regions(&self, a: ty::Region, _: ty::Region) -> cres<'tcx, ty::Region> {
Ok(a)
}
fn builtin_bounds(&self,
a: BuiltinBounds,
b: BuiltinBounds)
-> cres<'tcx, BuiltinBounds>
{
if a != b {
Err(ty::terr_builtin_bounds(expected_found(self, a, b)))
} else {
Ok(a)
}
}
fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
debug!("{}.tys({}, {})", self.tag(), debug!("{}.tys({}, {})", self.tag(),
a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx)); a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
if a == b { return Ok(a); } if a == b { return Ok(a); }
@ -109,17 +97,22 @@ impl<'f, 'tcx> Combine<'tcx> for Bivariate<'f, 'tcx> {
} }
_ => { _ => {
super_tys(self, a, b) combine::super_combine_tys(self.fields.infcx, self, a, b)
} }
} }
} }
fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>> fn regions(&mut self, a: ty::Region, _: ty::Region) -> RelateResult<'tcx, ty::Region> {
where T : Combineable<'tcx> Ok(a)
}
fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'a,'tcx>
{ {
let a1 = ty::erase_late_bound_regions(self.tcx(), a); let a1 = ty::erase_late_bound_regions(self.tcx(), a);
let b1 = ty::erase_late_bound_regions(self.tcx(), b); let b1 = ty::erase_late_bound_regions(self.tcx(), b);
let c = try!(Combineable::combine(self, &a1, &b1)); let c = try!(self.relate(&a1, &b1));
Ok(ty::Binder(c)) Ok(ty::Binder(c))
} }
} }

View file

@ -37,395 +37,21 @@ use super::equate::Equate;
use super::glb::Glb; use super::glb::Glb;
use super::lub::Lub; use super::lub::Lub;
use super::sub::Sub; use super::sub::Sub;
use super::unify::InferCtxtMethodsForSimplyUnifiableTypes; use super::{InferCtxt};
use super::{InferCtxt, cres};
use super::{MiscVariable, TypeTrace}; use super::{MiscVariable, TypeTrace};
use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf}; use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf};
use middle::subst; use middle::ty::{TyVar};
use middle::subst::{ErasedRegions, NonerasedRegions, Substs};
use middle::ty::{FloatVar, FnSig, IntVar, TyVar};
use middle::ty::{IntType, UintType}; use middle::ty::{IntType, UintType};
use middle::ty::BuiltinBounds;
use middle::ty::{self, Ty}; use middle::ty::{self, Ty};
use middle::ty_fold; use middle::ty_fold;
use middle::ty_fold::{TypeFolder, TypeFoldable}; use middle::ty_fold::{TypeFolder, TypeFoldable};
use middle::ty_relate::{self, Relate, RelateResult, TypeRelation};
use util::ppaux::Repr; use util::ppaux::Repr;
use std::rc::Rc;
use syntax::ast::Unsafety;
use syntax::ast; use syntax::ast;
use syntax::abi;
use syntax::codemap::Span; use syntax::codemap::Span;
pub trait Combine<'tcx> : Sized {
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.infcx().tcx }
fn tag(&self) -> String;
fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx>;
fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx> { self.fields().infcx }
fn a_is_expected(&self) -> bool { self.fields().a_is_expected }
fn trace(&self) -> TypeTrace<'tcx> { self.fields().trace.clone() }
fn equate<'a>(&'a self) -> Equate<'a, 'tcx> { self.fields().equate() }
fn bivariate<'a>(&'a self) -> Bivariate<'a, 'tcx> { self.fields().bivariate() }
fn sub<'a>(&'a self) -> Sub<'a, 'tcx> { self.fields().sub() }
fn lub<'a>(&'a self) -> Lub<'a, 'tcx> { Lub(self.fields().clone()) }
fn glb<'a>(&'a self) -> Glb<'a, 'tcx> { Glb(self.fields().clone()) }
fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> cres<'tcx, ty::mt<'tcx>> {
debug!("{}.mts({}, {})",
self.tag(),
a.repr(self.tcx()),
b.repr(self.tcx()));
if a.mutbl != b.mutbl {
Err(ty::terr_mutability)
} else {
let mutbl = a.mutbl;
let variance = match mutbl {
ast::MutImmutable => ty::Covariant,
ast::MutMutable => ty::Invariant,
};
let ty = try!(self.tys_with_variance(variance, a.ty, b.ty));
Ok(ty::mt {ty: ty, mutbl: mutbl})
}
}
fn tys_with_variance(&self, variance: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
-> cres<'tcx, Ty<'tcx>>;
fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>>;
fn regions_with_variance(&self, variance: ty::Variance, a: ty::Region, b: ty::Region)
-> cres<'tcx, ty::Region>;
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region>;
fn substs(&self,
item_def_id: ast::DefId,
a_subst: &subst::Substs<'tcx>,
b_subst: &subst::Substs<'tcx>)
-> cres<'tcx, subst::Substs<'tcx>>
{
debug!("substs: item_def_id={} a_subst={} b_subst={}",
item_def_id.repr(self.infcx().tcx),
a_subst.repr(self.infcx().tcx),
b_subst.repr(self.infcx().tcx));
let variances = if self.infcx().tcx.variance_computed.get() {
Some(ty::item_variances(self.infcx().tcx, item_def_id))
} else {
None
};
self.substs_variances(variances.as_ref().map(|v| &**v), a_subst, b_subst)
}
fn substs_variances(&self,
variances: Option<&ty::ItemVariances>,
a_subst: &subst::Substs<'tcx>,
b_subst: &subst::Substs<'tcx>)
-> cres<'tcx, subst::Substs<'tcx>>
{
let mut substs = subst::Substs::empty();
for &space in &subst::ParamSpace::all() {
let a_tps = a_subst.types.get_slice(space);
let b_tps = b_subst.types.get_slice(space);
let t_variances = variances.map(|v| v.types.get_slice(space));
let tps = try!(relate_type_params(self, t_variances, a_tps, b_tps));
substs.types.replace(space, tps);
}
match (&a_subst.regions, &b_subst.regions) {
(&ErasedRegions, _) | (_, &ErasedRegions) => {
substs.regions = ErasedRegions;
}
(&NonerasedRegions(ref a), &NonerasedRegions(ref b)) => {
for &space in &subst::ParamSpace::all() {
let a_regions = a.get_slice(space);
let b_regions = b.get_slice(space);
let r_variances = variances.map(|v| v.regions.get_slice(space));
let regions = try!(relate_region_params(self,
r_variances,
a_regions,
b_regions));
substs.mut_regions().replace(space, regions);
}
}
}
return Ok(substs);
fn relate_type_params<'tcx, C: Combine<'tcx>>(this: &C,
variances: Option<&[ty::Variance]>,
a_tys: &[Ty<'tcx>],
b_tys: &[Ty<'tcx>])
-> cres<'tcx, Vec<Ty<'tcx>>>
{
if a_tys.len() != b_tys.len() {
return Err(ty::terr_ty_param_size(expected_found(this,
a_tys.len(),
b_tys.len())));
}
(0.. a_tys.len()).map(|i| {
let a_ty = a_tys[i];
let b_ty = b_tys[i];
let v = variances.map_or(ty::Invariant, |v| v[i]);
this.tys_with_variance(v, a_ty, b_ty)
}).collect()
}
fn relate_region_params<'tcx, C: Combine<'tcx>>(this: &C,
variances: Option<&[ty::Variance]>,
a_rs: &[ty::Region],
b_rs: &[ty::Region])
-> cres<'tcx, Vec<ty::Region>>
{
let tcx = this.infcx().tcx;
let num_region_params = a_rs.len();
debug!("relate_region_params(\
a_rs={}, \
b_rs={},
variances={})",
a_rs.repr(tcx),
b_rs.repr(tcx),
variances.repr(tcx));
assert_eq!(num_region_params,
variances.map_or(num_region_params,
|v| v.len()));
assert_eq!(num_region_params, b_rs.len());
(0..a_rs.len()).map(|i| {
let a_r = a_rs[i];
let b_r = b_rs[i];
let variance = variances.map_or(ty::Invariant, |v| v[i]);
this.regions_with_variance(variance, a_r, b_r)
}).collect()
}
}
fn bare_fn_tys(&self, a: &ty::BareFnTy<'tcx>,
b: &ty::BareFnTy<'tcx>) -> cres<'tcx, ty::BareFnTy<'tcx>> {
let unsafety = try!(self.unsafeties(a.unsafety, b.unsafety));
let abi = try!(self.abi(a.abi, b.abi));
let sig = try!(self.binders(&a.sig, &b.sig));
Ok(ty::BareFnTy {unsafety: unsafety,
abi: abi,
sig: sig})
}
fn fn_sigs(&self, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) -> cres<'tcx, ty::FnSig<'tcx>> {
if a.variadic != b.variadic {
return Err(ty::terr_variadic_mismatch(expected_found(self, a.variadic, b.variadic)));
}
let inputs = try!(argvecs(self,
&a.inputs,
&b.inputs));
let output = try!(match (a.output, b.output) {
(ty::FnConverging(a_ty), ty::FnConverging(b_ty)) =>
Ok(ty::FnConverging(try!(self.tys(a_ty, b_ty)))),
(ty::FnDiverging, ty::FnDiverging) =>
Ok(ty::FnDiverging),
(a, b) =>
Err(ty::terr_convergence_mismatch(
expected_found(self, a != ty::FnDiverging, b != ty::FnDiverging))),
});
return Ok(ty::FnSig {inputs: inputs,
output: output,
variadic: a.variadic});
fn argvecs<'tcx, C>(combiner: &C,
a_args: &[Ty<'tcx>],
b_args: &[Ty<'tcx>])
-> cres<'tcx, Vec<Ty<'tcx>>>
where C: Combine<'tcx> {
if a_args.len() == b_args.len() {
a_args.iter().zip(b_args.iter())
.map(|(a, b)| combiner.args(*a, *b)).collect()
} else {
Err(ty::terr_arg_count)
}
}
}
fn args(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
self.tys_with_variance(ty::Contravariant, a, b).and_then(|t| Ok(t))
}
fn unsafeties(&self, a: Unsafety, b: Unsafety) -> cres<'tcx, Unsafety> {
if a != b {
Err(ty::terr_unsafety_mismatch(expected_found(self, a, b)))
} else {
Ok(a)
}
}
fn abi(&self, a: abi::Abi, b: abi::Abi) -> cres<'tcx, abi::Abi> {
if a == b {
Ok(a)
} else {
Err(ty::terr_abi_mismatch(expected_found(self, a, b)))
}
}
fn projection_tys(&self,
a: &ty::ProjectionTy<'tcx>,
b: &ty::ProjectionTy<'tcx>)
-> cres<'tcx, ty::ProjectionTy<'tcx>>
{
if a.item_name != b.item_name {
Err(ty::terr_projection_name_mismatched(
expected_found(self, a.item_name, b.item_name)))
} else {
let trait_ref = try!(self.trait_refs(&*a.trait_ref, &*b.trait_ref));
Ok(ty::ProjectionTy { trait_ref: Rc::new(trait_ref), item_name: a.item_name })
}
}
fn projection_predicates(&self,
a: &ty::ProjectionPredicate<'tcx>,
b: &ty::ProjectionPredicate<'tcx>)
-> cres<'tcx, ty::ProjectionPredicate<'tcx>>
{
let projection_ty = try!(self.projection_tys(&a.projection_ty, &b.projection_ty));
let ty = try!(self.tys(a.ty, b.ty));
Ok(ty::ProjectionPredicate { projection_ty: projection_ty, ty: ty })
}
fn projection_bounds(&self,
a: &Vec<ty::PolyProjectionPredicate<'tcx>>,
b: &Vec<ty::PolyProjectionPredicate<'tcx>>)
-> cres<'tcx, Vec<ty::PolyProjectionPredicate<'tcx>>>
{
// To be compatible, `a` and `b` must be for precisely the
// same set of traits and item names. We always require that
// projection bounds lists are sorted by trait-def-id and item-name,
// so we can just iterate through the lists pairwise, so long as they are the
// same length.
if a.len() != b.len() {
Err(ty::terr_projection_bounds_length(expected_found(self, a.len(), b.len())))
} else {
a.iter()
.zip(b.iter())
.map(|(a, b)| self.binders(a, b))
.collect()
}
}
fn existential_bounds(&self,
a: &ty::ExistentialBounds<'tcx>,
b: &ty::ExistentialBounds<'tcx>)
-> cres<'tcx, ty::ExistentialBounds<'tcx>>
{
let r = try!(self.regions_with_variance(ty::Contravariant, a.region_bound, b.region_bound));
let nb = try!(self.builtin_bounds(a.builtin_bounds, b.builtin_bounds));
let pb = try!(self.projection_bounds(&a.projection_bounds, &b.projection_bounds));
Ok(ty::ExistentialBounds { region_bound: r,
builtin_bounds: nb,
projection_bounds: pb })
}
fn builtin_bounds(&self,
a: BuiltinBounds,
b: BuiltinBounds)
-> cres<'tcx, BuiltinBounds>
{
// Two sets of builtin bounds are only relatable if they are
// precisely the same (but see the coercion code).
if a != b {
Err(ty::terr_builtin_bounds(expected_found(self, a, b)))
} else {
Ok(a)
}
}
fn trait_refs(&self,
a: &ty::TraitRef<'tcx>,
b: &ty::TraitRef<'tcx>)
-> cres<'tcx, ty::TraitRef<'tcx>>
{
// Different traits cannot be related
if a.def_id != b.def_id {
Err(ty::terr_traits(expected_found(self, a.def_id, b.def_id)))
} else {
let substs = try!(self.substs(a.def_id, a.substs, b.substs));
Ok(ty::TraitRef { def_id: a.def_id, substs: self.tcx().mk_substs(substs) })
}
}
fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>>
where T : Combineable<'tcx>;
// this must be overridden to do correctly, so as to account for higher-ranked
// behavior
}
pub trait Combineable<'tcx> : Repr<'tcx> + TypeFoldable<'tcx> {
fn combine<C:Combine<'tcx>>(combiner: &C, a: &Self, b: &Self) -> cres<'tcx, Self>;
}
impl<'tcx,T> Combineable<'tcx> for Rc<T>
where T : Combineable<'tcx>
{
fn combine<C>(combiner: &C,
a: &Rc<T>,
b: &Rc<T>)
-> cres<'tcx, Rc<T>>
where C: Combine<'tcx> {
Ok(Rc::new(try!(Combineable::combine(combiner, &**a, &**b))))
}
}
impl<'tcx> Combineable<'tcx> for ty::TraitRef<'tcx> {
fn combine<C>(combiner: &C,
a: &ty::TraitRef<'tcx>,
b: &ty::TraitRef<'tcx>)
-> cres<'tcx, ty::TraitRef<'tcx>>
where C: Combine<'tcx> {
combiner.trait_refs(a, b)
}
}
impl<'tcx> Combineable<'tcx> for Ty<'tcx> {
fn combine<C>(combiner: &C,
a: &Ty<'tcx>,
b: &Ty<'tcx>)
-> cres<'tcx, Ty<'tcx>>
where C: Combine<'tcx> {
combiner.tys(*a, *b)
}
}
impl<'tcx> Combineable<'tcx> for ty::ProjectionPredicate<'tcx> {
fn combine<C>(combiner: &C,
a: &ty::ProjectionPredicate<'tcx>,
b: &ty::ProjectionPredicate<'tcx>)
-> cres<'tcx, ty::ProjectionPredicate<'tcx>>
where C: Combine<'tcx> {
combiner.projection_predicates(a, b)
}
}
impl<'tcx> Combineable<'tcx> for ty::FnSig<'tcx> {
fn combine<C>(combiner: &C,
a: &ty::FnSig<'tcx>,
b: &ty::FnSig<'tcx>)
-> cres<'tcx, ty::FnSig<'tcx>>
where C: Combine<'tcx> {
combiner.fn_sigs(a, b)
}
}
#[derive(Clone)] #[derive(Clone)]
pub struct CombineFields<'a, 'tcx: 'a> { pub struct CombineFields<'a, 'tcx: 'a> {
pub infcx: &'a InferCtxt<'a, 'tcx>, pub infcx: &'a InferCtxt<'a, 'tcx>,
@ -433,234 +59,133 @@ pub struct CombineFields<'a, 'tcx: 'a> {
pub trace: TypeTrace<'tcx>, pub trace: TypeTrace<'tcx>,
} }
pub fn expected_found<'tcx, C, T>(this: &C, pub fn super_combine_tys<'a,'tcx:'a,R>(infcx: &InferCtxt<'a, 'tcx>,
a: T, relation: &mut R,
b: T)
-> ty::expected_found<T>
where C: Combine<'tcx> {
if this.a_is_expected() {
ty::expected_found {expected: a, found: b}
} else {
ty::expected_found {expected: b, found: a}
}
}
pub fn super_tys<'tcx, C>(this: &C,
a: Ty<'tcx>, a: Ty<'tcx>,
b: Ty<'tcx>) b: Ty<'tcx>)
-> cres<'tcx, Ty<'tcx>> -> RelateResult<'tcx, Ty<'tcx>>
where C: Combine<'tcx> { where R: TypeRelation<'a,'tcx>
let tcx = this.infcx().tcx; {
let a_sty = &a.sty; let a_is_expected = relation.a_is_expected();
let b_sty = &b.sty;
debug!("super_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty);
return match (a_sty, b_sty) {
// The "subtype" ought to be handling cases involving var:
(&ty::ty_infer(TyVar(_)), _)
| (_, &ty::ty_infer(TyVar(_))) =>
tcx.sess.bug(
&format!("{}: bot and var types should have been handled ({},{})",
this.tag(),
a.repr(this.infcx().tcx),
b.repr(this.infcx().tcx))),
(&ty::ty_err, _) | (_, &ty::ty_err) => Ok(tcx.types.err),
match (&a.sty, &b.sty) {
// Relate integral variables to other types // Relate integral variables to other types
(&ty::ty_infer(IntVar(a_id)), &ty::ty_infer(IntVar(b_id))) => { (&ty::ty_infer(ty::IntVar(a_id)), &ty::ty_infer(ty::IntVar(b_id))) => {
try!(this.infcx().simple_vars(this.a_is_expected(), try!(infcx.int_unification_table
a_id, b_id)); .borrow_mut()
.unify_var_var(a_id, b_id)
.map_err(|e| int_unification_error(a_is_expected, e)));
Ok(a) Ok(a)
} }
(&ty::ty_infer(IntVar(v_id)), &ty::ty_int(v)) => { (&ty::ty_infer(ty::IntVar(v_id)), &ty::ty_int(v)) => {
unify_integral_variable(this, this.a_is_expected(), unify_integral_variable(infcx, a_is_expected, v_id, IntType(v))
v_id, IntType(v))
} }
(&ty::ty_int(v), &ty::ty_infer(IntVar(v_id))) => { (&ty::ty_int(v), &ty::ty_infer(ty::IntVar(v_id))) => {
unify_integral_variable(this, !this.a_is_expected(), unify_integral_variable(infcx, !a_is_expected, v_id, IntType(v))
v_id, IntType(v))
} }
(&ty::ty_infer(IntVar(v_id)), &ty::ty_uint(v)) => { (&ty::ty_infer(ty::IntVar(v_id)), &ty::ty_uint(v)) => {
unify_integral_variable(this, this.a_is_expected(), unify_integral_variable(infcx, a_is_expected, v_id, UintType(v))
v_id, UintType(v))
} }
(&ty::ty_uint(v), &ty::ty_infer(IntVar(v_id))) => { (&ty::ty_uint(v), &ty::ty_infer(ty::IntVar(v_id))) => {
unify_integral_variable(this, !this.a_is_expected(), unify_integral_variable(infcx, !a_is_expected, v_id, UintType(v))
v_id, UintType(v))
} }
// Relate floating-point variables to other types // Relate floating-point variables to other types
(&ty::ty_infer(FloatVar(a_id)), &ty::ty_infer(FloatVar(b_id))) => { (&ty::ty_infer(ty::FloatVar(a_id)), &ty::ty_infer(ty::FloatVar(b_id))) => {
try!(this.infcx().simple_vars(this.a_is_expected(), a_id, b_id)); try!(infcx.float_unification_table
.borrow_mut()
.unify_var_var(a_id, b_id)
.map_err(|e| float_unification_error(relation.a_is_expected(), e)));
Ok(a) Ok(a)
} }
(&ty::ty_infer(FloatVar(v_id)), &ty::ty_float(v)) => { (&ty::ty_infer(ty::FloatVar(v_id)), &ty::ty_float(v)) => {
unify_float_variable(this, this.a_is_expected(), v_id, v) unify_float_variable(infcx, a_is_expected, v_id, v)
} }
(&ty::ty_float(v), &ty::ty_infer(FloatVar(v_id))) => { (&ty::ty_float(v), &ty::ty_infer(ty::FloatVar(v_id))) => {
unify_float_variable(this, !this.a_is_expected(), v_id, v) unify_float_variable(infcx, !a_is_expected, v_id, v)
} }
(&ty::ty_char, _) // All other cases of inference are errors
| (&ty::ty_bool, _) (&ty::ty_infer(_), _) |
| (&ty::ty_int(_), _) (_, &ty::ty_infer(_)) => {
| (&ty::ty_uint(_), _) Err(ty::terr_sorts(ty_relate::expected_found(relation, &a, &b)))
| (&ty::ty_float(_), _) => { }
if a == b {
Ok(a)
} else { _ => {
Err(ty::terr_sorts(expected_found(this, a, b))) ty_relate::super_relate_tys(relation, a, b)
}
} }
} }
(&ty::ty_param(ref a_p), &ty::ty_param(ref b_p)) if fn unify_integral_variable<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
a_p.idx == b_p.idx && a_p.space == b_p.space => Ok(a),
(&ty::ty_enum(a_id, a_substs), &ty::ty_enum(b_id, b_substs))
if a_id == b_id => {
let substs = try!(this.substs(a_id, a_substs, b_substs));
Ok(ty::mk_enum(tcx, a_id, tcx.mk_substs(substs)))
}
(&ty::ty_trait(ref a_), &ty::ty_trait(ref b_)) => {
debug!("Trying to match traits {:?} and {:?}", a, b);
let principal = try!(this.binders(&a_.principal, &b_.principal));
let bounds = try!(this.existential_bounds(&a_.bounds, &b_.bounds));
Ok(ty::mk_trait(tcx, principal, bounds))
}
(&ty::ty_struct(a_id, a_substs), &ty::ty_struct(b_id, b_substs))
if a_id == b_id => {
let substs = try!(this.substs(a_id, a_substs, b_substs));
Ok(ty::mk_struct(tcx, a_id, tcx.mk_substs(substs)))
}
(&ty::ty_closure(a_id, a_substs),
&ty::ty_closure(b_id, b_substs))
if a_id == b_id => {
// All ty_closure types with the same id represent
// the (anonymous) type of the same closure expression. So
// all of their regions should be equated.
let substs = try!(this.substs_variances(None, a_substs, b_substs));
Ok(ty::mk_closure(tcx, a_id, tcx.mk_substs(substs)))
}
(&ty::ty_uniq(a_inner), &ty::ty_uniq(b_inner)) => {
let typ = try!(this.tys(a_inner, b_inner));
Ok(ty::mk_uniq(tcx, typ))
}
(&ty::ty_ptr(ref a_mt), &ty::ty_ptr(ref b_mt)) => {
let mt = try!(this.mts(a_mt, b_mt));
Ok(ty::mk_ptr(tcx, mt))
}
(&ty::ty_rptr(a_r, ref a_mt), &ty::ty_rptr(b_r, ref b_mt)) => {
let r = try!(this.regions_with_variance(ty::Contravariant, *a_r, *b_r));
let mt = try!(this.mts(a_mt, b_mt));
Ok(ty::mk_rptr(tcx, tcx.mk_region(r), mt))
}
(&ty::ty_vec(a_t, Some(sz_a)), &ty::ty_vec(b_t, Some(sz_b))) => {
this.tys(a_t, b_t).and_then(|t| {
if sz_a == sz_b {
Ok(ty::mk_vec(tcx, t, Some(sz_a)))
} else {
Err(ty::terr_fixed_array_size(expected_found(this, sz_a, sz_b)))
}
})
}
(&ty::ty_vec(a_t, sz_a), &ty::ty_vec(b_t, sz_b)) => {
this.tys(a_t, b_t).and_then(|t| {
if sz_a == sz_b {
Ok(ty::mk_vec(tcx, t, sz_a))
} else {
Err(ty::terr_sorts(expected_found(this, a, b)))
}
})
}
(&ty::ty_str, &ty::ty_str) => Ok(ty::mk_str(tcx)),
(&ty::ty_tup(ref as_), &ty::ty_tup(ref bs)) => {
if as_.len() == bs.len() {
as_.iter().zip(bs.iter())
.map(|(a, b)| this.tys(*a, *b))
.collect::<Result<_, _>>()
.map(|ts| ty::mk_tup(tcx, ts))
} else if as_.len() != 0 && bs.len() != 0 {
Err(ty::terr_tuple_size(
expected_found(this, as_.len(), bs.len())))
} else {
Err(ty::terr_sorts(expected_found(this, a, b)))
}
}
(&ty::ty_bare_fn(a_opt_def_id, a_fty), &ty::ty_bare_fn(b_opt_def_id, b_fty))
if a_opt_def_id == b_opt_def_id =>
{
let fty = try!(this.bare_fn_tys(a_fty, b_fty));
Ok(ty::mk_bare_fn(tcx, a_opt_def_id, tcx.mk_bare_fn(fty)))
}
(&ty::ty_projection(ref a_data), &ty::ty_projection(ref b_data)) => {
let projection_ty = try!(this.projection_tys(a_data, b_data));
Ok(ty::mk_projection(tcx, projection_ty.trait_ref, projection_ty.item_name))
}
_ => Err(ty::terr_sorts(expected_found(this, a, b))),
};
fn unify_integral_variable<'tcx, C>(this: &C,
vid_is_expected: bool, vid_is_expected: bool,
vid: ty::IntVid, vid: ty::IntVid,
val: ty::IntVarValue) val: ty::IntVarValue)
-> cres<'tcx, Ty<'tcx>> -> RelateResult<'tcx, Ty<'tcx>>
where C: Combine<'tcx> { {
try!(this.infcx().simple_var_t(vid_is_expected, vid, val)); try!(infcx
.int_unification_table
.borrow_mut()
.unify_var_value(vid, val)
.map_err(|e| int_unification_error(vid_is_expected, e)));
match val { match val {
IntType(v) => Ok(ty::mk_mach_int(this.tcx(), v)), IntType(v) => Ok(ty::mk_mach_int(infcx.tcx, v)),
UintType(v) => Ok(ty::mk_mach_uint(this.tcx(), v)), UintType(v) => Ok(ty::mk_mach_uint(infcx.tcx, v)),
} }
} }
fn unify_float_variable<'tcx, C>(this: &C, fn unify_float_variable<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
vid_is_expected: bool, vid_is_expected: bool,
vid: ty::FloatVid, vid: ty::FloatVid,
val: ast::FloatTy) val: ast::FloatTy)
-> cres<'tcx, Ty<'tcx>> -> RelateResult<'tcx, Ty<'tcx>>
where C: Combine<'tcx> { {
try!(this.infcx().simple_var_t(vid_is_expected, vid, val)); try!(infcx
Ok(ty::mk_mach_float(this.tcx(), val)) .float_unification_table
} .borrow_mut()
.unify_var_value(vid, val)
.map_err(|e| float_unification_error(vid_is_expected, e)));
Ok(ty::mk_mach_float(infcx.tcx, val))
} }
impl<'f, 'tcx> CombineFields<'f, 'tcx> { impl<'a, 'tcx> CombineFields<'a, 'tcx> {
pub fn switch_expected(&self) -> CombineFields<'f, 'tcx> { pub fn tcx(&self) -> &'a ty::ctxt<'tcx> {
self.infcx.tcx
}
pub fn switch_expected(&self) -> CombineFields<'a, 'tcx> {
CombineFields { CombineFields {
a_is_expected: !self.a_is_expected, a_is_expected: !self.a_is_expected,
..(*self).clone() ..(*self).clone()
} }
} }
fn equate(&self) -> Equate<'f, 'tcx> { pub fn equate(&self) -> Equate<'a, 'tcx> {
Equate((*self).clone()) Equate::new(self.clone())
} }
fn bivariate(&self) -> Bivariate<'f, 'tcx> { pub fn bivariate(&self) -> Bivariate<'a, 'tcx> {
Bivariate((*self).clone()) Bivariate::new(self.clone())
} }
fn sub(&self) -> Sub<'f, 'tcx> { pub fn sub(&self) -> Sub<'a, 'tcx> {
Sub((*self).clone()) Sub::new(self.clone())
}
pub fn lub(&self) -> Lub<'a, 'tcx> {
Lub::new(self.clone())
}
pub fn glb(&self) -> Glb<'a, 'tcx> {
Glb::new(self.clone())
} }
pub fn instantiate(&self, pub fn instantiate(&self,
a_ty: Ty<'tcx>, a_ty: Ty<'tcx>,
dir: RelationDir, dir: RelationDir,
b_vid: ty::TyVid) b_vid: ty::TyVid)
-> cres<'tcx, ()> -> RelateResult<'tcx, ()>
{ {
let tcx = self.infcx.tcx; let tcx = self.infcx.tcx;
let mut stack = Vec::new(); let mut stack = Vec::new();
@ -724,15 +249,12 @@ impl<'f, 'tcx> CombineFields<'f, 'tcx> {
// relations wind up attributed to the same spans. We need // relations wind up attributed to the same spans. We need
// to associate causes/spans with each of the relations in // to associate causes/spans with each of the relations in
// the stack to get this right. // the stack to get this right.
match dir { try!(match dir {
BiTo => try!(self.bivariate().tys(a_ty, b_ty)), BiTo => self.bivariate().relate(&a_ty, &b_ty),
EqTo => self.equate().relate(&a_ty, &b_ty),
EqTo => try!(self.equate().tys(a_ty, b_ty)), SubtypeOf => self.sub().relate(&a_ty, &b_ty),
SupertypeOf => self.sub().relate_with_variance(ty::Contravariant, &a_ty, &b_ty),
SubtypeOf => try!(self.sub().tys(a_ty, b_ty)), });
SupertypeOf => try!(self.sub().tys_with_variance(ty::Contravariant, a_ty, b_ty)),
};
} }
Ok(()) Ok(())
@ -746,7 +268,7 @@ impl<'f, 'tcx> CombineFields<'f, 'tcx> {
ty: Ty<'tcx>, ty: Ty<'tcx>,
for_vid: ty::TyVid, for_vid: ty::TyVid,
make_region_vars: bool) make_region_vars: bool)
-> cres<'tcx, Ty<'tcx>> -> RelateResult<'tcx, Ty<'tcx>>
{ {
let mut generalize = Generalizer { let mut generalize = Generalizer {
infcx: self.infcx, infcx: self.infcx,
@ -839,3 +361,37 @@ impl<'cx, 'tcx> ty_fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> {
self.infcx.next_region_var(MiscVariable(self.span)) self.infcx.next_region_var(MiscVariable(self.span))
} }
} }
pub trait RelateResultCompare<'tcx, T> {
fn compare<F>(&self, t: T, f: F) -> RelateResult<'tcx, T> where
F: FnOnce() -> ty::type_err<'tcx>;
}
impl<'tcx, T:Clone + PartialEq> RelateResultCompare<'tcx, T> for RelateResult<'tcx, T> {
fn compare<F>(&self, t: T, f: F) -> RelateResult<'tcx, T> where
F: FnOnce() -> ty::type_err<'tcx>,
{
self.clone().and_then(|s| {
if s == t {
self.clone()
} else {
Err(f())
}
})
}
}
fn int_unification_error<'tcx>(a_is_expected: bool, v: (ty::IntVarValue, ty::IntVarValue))
-> ty::type_err<'tcx>
{
let (a, b) = v;
ty::terr_int_mismatch(ty_relate::expected_found_bool(a_is_expected, &a, &b))
}
fn float_unification_error<'tcx>(a_is_expected: bool,
v: (ast::FloatTy, ast::FloatTy))
-> ty::type_err<'tcx>
{
let (a, b) = v;
ty::terr_float_mismatch(ty_relate::expected_found_bool(a_is_expected, &a, &b))
}

View file

@ -8,51 +8,43 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use super::combine::{self, CombineFields};
use super::higher_ranked::HigherRankedRelations;
use super::{Subtype};
use super::type_variable::{EqTo};
use middle::ty::{self, Ty}; use middle::ty::{self, Ty};
use middle::ty::TyVar; use middle::ty::TyVar;
use middle::infer::combine::*; use middle::ty_relate::{Relate, RelateResult, TypeRelation};
use middle::infer::cres; use util::ppaux::{Repr};
use middle::infer::Subtype;
use middle::infer::type_variable::EqTo;
use util::ppaux::Repr;
pub struct Equate<'f, 'tcx: 'f> { pub struct Equate<'a, 'tcx: 'a> {
fields: CombineFields<'f, 'tcx> fields: CombineFields<'a, 'tcx>
} }
#[allow(non_snake_case)] impl<'a, 'tcx> Equate<'a, 'tcx> {
pub fn Equate<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Equate<'f, 'tcx> { pub fn new(fields: CombineFields<'a, 'tcx>) -> Equate<'a, 'tcx> {
Equate { fields: cf } Equate { fields: fields }
}
} }
impl<'f, 'tcx> Combine<'tcx> for Equate<'f, 'tcx> { impl<'a, 'tcx> TypeRelation<'a,'tcx> for Equate<'a, 'tcx> {
fn tag(&self) -> String { "Equate".to_string() } fn tag(&self) -> &'static str { "Equate" }
fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
fn tys_with_variance(&self, _: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() }
-> cres<'tcx, Ty<'tcx>>
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
_: ty::Variance,
a: &T,
b: &T)
-> RelateResult<'tcx, T>
{ {
// Once we're equating, it doesn't matter what the variance is. self.relate(a, b)
self.tys(a, b)
} }
fn regions_with_variance(&self, _: ty::Variance, a: ty::Region, b: ty::Region) fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-> cres<'tcx, ty::Region>
{
// Once we're equating, it doesn't matter what the variance is.
self.regions(a, b)
}
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
debug!("{}.regions({}, {})",
self.tag(),
a.repr(self.fields.infcx.tcx),
b.repr(self.fields.infcx.tcx));
self.infcx().region_vars.make_eqregion(Subtype(self.trace()), a, b);
Ok(a)
}
fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
debug!("{}.tys({}, {})", self.tag(), debug!("{}.tys({}, {})", self.tag(),
a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx)); a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
if a == b { return Ok(a); } if a == b { return Ok(a); }
@ -77,15 +69,26 @@ impl<'f, 'tcx> Combine<'tcx> for Equate<'f, 'tcx> {
} }
_ => { _ => {
super_tys(self, a, b) combine::super_combine_tys(self.fields.infcx, self, a, b)
} }
} }
} }
fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>> fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
where T : Combineable<'tcx> debug!("{}.regions({}, {})",
self.tag(),
a.repr(self.fields.infcx.tcx),
b.repr(self.fields.infcx.tcx));
let origin = Subtype(self.fields.trace.clone());
self.fields.infcx.region_vars.make_eqregion(origin, a, b);
Ok(a)
}
fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'a, 'tcx>
{ {
try!(self.sub().binders(a, b)); try!(self.fields.higher_ranked_sub(a, b));
self.sub().binders(b, a) self.fields.higher_ranked_sub(b, a)
} }
} }

View file

@ -37,7 +37,7 @@ use middle::ty_fold::TypeFolder;
use std::collections::hash_map::{self, Entry}; use std::collections::hash_map::{self, Entry};
use super::InferCtxt; use super::InferCtxt;
use super::unify::InferCtxtMethodsForSimplyUnifiableTypes; use super::unify::ToType;
pub struct TypeFreshener<'a, 'tcx:'a> { pub struct TypeFreshener<'a, 'tcx:'a> {
infcx: &'a InferCtxt<'a, 'tcx>, infcx: &'a InferCtxt<'a, 'tcx>,
@ -104,21 +104,30 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
} }
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
let tcx = self.infcx.tcx;
match t.sty { match t.sty {
ty::ty_infer(ty::TyVar(v)) => { ty::ty_infer(ty::TyVar(v)) => {
self.freshen(self.infcx.type_variables.borrow().probe(v), self.freshen(
self.infcx.type_variables.borrow().probe(v),
ty::TyVar(v), ty::TyVar(v),
ty::FreshTy) ty::FreshTy)
} }
ty::ty_infer(ty::IntVar(v)) => { ty::ty_infer(ty::IntVar(v)) => {
self.freshen(self.infcx.probe_var(v), self.freshen(
self.infcx.int_unification_table.borrow_mut()
.probe(v)
.map(|v| v.to_type(tcx)),
ty::IntVar(v), ty::IntVar(v),
ty::FreshIntTy) ty::FreshIntTy)
} }
ty::ty_infer(ty::FloatVar(v)) => { ty::ty_infer(ty::FloatVar(v)) => {
self.freshen(self.infcx.probe_var(v), self.freshen(
self.infcx.float_unification_table.borrow_mut()
.probe(v)
.map(|v| v.to_type(tcx)),
ty::FloatVar(v), ty::FloatVar(v),
ty::FreshIntTy) ty::FreshIntTy)
} }
@ -126,7 +135,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
ty::ty_infer(ty::FreshTy(c)) | ty::ty_infer(ty::FreshTy(c)) |
ty::ty_infer(ty::FreshIntTy(c)) => { ty::ty_infer(ty::FreshIntTy(c)) => {
if c >= self.freshen_count { if c >= self.freshen_count {
self.tcx().sess.bug( tcx.sess.bug(
&format!("Encountered a freshend type with id {} \ &format!("Encountered a freshend type with id {} \
but our counter is only at {}", but our counter is only at {}",
c, c,

View file

@ -8,67 +8,79 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use super::combine::*; use super::combine::CombineFields;
use super::lattice::*;
use super::higher_ranked::HigherRankedRelations; use super::higher_ranked::HigherRankedRelations;
use super::cres; use super::InferCtxt;
use super::lattice::{self, LatticeDir};
use super::Subtype; use super::Subtype;
use middle::ty::{self, Ty}; use middle::ty::{self, Ty};
use middle::ty_relate::{Relate, RelateResult, TypeRelation};
use util::ppaux::Repr; use util::ppaux::Repr;
/// "Greatest lower bound" (common subtype) /// "Greatest lower bound" (common subtype)
pub struct Glb<'f, 'tcx: 'f> { pub struct Glb<'a, 'tcx: 'a> {
fields: CombineFields<'f, 'tcx> fields: CombineFields<'a, 'tcx>
} }
#[allow(non_snake_case)] impl<'a, 'tcx> Glb<'a, 'tcx> {
pub fn Glb<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Glb<'f, 'tcx> { pub fn new(fields: CombineFields<'a, 'tcx>) -> Glb<'a, 'tcx> {
Glb { fields: cf } Glb { fields: fields }
}
} }
impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> { impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Glb<'a, 'tcx> {
fn tag(&self) -> String { "Glb".to_string() } fn tag(&self) -> &'static str { "Glb" }
fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() }
-> cres<'tcx, Ty<'tcx>>
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
variance: ty::Variance,
a: &T,
b: &T)
-> RelateResult<'tcx, T>
{ {
match v { match variance {
ty::Invariant => self.equate().tys(a, b), ty::Invariant => self.fields.equate().relate(a, b),
ty::Covariant => self.tys(a, b), ty::Covariant => self.relate(a, b),
ty::Bivariant => self.bivariate().tys(a, b), ty::Bivariant => self.fields.bivariate().relate(a, b),
ty::Contravariant => self.lub().tys(a, b), ty::Contravariant => self.fields.lub().relate(a, b),
} }
} }
fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region) fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-> cres<'tcx, ty::Region> lattice::super_lattice_tys(self, a, b)
{
match v {
ty::Invariant => self.equate().regions(a, b),
ty::Covariant => self.regions(a, b),
ty::Bivariant => self.bivariate().regions(a, b),
ty::Contravariant => self.lub().regions(a, b),
}
} }
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> { fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
debug!("{}.regions({}, {})", debug!("{}.regions({}, {})",
self.tag(), self.tag(),
a.repr(self.fields.infcx.tcx), a.repr(self.fields.infcx.tcx),
b.repr(self.fields.infcx.tcx)); b.repr(self.fields.infcx.tcx));
Ok(self.fields.infcx.region_vars.glb_regions(Subtype(self.trace()), a, b)) let origin = Subtype(self.fields.trace.clone());
Ok(self.fields.infcx.region_vars.glb_regions(origin, a, b))
} }
fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
super_lattice_tys(self, a, b) -> RelateResult<'tcx, ty::Binder<T>>
} where T: Relate<'a, 'tcx>
fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>>
where T : Combineable<'tcx>
{ {
self.higher_ranked_glb(a, b) self.fields.higher_ranked_glb(a, b)
}
}
impl<'a, 'tcx> LatticeDir<'a,'tcx> for Glb<'a, 'tcx> {
fn infcx(&self) -> &'a InferCtxt<'a,'tcx> {
self.fields.infcx
}
fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
let mut sub = self.fields.sub();
try!(sub.relate(&v, &a));
try!(sub.relate(&v, &b));
Ok(())
} }
} }

View file

@ -11,25 +11,26 @@
//! Helper routines for higher-ranked things. See the `doc` module at //! Helper routines for higher-ranked things. See the `doc` module at
//! the end of the file for details. //! the end of the file for details.
use super::{CombinedSnapshot, cres, InferCtxt, HigherRankedType, SkolemizationMap}; use super::{CombinedSnapshot, InferCtxt, HigherRankedType, SkolemizationMap};
use super::combine::{Combine, Combineable}; use super::combine::CombineFields;
use middle::subst; use middle::subst;
use middle::ty::{self, Binder}; use middle::ty::{self, Binder};
use middle::ty_fold::{self, TypeFoldable}; use middle::ty_fold::{self, TypeFoldable};
use middle::ty_relate::{Relate, RelateResult, TypeRelation};
use syntax::codemap::Span; use syntax::codemap::Span;
use util::nodemap::{FnvHashMap, FnvHashSet}; use util::nodemap::{FnvHashMap, FnvHashSet};
use util::ppaux::Repr; use util::ppaux::Repr;
pub trait HigherRankedRelations<'tcx> { pub trait HigherRankedRelations<'a,'tcx> {
fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binder<T>> fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> RelateResult<'tcx, Binder<T>>
where T : Combineable<'tcx>; where T: Relate<'a,'tcx>;
fn higher_ranked_lub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binder<T>> fn higher_ranked_lub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> RelateResult<'tcx, Binder<T>>
where T : Combineable<'tcx>; where T: Relate<'a,'tcx>;
fn higher_ranked_glb<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binder<T>> fn higher_ranked_glb<T>(&self, a: &Binder<T>, b: &Binder<T>) -> RelateResult<'tcx, Binder<T>>
where T : Combineable<'tcx>; where T: Relate<'a,'tcx>;
} }
trait InferCtxtExt { trait InferCtxtExt {
@ -40,15 +41,15 @@ trait InferCtxtExt {
-> Vec<ty::RegionVid>; -> Vec<ty::RegionVid>;
} }
impl<'tcx,C> HigherRankedRelations<'tcx> for C impl<'a,'tcx> HigherRankedRelations<'a,'tcx> for CombineFields<'a,'tcx> {
where C : Combine<'tcx>
{
fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>) fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>)
-> cres<'tcx, Binder<T>> -> RelateResult<'tcx, Binder<T>>
where T : Combineable<'tcx> where T: Relate<'a,'tcx>
{ {
let tcx = self.infcx.tcx;
debug!("higher_ranked_sub(a={}, b={})", debug!("higher_ranked_sub(a={}, b={})",
a.repr(self.tcx()), b.repr(self.tcx())); a.repr(tcx), b.repr(tcx));
// Rather than checking the subtype relationship between `a` and `b` // Rather than checking the subtype relationship between `a` and `b`
// as-is, we need to do some extra work here in order to make sure // as-is, we need to do some extra work here in order to make sure
@ -60,32 +61,32 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C
// Start a snapshot so we can examine "all bindings that were // Start a snapshot so we can examine "all bindings that were
// created as part of this type comparison". // created as part of this type comparison".
return self.infcx().try(|snapshot| { return self.infcx.commit_if_ok(|snapshot| {
// First, we instantiate each bound region in the subtype with a fresh // First, we instantiate each bound region in the subtype with a fresh
// region variable. // region variable.
let (a_prime, _) = let (a_prime, _) =
self.infcx().replace_late_bound_regions_with_fresh_var( self.infcx.replace_late_bound_regions_with_fresh_var(
self.trace().origin.span(), self.trace.origin.span(),
HigherRankedType, HigherRankedType,
a); a);
// Second, we instantiate each bound region in the supertype with a // Second, we instantiate each bound region in the supertype with a
// fresh concrete region. // fresh concrete region.
let (b_prime, skol_map) = let (b_prime, skol_map) =
self.infcx().skolemize_late_bound_regions(b, snapshot); self.infcx.skolemize_late_bound_regions(b, snapshot);
debug!("a_prime={}", a_prime.repr(self.tcx())); debug!("a_prime={}", a_prime.repr(tcx));
debug!("b_prime={}", b_prime.repr(self.tcx())); debug!("b_prime={}", b_prime.repr(tcx));
// Compare types now that bound regions have been replaced. // Compare types now that bound regions have been replaced.
let result = try!(Combineable::combine(self, &a_prime, &b_prime)); let result = try!(self.sub().relate(&a_prime, &b_prime));
// Presuming type comparison succeeds, we need to check // Presuming type comparison succeeds, we need to check
// that the skolemized regions do not "leak". // that the skolemized regions do not "leak".
match leak_check(self.infcx(), &skol_map, snapshot) { match leak_check(self.infcx, &skol_map, snapshot) {
Ok(()) => { } Ok(()) => { }
Err((skol_br, tainted_region)) => { Err((skol_br, tainted_region)) => {
if self.a_is_expected() { if self.a_is_expected {
debug!("Not as polymorphic!"); debug!("Not as polymorphic!");
return Err(ty::terr_regions_insufficiently_polymorphic(skol_br, return Err(ty::terr_regions_insufficiently_polymorphic(skol_br,
tainted_region)); tainted_region));
@ -98,42 +99,42 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C
} }
debug!("higher_ranked_sub: OK result={}", debug!("higher_ranked_sub: OK result={}",
result.repr(self.tcx())); result.repr(tcx));
Ok(ty::Binder(result)) Ok(ty::Binder(result))
}); });
} }
fn higher_ranked_lub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binder<T>> fn higher_ranked_lub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> RelateResult<'tcx, Binder<T>>
where T : Combineable<'tcx> where T: Relate<'a,'tcx>
{ {
// Start a snapshot so we can examine "all bindings that were // Start a snapshot so we can examine "all bindings that were
// created as part of this type comparison". // created as part of this type comparison".
return self.infcx().try(|snapshot| { return self.infcx.commit_if_ok(|snapshot| {
// Instantiate each bound region with a fresh region variable. // Instantiate each bound region with a fresh region variable.
let span = self.trace().origin.span(); let span = self.trace.origin.span();
let (a_with_fresh, a_map) = let (a_with_fresh, a_map) =
self.infcx().replace_late_bound_regions_with_fresh_var( self.infcx.replace_late_bound_regions_with_fresh_var(
span, HigherRankedType, a); span, HigherRankedType, a);
let (b_with_fresh, _) = let (b_with_fresh, _) =
self.infcx().replace_late_bound_regions_with_fresh_var( self.infcx.replace_late_bound_regions_with_fresh_var(
span, HigherRankedType, b); span, HigherRankedType, b);
// Collect constraints. // Collect constraints.
let result0 = let result0 =
try!(Combineable::combine(self, &a_with_fresh, &b_with_fresh)); try!(self.lub().relate(&a_with_fresh, &b_with_fresh));
let result0 = let result0 =
self.infcx().resolve_type_vars_if_possible(&result0); self.infcx.resolve_type_vars_if_possible(&result0);
debug!("lub result0 = {}", result0.repr(self.tcx())); debug!("lub result0 = {}", result0.repr(self.tcx()));
// Generalize the regions appearing in result0 if possible // Generalize the regions appearing in result0 if possible
let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot); let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
let span = self.trace().origin.span(); let span = self.trace.origin.span();
let result1 = let result1 =
fold_regions_in( fold_regions_in(
self.tcx(), self.tcx(),
&result0, &result0,
|r, debruijn| generalize_region(self.infcx(), span, snapshot, debruijn, |r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn,
&new_vars, &a_map, r)); &new_vars, &a_map, r));
debug!("lub({},{}) = {}", debug!("lub({},{}) = {}",
@ -194,40 +195,40 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C
} }
} }
fn higher_ranked_glb<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binder<T>> fn higher_ranked_glb<T>(&self, a: &Binder<T>, b: &Binder<T>) -> RelateResult<'tcx, Binder<T>>
where T : Combineable<'tcx> where T: Relate<'a,'tcx>
{ {
debug!("{}.higher_ranked_glb({}, {})", debug!("higher_ranked_glb({}, {})",
self.tag(), a.repr(self.tcx()), b.repr(self.tcx())); a.repr(self.tcx()), b.repr(self.tcx()));
// Make a snapshot so we can examine "all bindings that were // Make a snapshot so we can examine "all bindings that were
// created as part of this type comparison". // created as part of this type comparison".
return self.infcx().try(|snapshot| { return self.infcx.commit_if_ok(|snapshot| {
// Instantiate each bound region with a fresh region variable. // Instantiate each bound region with a fresh region variable.
let (a_with_fresh, a_map) = let (a_with_fresh, a_map) =
self.infcx().replace_late_bound_regions_with_fresh_var( self.infcx.replace_late_bound_regions_with_fresh_var(
self.trace().origin.span(), HigherRankedType, a); self.trace.origin.span(), HigherRankedType, a);
let (b_with_fresh, b_map) = let (b_with_fresh, b_map) =
self.infcx().replace_late_bound_regions_with_fresh_var( self.infcx.replace_late_bound_regions_with_fresh_var(
self.trace().origin.span(), HigherRankedType, b); self.trace.origin.span(), HigherRankedType, b);
let a_vars = var_ids(self, &a_map); let a_vars = var_ids(self, &a_map);
let b_vars = var_ids(self, &b_map); let b_vars = var_ids(self, &b_map);
// Collect constraints. // Collect constraints.
let result0 = let result0 =
try!(Combineable::combine(self, &a_with_fresh, &b_with_fresh)); try!(self.glb().relate(&a_with_fresh, &b_with_fresh));
let result0 = let result0 =
self.infcx().resolve_type_vars_if_possible(&result0); self.infcx.resolve_type_vars_if_possible(&result0);
debug!("glb result0 = {}", result0.repr(self.tcx())); debug!("glb result0 = {}", result0.repr(self.tcx()));
// Generalize the regions appearing in result0 if possible // Generalize the regions appearing in result0 if possible
let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot); let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
let span = self.trace().origin.span(); let span = self.trace.origin.span();
let result1 = let result1 =
fold_regions_in( fold_regions_in(
self.tcx(), self.tcx(),
&result0, &result0,
|r, debruijn| generalize_region(self.infcx(), span, snapshot, debruijn, |r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn,
&new_vars, &new_vars,
&a_map, &a_vars, &b_vars, &a_map, &a_vars, &b_vars,
r)); r));
@ -332,17 +333,19 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C
} }
} }
fn var_ids<'tcx, T: Combine<'tcx>>(combiner: &T, fn var_ids<'a, 'tcx>(fields: &CombineFields<'a, 'tcx>,
map: &FnvHashMap<ty::BoundRegion, ty::Region>) map: &FnvHashMap<ty::BoundRegion, ty::Region>)
-> Vec<ty::RegionVid> { -> Vec<ty::RegionVid> {
map.iter().map(|(_, r)| match *r { map.iter()
.map(|(_, r)| match *r {
ty::ReInfer(ty::ReVar(r)) => { r } ty::ReInfer(ty::ReVar(r)) => { r }
r => { r => {
combiner.infcx().tcx.sess.span_bug( fields.tcx().sess.span_bug(
combiner.trace().origin.span(), fields.trace.origin.span(),
&format!("found non-region-vid: {:?}", r)); &format!("found non-region-vid: {:?}", r));
} }
}).collect() })
.collect()
} }
fn is_var_in_set(new_vars: &[ty::RegionVid], r: ty::Region) -> bool { fn is_var_in_set(new_vars: &[ty::RegionVid], r: ty::Region) -> bool {
@ -356,7 +359,7 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>,
unbound_value: &T, unbound_value: &T,
mut fldr: F) mut fldr: F)
-> T -> T
where T : Combineable<'tcx>, where T: TypeFoldable<'tcx>,
F: FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region, F: FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region,
{ {
unbound_value.fold_with(&mut ty_fold::RegionFolder::new(tcx, &mut |region, current_depth| { unbound_value.fold_with(&mut ty_fold::RegionFolder::new(tcx, &mut |region, current_depth| {

View file

@ -29,48 +29,32 @@
//! over a `LatticeValue`, which is a value defined with respect to //! over a `LatticeValue`, which is a value defined with respect to
//! a lattice. //! a lattice.
use super::*; use super::combine;
use super::combine::*; use super::InferCtxt;
use super::glb::Glb;
use super::lub::Lub;
use middle::ty::TyVar; use middle::ty::TyVar;
use middle::ty::{self, Ty}; use middle::ty::{self, Ty};
use middle::ty_relate::{RelateResult, TypeRelation};
use util::ppaux::Repr; use util::ppaux::Repr;
pub trait LatticeDir<'tcx> { pub trait LatticeDir<'f,'tcx> : TypeRelation<'f,'tcx> {
fn infcx(&self) -> &'f InferCtxt<'f, 'tcx>;
// Relates the type `v` to `a` and `b` such that `v` represents // Relates the type `v` to `a` and `b` such that `v` represents
// the LUB/GLB of `a` and `b` as appropriate. // the LUB/GLB of `a` and `b` as appropriate.
fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, ()>; fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>;
} }
impl<'a, 'tcx> LatticeDir<'tcx> for Lub<'a, 'tcx> { pub fn super_lattice_tys<'a,'tcx,L:LatticeDir<'a,'tcx>>(this: &mut L,
fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, ()> {
let sub = self.sub();
try!(sub.tys(a, v));
try!(sub.tys(b, v));
Ok(())
}
}
impl<'a, 'tcx> LatticeDir<'tcx> for Glb<'a, 'tcx> {
fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, ()> {
let sub = self.sub();
try!(sub.tys(v, a));
try!(sub.tys(v, b));
Ok(())
}
}
pub fn super_lattice_tys<'tcx, L:LatticeDir<'tcx>+Combine<'tcx>>(this: &L,
a: Ty<'tcx>, a: Ty<'tcx>,
b: Ty<'tcx>) b: Ty<'tcx>)
-> cres<'tcx, Ty<'tcx>> -> RelateResult<'tcx, Ty<'tcx>>
where 'tcx: 'a
{ {
debug!("{}.lattice_tys({}, {})", debug!("{}.lattice_tys({}, {})",
this.tag(), this.tag(),
a.repr(this.infcx().tcx), a.repr(this.tcx()),
b.repr(this.infcx().tcx)); b.repr(this.tcx()));
if a == b { if a == b {
return Ok(a); return Ok(a);
@ -95,7 +79,7 @@ pub fn super_lattice_tys<'tcx, L:LatticeDir<'tcx>+Combine<'tcx>>(this: &L,
} }
_ => { _ => {
super_tys(this, a, b) combine::super_combine_tys(this.infcx(), this, a, b)
} }
} }
} }

View file

@ -8,67 +8,80 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use super::combine::*; use super::combine::CombineFields;
use super::higher_ranked::HigherRankedRelations; use super::higher_ranked::HigherRankedRelations;
use super::lattice::*; use super::InferCtxt;
use super::cres; use super::lattice::{self, LatticeDir};
use super::Subtype; use super::Subtype;
use middle::ty::{self, Ty}; use middle::ty::{self, Ty};
use middle::ty_relate::{Relate, RelateResult, TypeRelation};
use util::ppaux::Repr; use util::ppaux::Repr;
/// "Least upper bound" (common supertype) /// "Least upper bound" (common supertype)
pub struct Lub<'f, 'tcx: 'f> { pub struct Lub<'a, 'tcx: 'a> {
fields: CombineFields<'f, 'tcx> fields: CombineFields<'a, 'tcx>
} }
#[allow(non_snake_case)] impl<'a, 'tcx> Lub<'a, 'tcx> {
pub fn Lub<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Lub<'f, 'tcx> { pub fn new(fields: CombineFields<'a, 'tcx>) -> Lub<'a, 'tcx> {
Lub { fields: cf } Lub { fields: fields }
}
} }
impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> { impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Lub<'a, 'tcx> {
fn tag(&self) -> String { "Lub".to_string() } fn tag(&self) -> &'static str { "Lub" }
fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() }
-> cres<'tcx, Ty<'tcx>>
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
variance: ty::Variance,
a: &T,
b: &T)
-> RelateResult<'tcx, T>
{ {
match v { match variance {
ty::Invariant => self.equate().tys(a, b), ty::Invariant => self.fields.equate().relate(a, b),
ty::Covariant => self.tys(a, b), ty::Covariant => self.relate(a, b),
ty::Bivariant => self.bivariate().tys(a, b), ty::Bivariant => self.fields.bivariate().relate(a, b),
ty::Contravariant => self.glb().tys(a, b), ty::Contravariant => self.fields.glb().relate(a, b),
} }
} }
fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region) fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-> cres<'tcx, ty::Region> lattice::super_lattice_tys(self, a, b)
{
match v {
ty::Invariant => self.equate().regions(a, b),
ty::Covariant => self.regions(a, b),
ty::Bivariant => self.bivariate().regions(a, b),
ty::Contravariant => self.glb().regions(a, b),
}
} }
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> { fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
debug!("{}.regions({}, {})", debug!("{}.regions({}, {})",
self.tag(), self.tag(),
a.repr(self.tcx()), a.repr(self.tcx()),
b.repr(self.tcx())); b.repr(self.tcx()));
Ok(self.infcx().region_vars.lub_regions(Subtype(self.trace()), a, b)) let origin = Subtype(self.fields.trace.clone());
Ok(self.fields.infcx.region_vars.lub_regions(origin, a, b))
} }
fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
super_lattice_tys(self, a, b) -> RelateResult<'tcx, ty::Binder<T>>
} where T: Relate<'a, 'tcx>
fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>>
where T : Combineable<'tcx>
{ {
self.higher_ranked_lub(a, b) self.fields.higher_ranked_lub(a, b)
} }
} }
impl<'a, 'tcx> LatticeDir<'a,'tcx> for Lub<'a, 'tcx> {
fn infcx(&self) -> &'a InferCtxt<'a,'tcx> {
self.fields.infcx
}
fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
let mut sub = self.fields.sub();
try!(sub.relate(&a, &v));
try!(sub.relate(&b, &v));
Ok(())
}
}

View file

@ -28,7 +28,8 @@ use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, UnconstrainedNumeric};
use middle::ty::replace_late_bound_regions; use middle::ty::replace_late_bound_regions;
use middle::ty::{self, Ty}; use middle::ty::{self, Ty};
use middle::ty_fold::{TypeFolder, TypeFoldable}; use middle::ty_fold::{TypeFolder, TypeFoldable};
use std::cell::RefCell; use middle::ty_relate::{Relate, RelateResult, TypeRelation};
use std::cell::{RefCell};
use std::fmt; use std::fmt;
use std::rc::Rc; use std::rc::Rc;
use syntax::ast; use syntax::ast;
@ -38,12 +39,9 @@ use util::nodemap::FnvHashMap;
use util::ppaux::ty_to_string; use util::ppaux::ty_to_string;
use util::ppaux::{Repr, UserString}; use util::ppaux::{Repr, UserString};
use self::combine::{Combine, Combineable, CombineFields}; use self::combine::CombineFields;
use self::region_inference::{RegionVarBindings, RegionSnapshot}; use self::region_inference::{RegionVarBindings, RegionSnapshot};
use self::equate::Equate; use self::unify::{ToType, UnificationTable};
use self::sub::Sub;
use self::lub::Lub;
use self::unify::{UnificationTable, InferCtxtMethodsForSimplyUnifiableTypes};
use self::error_reporting::ErrorReporting; use self::error_reporting::ErrorReporting;
pub mod bivariate; pub mod bivariate;
@ -62,9 +60,7 @@ pub mod type_variable;
pub mod unify; pub mod unify;
pub type Bound<T> = Option<T>; pub type Bound<T> = Option<T>;
pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
pub type cres<'tcx, T> = Result<T,ty::type_err<'tcx>>; // "combine result"
pub type ures<'tcx> = cres<'tcx, ()>; // "unify result"
pub type fres<T> = Result<T, fixup_err>; // "fixup result" pub type fres<T> = Result<T, fixup_err>; // "fixup result"
pub struct InferCtxt<'a, 'tcx: 'a> { pub struct InferCtxt<'a, 'tcx: 'a> {
@ -265,7 +261,7 @@ pub enum LateBoundRegionConversionTime {
/// ///
/// See `error_reporting.rs` for more details /// See `error_reporting.rs` for more details
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum RegionVariableOrigin<'tcx> { pub enum RegionVariableOrigin {
// Region variables created for ill-categorized reasons, // Region variables created for ill-categorized reasons,
// mostly indicates places in need of refactoring // mostly indicates places in need of refactoring
MiscVariable(Span), MiscVariable(Span),
@ -280,7 +276,7 @@ pub enum RegionVariableOrigin<'tcx> {
Autoref(Span), Autoref(Span),
// Regions created as part of an automatic coercion // Regions created as part of an automatic coercion
Coercion(TypeTrace<'tcx>), Coercion(Span),
// Region variables created as the values for early-bound regions // Region variables created as the values for early-bound regions
EarlyBoundRegion(Span, ast::Name), EarlyBoundRegion(Span, ast::Name),
@ -343,8 +339,7 @@ pub fn common_supertype<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
values: Types(expected_found(a_is_expected, a, b)) values: Types(expected_found(a_is_expected, a, b))
}; };
let result = let result = cx.commit_if_ok(|_| cx.lub(a_is_expected, trace.clone()).relate(&a, &b));
cx.commit_if_ok(|| cx.lub(a_is_expected, trace.clone()).tys(a, b));
match result { match result {
Ok(t) => t, Ok(t) => t,
Err(ref err) => { Err(ref err) => {
@ -359,29 +354,28 @@ pub fn mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
origin: TypeOrigin, origin: TypeOrigin,
a: Ty<'tcx>, a: Ty<'tcx>,
b: Ty<'tcx>) b: Ty<'tcx>)
-> ures<'tcx> -> UnitResult<'tcx>
{ {
debug!("mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); debug!("mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
cx.commit_if_ok(|| {
cx.sub_types(a_is_expected, origin, a, b) cx.sub_types(a_is_expected, origin, a, b)
})
} }
pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
a: Ty<'tcx>, a: Ty<'tcx>,
b: Ty<'tcx>) b: Ty<'tcx>)
-> ures<'tcx> { -> UnitResult<'tcx> {
debug!("can_mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); debug!("can_mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
cx.probe(|_| { cx.probe(|_| {
let trace = TypeTrace { let trace = TypeTrace {
origin: Misc(codemap::DUMMY_SP), origin: Misc(codemap::DUMMY_SP),
values: Types(expected_found(true, a, b)) values: Types(expected_found(true, a, b))
}; };
cx.sub(true, trace).tys(a, b).to_ures() cx.sub(true, trace).relate(&a, &b).map(|_| ())
}) })
} }
pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> ures<'tcx> pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>)
-> UnitResult<'tcx>
{ {
cx.can_equate(&a, &b) cx.can_equate(&a, &b)
} }
@ -401,11 +395,10 @@ pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
origin: TypeOrigin, origin: TypeOrigin,
a: Ty<'tcx>, a: Ty<'tcx>,
b: Ty<'tcx>) b: Ty<'tcx>)
-> ures<'tcx> -> UnitResult<'tcx>
{ {
debug!("mk_eqty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); debug!("mk_eqty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
cx.commit_if_ok( cx.commit_if_ok(|_| cx.eq_types(a_is_expected, origin, a, b))
|| cx.eq_types(a_is_expected, origin, a, b))
} }
pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
@ -413,12 +406,11 @@ pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
origin: TypeOrigin, origin: TypeOrigin,
a: ty::PolyTraitRef<'tcx>, a: ty::PolyTraitRef<'tcx>,
b: ty::PolyTraitRef<'tcx>) b: ty::PolyTraitRef<'tcx>)
-> ures<'tcx> -> UnitResult<'tcx>
{ {
debug!("mk_sub_trait_refs({} <: {})", debug!("mk_sub_trait_refs({} <: {})",
a.repr(cx.tcx), b.repr(cx.tcx)); a.repr(cx.tcx), b.repr(cx.tcx));
cx.commit_if_ok( cx.commit_if_ok(|_| cx.sub_poly_trait_refs(a_is_expected, origin, a.clone(), b.clone()))
|| cx.sub_poly_trait_refs(a_is_expected, origin, a.clone(), b.clone()))
} }
fn expected_found<T>(a_is_expected: bool, fn expected_found<T>(a_is_expected: bool,
@ -433,57 +425,6 @@ fn expected_found<T>(a_is_expected: bool,
} }
} }
trait then<'tcx> {
fn then<T, F>(&self, f: F) -> Result<T, ty::type_err<'tcx>> where
T: Clone,
F: FnOnce() -> Result<T, ty::type_err<'tcx>>;
}
impl<'tcx> then<'tcx> for ures<'tcx> {
fn then<T, F>(&self, f: F) -> Result<T, ty::type_err<'tcx>> where
T: Clone,
F: FnOnce() -> Result<T, ty::type_err<'tcx>>,
{
self.and_then(move |_| f())
}
}
trait ToUres<'tcx> {
fn to_ures(&self) -> ures<'tcx>;
}
impl<'tcx, T> ToUres<'tcx> for cres<'tcx, T> {
fn to_ures(&self) -> ures<'tcx> {
match *self {
Ok(ref _v) => Ok(()),
Err(ref e) => Err((*e))
}
}
}
trait CresCompare<'tcx, T> {
fn compare<F>(&self, t: T, f: F) -> cres<'tcx, T> where
F: FnOnce() -> ty::type_err<'tcx>;
}
impl<'tcx, T:Clone + PartialEq> CresCompare<'tcx, T> for cres<'tcx, T> {
fn compare<F>(&self, t: T, f: F) -> cres<'tcx, T> where
F: FnOnce() -> ty::type_err<'tcx>,
{
(*self).clone().and_then(move |s| {
if s == t {
(*self).clone()
} else {
Err(f())
}
})
}
}
pub fn uok<'tcx>() -> ures<'tcx> {
Ok(())
}
#[must_use = "once you start a snapshot, you should always consume it"] #[must_use = "once you start a snapshot, you should always consume it"]
pub struct CombinedSnapshot { pub struct CombinedSnapshot {
type_snapshot: type_variable::Snapshot, type_snapshot: type_variable::Snapshot,
@ -512,41 +453,56 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
use middle::ty::UnconstrainedNumeric::{Neither, UnconstrainedInt, UnconstrainedFloat}; use middle::ty::UnconstrainedNumeric::{Neither, UnconstrainedInt, UnconstrainedFloat};
match ty.sty { match ty.sty {
ty::ty_infer(ty::IntVar(vid)) => { ty::ty_infer(ty::IntVar(vid)) => {
match self.int_unification_table.borrow_mut().get(self.tcx, vid).value { if self.int_unification_table.borrow_mut().has_value(vid) {
None => UnconstrainedInt, Neither
_ => Neither, } else {
UnconstrainedInt
} }
}, },
ty::ty_infer(ty::FloatVar(vid)) => { ty::ty_infer(ty::FloatVar(vid)) => {
match self.float_unification_table.borrow_mut().get(self.tcx, vid).value { if self.float_unification_table.borrow_mut().has_value(vid) {
None => return UnconstrainedFloat, Neither
_ => Neither, } else {
UnconstrainedFloat
} }
}, },
_ => Neither, _ => Neither,
} }
} }
pub fn combine_fields<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>) fn combine_fields(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
-> CombineFields<'b, 'tcx> { -> CombineFields<'a, 'tcx> {
CombineFields {infcx: self, CombineFields {infcx: self,
a_is_expected: a_is_expected, a_is_expected: a_is_expected,
trace: trace} trace: trace}
} }
pub fn equate<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>) // public so that it can be used from the rustc_driver unit tests
-> Equate<'b, 'tcx> { pub fn equate(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
Equate(self.combine_fields(a_is_expected, trace)) -> equate::Equate<'a, 'tcx>
{
self.combine_fields(a_is_expected, trace).equate()
} }
pub fn sub<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>) // public so that it can be used from the rustc_driver unit tests
-> Sub<'b, 'tcx> { pub fn sub(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
Sub(self.combine_fields(a_is_expected, trace)) -> sub::Sub<'a, 'tcx>
{
self.combine_fields(a_is_expected, trace).sub()
} }
pub fn lub<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>) // public so that it can be used from the rustc_driver unit tests
-> Lub<'b, 'tcx> { pub fn lub(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
Lub(self.combine_fields(a_is_expected, trace)) -> lub::Lub<'a, 'tcx>
{
self.combine_fields(a_is_expected, trace).lub()
}
// public so that it can be used from the rustc_driver unit tests
pub fn glb(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
-> glb::Glb<'a, 'tcx>
{
self.combine_fields(a_is_expected, trace).glb()
} }
fn start_snapshot(&self) -> CombinedSnapshot { fn start_snapshot(&self) -> CombinedSnapshot {
@ -609,11 +565,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
r r
} }
/// Execute `f` and commit the bindings if successful /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)`
pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E> where pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E> where
F: FnOnce() -> Result<T, E> F: FnOnce(&CombinedSnapshot) -> Result<T, E>
{ {
self.commit_unconditionally(move || self.try(move |_| f())) debug!("commit_if_ok()");
let snapshot = self.start_snapshot();
let r = f(&snapshot);
debug!("commit_if_ok() -- r.is_ok() = {}", r.is_ok());
match r {
Ok(_) => { self.commit_from(snapshot); }
Err(_) => { self.rollback_to(snapshot); }
}
r
} }
/// Execute `f` and commit only the region bindings if successful. /// Execute `f` and commit only the region bindings if successful.
@ -628,7 +592,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
float_snapshot, float_snapshot,
region_vars_snapshot } = self.start_snapshot(); region_vars_snapshot } = self.start_snapshot();
let r = self.try(move |_| f()); let r = self.commit_if_ok(|_| f());
// Roll back any non-region bindings - they should be resolved // Roll back any non-region bindings - they should be resolved
// inside `f`, with, e.g. `resolve_type_vars_if_possible`. // inside `f`, with, e.g. `resolve_type_vars_if_possible`.
@ -649,25 +613,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
r r
} }
/// Execute `f`, unroll bindings on panic
pub fn try<T, E, F>(&self, f: F) -> Result<T, E> where
F: FnOnce(&CombinedSnapshot) -> Result<T, E>
{
debug!("try()");
let snapshot = self.start_snapshot();
let r = f(&snapshot);
debug!("try() -- r.is_ok() = {}", r.is_ok());
match r {
Ok(_) => {
self.commit_from(snapshot);
}
Err(_) => {
self.rollback_to(snapshot);
}
}
r
}
/// Execute `f` then unroll any bindings it creates /// Execute `f` then unroll any bindings it creates
pub fn probe<R, F>(&self, f: F) -> R where pub fn probe<R, F>(&self, f: F) -> R where
F: FnOnce(&CombinedSnapshot) -> R, F: FnOnce(&CombinedSnapshot) -> R,
@ -691,12 +636,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
origin: TypeOrigin, origin: TypeOrigin,
a: Ty<'tcx>, a: Ty<'tcx>,
b: Ty<'tcx>) b: Ty<'tcx>)
-> ures<'tcx> -> UnitResult<'tcx>
{ {
debug!("sub_types({} <: {})", a.repr(self.tcx), b.repr(self.tcx)); debug!("sub_types({} <: {})", a.repr(self.tcx), b.repr(self.tcx));
self.commit_if_ok(|| { self.commit_if_ok(|_| {
let trace = TypeTrace::types(origin, a_is_expected, a, b); let trace = TypeTrace::types(origin, a_is_expected, a, b);
self.sub(a_is_expected, trace).tys(a, b).to_ures() self.sub(a_is_expected, trace).relate(&a, &b).map(|_| ())
}) })
} }
@ -705,11 +650,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
origin: TypeOrigin, origin: TypeOrigin,
a: Ty<'tcx>, a: Ty<'tcx>,
b: Ty<'tcx>) b: Ty<'tcx>)
-> ures<'tcx> -> UnitResult<'tcx>
{ {
self.commit_if_ok(|| { self.commit_if_ok(|_| {
let trace = TypeTrace::types(origin, a_is_expected, a, b); let trace = TypeTrace::types(origin, a_is_expected, a, b);
self.equate(a_is_expected, trace).tys(a, b).to_ures() self.equate(a_is_expected, trace).relate(&a, &b).map(|_| ())
}) })
} }
@ -718,17 +663,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
origin: TypeOrigin, origin: TypeOrigin,
a: Rc<ty::TraitRef<'tcx>>, a: Rc<ty::TraitRef<'tcx>>,
b: Rc<ty::TraitRef<'tcx>>) b: Rc<ty::TraitRef<'tcx>>)
-> ures<'tcx> -> UnitResult<'tcx>
{ {
debug!("sub_trait_refs({} <: {})", debug!("sub_trait_refs({} <: {})",
a.repr(self.tcx), a.repr(self.tcx),
b.repr(self.tcx)); b.repr(self.tcx));
self.commit_if_ok(|| { self.commit_if_ok(|_| {
let trace = TypeTrace { let trace = TypeTrace {
origin: origin, origin: origin,
values: TraitRefs(expected_found(a_is_expected, a.clone(), b.clone())) values: TraitRefs(expected_found(a_is_expected, a.clone(), b.clone()))
}; };
self.sub(a_is_expected, trace).trait_refs(&*a, &*b).to_ures() self.sub(a_is_expected, trace).relate(&*a, &*b).map(|_| ())
}) })
} }
@ -737,17 +682,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
origin: TypeOrigin, origin: TypeOrigin,
a: ty::PolyTraitRef<'tcx>, a: ty::PolyTraitRef<'tcx>,
b: ty::PolyTraitRef<'tcx>) b: ty::PolyTraitRef<'tcx>)
-> ures<'tcx> -> UnitResult<'tcx>
{ {
debug!("sub_poly_trait_refs({} <: {})", debug!("sub_poly_trait_refs({} <: {})",
a.repr(self.tcx), a.repr(self.tcx),
b.repr(self.tcx)); b.repr(self.tcx));
self.commit_if_ok(|| { self.commit_if_ok(|_| {
let trace = TypeTrace { let trace = TypeTrace {
origin: origin, origin: origin,
values: PolyTraitRefs(expected_found(a_is_expected, a.clone(), b.clone())) values: PolyTraitRefs(expected_found(a_is_expected, a.clone(), b.clone()))
}; };
self.sub(a_is_expected, trace).binders(&a, &b).to_ures() self.sub(a_is_expected, trace).relate(&a, &b).map(|_| ())
}) })
} }
@ -774,7 +719,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn leak_check(&self, pub fn leak_check(&self,
skol_map: &SkolemizationMap, skol_map: &SkolemizationMap,
snapshot: &CombinedSnapshot) snapshot: &CombinedSnapshot)
-> ures<'tcx> -> UnitResult<'tcx>
{ {
/*! See `higher_ranked::leak_check` */ /*! See `higher_ranked::leak_check` */
@ -799,8 +744,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn equality_predicate(&self, pub fn equality_predicate(&self,
span: Span, span: Span,
predicate: &ty::PolyEquatePredicate<'tcx>) predicate: &ty::PolyEquatePredicate<'tcx>)
-> ures<'tcx> { -> UnitResult<'tcx> {
self.try(|snapshot| { self.commit_if_ok(|snapshot| {
let (ty::EquatePredicate(a, b), skol_map) = let (ty::EquatePredicate(a, b), skol_map) =
self.skolemize_late_bound_regions(predicate, snapshot); self.skolemize_late_bound_regions(predicate, snapshot);
let origin = EquatePredicate(span); let origin = EquatePredicate(span);
@ -812,8 +757,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn region_outlives_predicate(&self, pub fn region_outlives_predicate(&self,
span: Span, span: Span,
predicate: &ty::PolyRegionOutlivesPredicate) predicate: &ty::PolyRegionOutlivesPredicate)
-> ures<'tcx> { -> UnitResult<'tcx> {
self.try(|snapshot| { self.commit_if_ok(|snapshot| {
let (ty::OutlivesPredicate(r_a, r_b), skol_map) = let (ty::OutlivesPredicate(r_a, r_b), skol_map) =
self.skolemize_late_bound_regions(predicate, snapshot); self.skolemize_late_bound_regions(predicate, snapshot);
let origin = RelateRegionParamBound(span); let origin = RelateRegionParamBound(span);
@ -852,7 +797,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
.new_key(None) .new_key(None)
} }
pub fn next_region_var(&self, origin: RegionVariableOrigin<'tcx>) -> ty::Region { pub fn next_region_var(&self, origin: RegionVariableOrigin) -> ty::Region {
ty::ReInfer(ty::ReVar(self.region_vars.new_region_var(origin))) ty::ReInfer(ty::ReVar(self.region_vars.new_region_var(origin)))
} }
@ -948,12 +893,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
} }
ty::ty_infer(ty::IntVar(v)) => { ty::ty_infer(ty::IntVar(v)) => {
self.probe_var(v) self.int_unification_table
.borrow_mut()
.probe(v)
.map(|v| v.to_type(self.tcx))
.unwrap_or(typ) .unwrap_or(typ)
} }
ty::ty_infer(ty::FloatVar(v)) => { ty::ty_infer(ty::FloatVar(v)) => {
self.probe_var(v) self.float_unification_table
.borrow_mut()
.probe(v)
.map(|v| v.to_type(self.tcx))
.unwrap_or(typ) .unwrap_or(typ)
} }
@ -1104,8 +1055,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
self.region_vars.verify_generic_bound(origin, kind, a, bs); self.region_vars.verify_generic_bound(origin, kind, a, bs);
} }
pub fn can_equate<T>(&self, a: &T, b: &T) -> ures<'tcx> pub fn can_equate<'b,T>(&'b self, a: &T, b: &T) -> UnitResult<'tcx>
where T : Combineable<'tcx> + Repr<'tcx> where T: Relate<'b,'tcx> + Repr<'tcx>
{ {
debug!("can_equate({}, {})", a.repr(self.tcx), b.repr(self.tcx)); debug!("can_equate({}, {})", a.repr(self.tcx), b.repr(self.tcx));
self.probe(|_| { self.probe(|_| {
@ -1116,9 +1067,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let e = self.tcx.types.err; let e = self.tcx.types.err;
let trace = TypeTrace { origin: Misc(codemap::DUMMY_SP), let trace = TypeTrace { origin: Misc(codemap::DUMMY_SP),
values: Types(expected_found(true, e, e)) }; values: Types(expected_found(true, e, e)) };
let eq = self.equate(true, trace); self.equate(true, trace).relate(a, b)
Combineable::combine(&eq, a, b) }).map(|_| ())
}).to_ures()
} }
} }
@ -1304,14 +1254,14 @@ impl<'tcx> Repr<'tcx> for SubregionOrigin<'tcx> {
} }
} }
impl<'tcx> RegionVariableOrigin<'tcx> { impl RegionVariableOrigin {
pub fn span(&self) -> Span { pub fn span(&self) -> Span {
match *self { match *self {
MiscVariable(a) => a, MiscVariable(a) => a,
PatternRegion(a) => a, PatternRegion(a) => a,
AddrOfRegion(a) => a, AddrOfRegion(a) => a,
Autoref(a) => a, Autoref(a) => a,
Coercion(ref a) => a.span(), Coercion(a) => a,
EarlyBoundRegion(a, _) => a, EarlyBoundRegion(a, _) => a,
LateBoundRegion(a, _, _) => a, LateBoundRegion(a, _, _) => a,
BoundRegionInCoherence(_) => codemap::DUMMY_SP, BoundRegionInCoherence(_) => codemap::DUMMY_SP,
@ -1320,7 +1270,7 @@ impl<'tcx> RegionVariableOrigin<'tcx> {
} }
} }
impl<'tcx> Repr<'tcx> for RegionVariableOrigin<'tcx> { impl<'tcx> Repr<'tcx> for RegionVariableOrigin {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
match *self { match *self {
MiscVariable(a) => { MiscVariable(a) => {
@ -1333,7 +1283,7 @@ impl<'tcx> Repr<'tcx> for RegionVariableOrigin<'tcx> {
format!("AddrOfRegion({})", a.repr(tcx)) format!("AddrOfRegion({})", a.repr(tcx))
} }
Autoref(a) => format!("Autoref({})", a.repr(tcx)), Autoref(a) => format!("Autoref({})", a.repr(tcx)),
Coercion(ref a) => format!("Coercion({})", a.repr(tcx)), Coercion(a) => format!("Coercion({})", a.repr(tcx)),
EarlyBoundRegion(a, b) => { EarlyBoundRegion(a, b) => {
format!("EarlyBoundRegion({},{})", a.repr(tcx), b.repr(tcx)) format!("EarlyBoundRegion({},{})", a.repr(tcx), b.repr(tcx))
} }

View file

@ -18,7 +18,6 @@ pub use self::RegionResolutionError::*;
pub use self::VarValue::*; pub use self::VarValue::*;
use self::Classification::*; use self::Classification::*;
use super::cres;
use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable}; use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable};
use middle::region; use middle::region;
@ -26,6 +25,7 @@ use middle::ty::{self, Ty};
use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid}; use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid};
use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound}; use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound};
use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh}; use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh};
use middle::ty_relate::RelateResult;
use middle::graph; use middle::graph;
use middle::graph::{Direction, NodeIndex}; use middle::graph::{Direction, NodeIndex};
use util::common::indenter; use util::common::indenter;
@ -115,7 +115,7 @@ pub enum RegionResolutionError<'tcx> {
/// Could not infer a value for `v` because `sub_r <= v` (due to /// Could not infer a value for `v` because `sub_r <= v` (due to
/// `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and /// `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and
/// `sub_r <= sup_r` does not hold. /// `sub_r <= sup_r` does not hold.
SubSupConflict(RegionVariableOrigin<'tcx>, SubSupConflict(RegionVariableOrigin,
SubregionOrigin<'tcx>, Region, SubregionOrigin<'tcx>, Region,
SubregionOrigin<'tcx>, Region), SubregionOrigin<'tcx>, Region),
@ -124,7 +124,7 @@ pub enum RegionResolutionError<'tcx> {
/// Could not infer a value for `v` because `v <= r1` (due to /// Could not infer a value for `v` because `v <= r1` (due to
/// `origin1`) and `v <= r2` (due to `origin2`) and /// `origin1`) and `v <= r2` (due to `origin2`) and
/// `r1` and `r2` have no intersection. /// `r1` and `r2` have no intersection.
SupSupConflict(RegionVariableOrigin<'tcx>, SupSupConflict(RegionVariableOrigin,
SubregionOrigin<'tcx>, Region, SubregionOrigin<'tcx>, Region,
SubregionOrigin<'tcx>, Region), SubregionOrigin<'tcx>, Region),
@ -132,7 +132,7 @@ pub enum RegionResolutionError<'tcx> {
/// more specific errors message by suggesting to the user where they /// more specific errors message by suggesting to the user where they
/// should put a lifetime. In those cases we process and put those errors /// should put a lifetime. In those cases we process and put those errors
/// into `ProcessedErrors` before we do any reporting. /// into `ProcessedErrors` before we do any reporting.
ProcessedErrors(Vec<RegionVariableOrigin<'tcx>>, ProcessedErrors(Vec<RegionVariableOrigin>,
Vec<(TypeTrace<'tcx>, ty::type_err<'tcx>)>, Vec<(TypeTrace<'tcx>, ty::type_err<'tcx>)>,
Vec<SameRegions>), Vec<SameRegions>),
} }
@ -168,7 +168,7 @@ pub type CombineMap = FnvHashMap<TwoRegions, RegionVid>;
pub struct RegionVarBindings<'a, 'tcx: 'a> { pub struct RegionVarBindings<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>, tcx: &'a ty::ctxt<'tcx>,
var_origins: RefCell<Vec<RegionVariableOrigin<'tcx>>>, var_origins: RefCell<Vec<RegionVariableOrigin>>,
// Constraints of the form `A <= B` introduced by the region // Constraints of the form `A <= B` introduced by the region
// checker. Here at least one of `A` and `B` must be a region // checker. Here at least one of `A` and `B` must be a region
@ -316,7 +316,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
len as u32 len as u32
} }
pub fn new_region_var(&self, origin: RegionVariableOrigin<'tcx>) -> RegionVid { pub fn new_region_var(&self, origin: RegionVariableOrigin) -> RegionVid {
let id = self.num_vars(); let id = self.num_vars();
self.var_origins.borrow_mut().push(origin.clone()); self.var_origins.borrow_mut().push(origin.clone());
let vid = RegionVid { index: id }; let vid = RegionVid { index: id };
@ -798,7 +798,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
/// regions are given as argument, in any order, a consistent result is returned. /// regions are given as argument, in any order, a consistent result is returned.
fn lub_free_regions(&self, fn lub_free_regions(&self,
a: &FreeRegion, a: &FreeRegion,
b: &FreeRegion) -> ty::Region b: &FreeRegion)
-> ty::Region
{ {
return match a.cmp(b) { return match a.cmp(b) {
Less => helper(self, a, b), Less => helper(self, a, b),
@ -823,7 +824,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
fn glb_concrete_regions(&self, fn glb_concrete_regions(&self,
a: Region, a: Region,
b: Region) b: Region)
-> cres<'tcx, Region> { -> RelateResult<'tcx, Region>
{
debug!("glb_concrete_regions({:?}, {:?})", a, b); debug!("glb_concrete_regions({:?}, {:?})", a, b);
match (a, b) { match (a, b) {
(ReLateBound(..), _) | (ReLateBound(..), _) |
@ -898,7 +900,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
/// returned. /// returned.
fn glb_free_regions(&self, fn glb_free_regions(&self,
a: &FreeRegion, a: &FreeRegion,
b: &FreeRegion) -> cres<'tcx, ty::Region> b: &FreeRegion)
-> RelateResult<'tcx, ty::Region>
{ {
return match a.cmp(b) { return match a.cmp(b) {
Less => helper(self, a, b), Less => helper(self, a, b),
@ -908,7 +911,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
fn helper<'a, 'tcx>(this: &RegionVarBindings<'a, 'tcx>, fn helper<'a, 'tcx>(this: &RegionVarBindings<'a, 'tcx>,
a: &FreeRegion, a: &FreeRegion,
b: &FreeRegion) -> cres<'tcx, ty::Region> b: &FreeRegion) -> RelateResult<'tcx, ty::Region>
{ {
if this.tcx.region_maps.sub_free_region(*a, *b) { if this.tcx.region_maps.sub_free_region(*a, *b) {
Ok(ty::ReFree(*a)) Ok(ty::ReFree(*a))
@ -926,7 +929,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
region_a: ty::Region, region_a: ty::Region,
region_b: ty::Region, region_b: ty::Region,
scope_a: region::CodeExtent, scope_a: region::CodeExtent,
scope_b: region::CodeExtent) -> cres<'tcx, Region> scope_b: region::CodeExtent)
-> RelateResult<'tcx, Region>
{ {
// We want to generate the intersection of two // We want to generate the intersection of two
// scopes or two free regions. So, if one of // scopes or two free regions. So, if one of

View file

@ -8,64 +8,49 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use super::combine::*; use super::combine::{self, CombineFields};
use super::cres;
use super::higher_ranked::HigherRankedRelations; use super::higher_ranked::HigherRankedRelations;
use super::Subtype; use super::Subtype;
use super::type_variable::{SubtypeOf, SupertypeOf}; use super::type_variable::{SubtypeOf, SupertypeOf};
use middle::ty::{self, Ty}; use middle::ty::{self, Ty};
use middle::ty::TyVar; use middle::ty::TyVar;
use util::ppaux::Repr; use middle::ty_relate::{Relate, RelateResult, TypeRelation};
use util::ppaux::{Repr};
/// "Greatest lower bound" (common subtype) /// "Greatest lower bound" (common subtype)
pub struct Sub<'f, 'tcx: 'f> { pub struct Sub<'a, 'tcx: 'a> {
fields: CombineFields<'f, 'tcx> fields: CombineFields<'a, 'tcx>
} }
#[allow(non_snake_case)] impl<'a, 'tcx> Sub<'a, 'tcx> {
pub fn Sub<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Sub<'f, 'tcx> { pub fn new(f: CombineFields<'a, 'tcx>) -> Sub<'a, 'tcx> {
Sub { fields: cf } Sub { fields: f }
}
} }
impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> { impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Sub<'a, 'tcx> {
fn tag(&self) -> String { "Sub".to_string() } fn tag(&self) -> &'static str { "Sub" }
fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields } fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.infcx.tcx }
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
-> cres<'tcx, Ty<'tcx>> variance: ty::Variance,
a: &T,
b: &T)
-> RelateResult<'tcx, T>
{ {
match v { match variance {
ty::Invariant => self.equate().tys(a, b), ty::Invariant => self.fields.equate().relate(a, b),
ty::Covariant => self.tys(a, b), ty::Covariant => self.relate(a, b),
ty::Bivariant => self.bivariate().tys(a, b), ty::Bivariant => self.fields.bivariate().relate(a, b),
ty::Contravariant => Sub(self.fields.switch_expected()).tys(b, a), ty::Contravariant => self.fields.switch_expected().sub().relate(b, a),
} }
} }
fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region) fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-> cres<'tcx, ty::Region> debug!("{}.tys({}, {})", self.tag(), a.repr(self.tcx()), b.repr(self.tcx()));
{
match v {
ty::Invariant => self.equate().regions(a, b),
ty::Covariant => self.regions(a, b),
ty::Bivariant => self.bivariate().regions(a, b),
ty::Contravariant => Sub(self.fields.switch_expected()).regions(b, a),
}
}
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
debug!("{}.regions({}, {})",
self.tag(),
a.repr(self.tcx()),
b.repr(self.tcx()));
self.infcx().region_vars.make_subregion(Subtype(self.trace()), a, b);
Ok(a)
}
fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
debug!("{}.tys({}, {})", self.tag(),
a.repr(self.tcx()), b.repr(self.tcx()));
if a == b { return Ok(a); } if a == b { return Ok(a); }
let infcx = self.fields.infcx; let infcx = self.fields.infcx;
@ -94,14 +79,25 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> {
} }
_ => { _ => {
super_tys(self, a, b) combine::super_combine_tys(self.fields.infcx, self, a, b)
} }
} }
} }
fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>> fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
where T : Combineable<'tcx> debug!("{}.regions({}, {})",
self.tag(),
a.repr(self.tcx()),
b.repr(self.tcx()));
let origin = Subtype(self.fields.trace.clone());
self.fields.infcx.region_vars.make_subregion(origin, a, b);
Ok(a)
}
fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'a,'tcx>
{ {
self.higher_ranked_sub(a, b) self.fields.higher_ranked_sub(a, b)
} }
} }

View file

@ -12,11 +12,8 @@ pub use self::VarValue::*;
use std::marker; use std::marker;
use middle::ty::{expected_found, IntVarValue}; use middle::ty::{IntVarValue};
use middle::ty::{self, Ty}; use middle::ty::{self, Ty};
use middle::infer::{uok, ures};
use middle::infer::InferCtxt;
use std::cell::RefCell;
use std::fmt::Debug; use std::fmt::Debug;
use std::marker::PhantomData; use std::marker::PhantomData;
use syntax::ast; use syntax::ast;
@ -35,14 +32,9 @@ use util::snapshot_vec as sv;
pub trait UnifyKey : Clone + Debug + PartialEq { pub trait UnifyKey : Clone + Debug + PartialEq {
type Value : UnifyValue; type Value : UnifyValue;
fn index(&self) -> usize; fn index(&self) -> u32;
fn from_index(u: usize) -> Self; fn from_index(u: u32) -> Self;
// Given an inference context, returns the unification table
// appropriate to this key type.
fn unification_table<'v>(infcx: &'v InferCtxt)
-> &'v RefCell<UnificationTable<Self>>;
fn tag(k: Option<Self>) -> &'static str; fn tag(k: Option<Self>) -> &'static str;
} }
@ -130,21 +122,25 @@ impl<K:UnifyKey> UnificationTable<K> {
pub fn new_key(&mut self, value: K::Value) -> K { pub fn new_key(&mut self, value: K::Value) -> K {
let index = self.values.push(Root(value, 0)); let index = self.values.push(Root(value, 0));
let k = UnifyKey::from_index(index); let k = UnifyKey::from_index(index as u32);
debug!("{}: created new key: {:?}", debug!("{}: created new key: {:?}",
UnifyKey::tag(None::<K>), UnifyKey::tag(None::<K>),
k); k);
k k
} }
/// Find the root node for `vid`. This uses the standard union-find algorithm with path /// Find the root node for `vid`. This uses the standard
/// compression: http://en.wikipedia.org/wiki/Disjoint-set_data_structure /// union-find algorithm with path compression:
pub fn get(&mut self, tcx: &ty::ctxt, vid: K) -> Node<K> { /// <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>.
let index = vid.index(); ///
/// NB. This is a building-block operation and you would probably
/// prefer to call `probe` below.
fn get(&mut self, vid: K) -> Node<K> {
let index = vid.index() as usize;
let value = (*self.values.get(index)).clone(); let value = (*self.values.get(index)).clone();
match value { match value {
Redirect(redirect) => { Redirect(redirect) => {
let node: Node<K> = self.get(tcx, redirect.clone()); let node: Node<K> = self.get(redirect.clone());
if node.key != redirect { if node.key != redirect {
// Path compression // Path compression
self.values.set(index, Redirect(node.key.clone())); self.values.set(index, Redirect(node.key.clone()));
@ -158,58 +154,58 @@ impl<K:UnifyKey> UnificationTable<K> {
} }
fn is_root(&self, key: &K) -> bool { fn is_root(&self, key: &K) -> bool {
match *self.values.get(key.index()) { let index = key.index() as usize;
match *self.values.get(index) {
Redirect(..) => false, Redirect(..) => false,
Root(..) => true, Root(..) => true,
} }
} }
/// Sets the value for `vid` to `new_value`. `vid` MUST be a root node! Also, we must be in the /// Sets the value for `vid` to `new_value`. `vid` MUST be a root
/// middle of a snapshot. /// node! This is an internal operation used to impl other things.
pub fn set<'tcx>(&mut self, fn set(&mut self, key: K, new_value: VarValue<K>) {
_tcx: &ty::ctxt<'tcx>,
key: K,
new_value: VarValue<K>)
{
assert!(self.is_root(&key)); assert!(self.is_root(&key));
debug!("Updating variable {:?} to {:?}", debug!("Updating variable {:?} to {:?}",
key, new_value); key, new_value);
self.values.set(key.index(), new_value); let index = key.index() as usize;
self.values.set(index, new_value);
} }
/// Either redirects node_a to node_b or vice versa, depending on the relative rank. Returns /// Either redirects `node_a` to `node_b` or vice versa, depending
/// the new root and rank. You should then update the value of the new root to something /// on the relative rank. The value associated with the new root
/// suitable. /// will be `new_value`.
pub fn unify<'tcx>(&mut self, ///
tcx: &ty::ctxt<'tcx>, /// NB: This is the "union" operation of "union-find". It is
node_a: &Node<K>, /// really more of a building block. If the values associated with
node_b: &Node<K>) /// your key are non-trivial, you would probably prefer to call
-> (K, usize) /// `unify_var_var` below.
{ fn unify(&mut self, node_a: &Node<K>, node_b: &Node<K>, new_value: K::Value) {
debug!("unify(node_a(id={:?}, rank={:?}), node_b(id={:?}, rank={:?}))", debug!("unify(node_a(id={:?}, rank={:?}), node_b(id={:?}, rank={:?}))",
node_a.key, node_a.key,
node_a.rank, node_a.rank,
node_b.key, node_b.key,
node_b.rank); node_b.rank);
if node_a.rank > node_b.rank { let (new_root, new_rank) = if node_a.rank > node_b.rank {
// a has greater rank, so a should become b's parent, // a has greater rank, so a should become b's parent,
// i.e., b should redirect to a. // i.e., b should redirect to a.
self.set(tcx, node_b.key.clone(), Redirect(node_a.key.clone())); self.set(node_b.key.clone(), Redirect(node_a.key.clone()));
(node_a.key.clone(), node_a.rank) (node_a.key.clone(), node_a.rank)
} else if node_a.rank < node_b.rank { } else if node_a.rank < node_b.rank {
// b has greater rank, so a should redirect to b. // b has greater rank, so a should redirect to b.
self.set(tcx, node_a.key.clone(), Redirect(node_b.key.clone())); self.set(node_a.key.clone(), Redirect(node_b.key.clone()));
(node_b.key.clone(), node_b.rank) (node_b.key.clone(), node_b.rank)
} else { } else {
// If equal, redirect one to the other and increment the // If equal, redirect one to the other and increment the
// other's rank. // other's rank.
assert_eq!(node_a.rank, node_b.rank); assert_eq!(node_a.rank, node_b.rank);
self.set(tcx, node_b.key.clone(), Redirect(node_a.key.clone())); self.set(node_b.key.clone(), Redirect(node_a.key.clone()));
(node_a.key.clone(), node_a.rank + 1) (node_a.key.clone(), node_a.rank + 1)
} };
self.set(new_root, Root(new_value, new_rank));
} }
} }
@ -223,69 +219,26 @@ impl<K:UnifyKey> sv::SnapshotVecDelegate for Delegate<K> {
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Code to handle simple keys like ints, floats---anything that // Code to handle keys which carry a value, like ints,
// doesn't have a subtyping relationship we need to worry about. // floats---anything that doesn't have a subtyping relationship we
// need to worry about.
/// Indicates a type that does not have any kind of subtyping impl<'tcx,K,V> UnificationTable<K>
/// relationship.
pub trait SimplyUnifiable<'tcx> : Clone + PartialEq + Debug {
fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx>;
fn to_type_err(expected_found<Self>) -> ty::type_err<'tcx>;
}
pub fn err<'tcx, V:SimplyUnifiable<'tcx>>(a_is_expected: bool,
a_t: V,
b_t: V)
-> ures<'tcx> {
if a_is_expected {
Err(SimplyUnifiable::to_type_err(
ty::expected_found {expected: a_t, found: b_t}))
} else {
Err(SimplyUnifiable::to_type_err(
ty::expected_found {expected: b_t, found: a_t}))
}
}
pub trait InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V>
where K: UnifyKey<Value=Option<V>>, where K: UnifyKey<Value=Option<V>>,
V : SimplyUnifiable<'tcx>, V: Clone+PartialEq,
Option<V>: UnifyValue, Option<V>: UnifyValue,
{ {
fn simple_vars(&self, pub fn unify_var_var(&mut self,
a_is_expected: bool,
a_id: K, a_id: K,
b_id: K) b_id: K)
-> ures<'tcx>; -> Result<(),(V,V)>
fn simple_var_t(&self,
a_is_expected: bool,
a_id: K,
b: V)
-> ures<'tcx>;
fn probe_var(&self, a_id: K) -> Option<Ty<'tcx>>;
}
impl<'a,'tcx,V,K> InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V> for InferCtxt<'a,'tcx>
where K : UnifyKey<Value=Option<V>>,
V : SimplyUnifiable<'tcx>,
Option<V> : UnifyValue,
{ {
/// Unifies two simple keys. Because simple keys do not have any subtyping relationships, if let node_a = self.get(a_id);
/// both keys have already been associated with a value, then those two values must be the let node_b = self.get(b_id);
/// same.
fn simple_vars(&self,
a_is_expected: bool,
a_id: K,
b_id: K)
-> ures<'tcx>
{
let tcx = self.tcx;
let table = UnifyKey::unification_table(self);
let node_a: Node<K> = table.borrow_mut().get(tcx, a_id);
let node_b: Node<K> = table.borrow_mut().get(tcx, b_id);
let a_id = node_a.key.clone(); let a_id = node_a.key.clone();
let b_id = node_b.key.clone(); let b_id = node_b.key.clone();
if a_id == b_id { return uok(); } if a_id == b_id { return Ok(()); }
let combined = { let combined = {
match (&node_a.value, &node_b.value) { match (&node_a.value, &node_b.value) {
@ -293,61 +246,52 @@ impl<'a,'tcx,V,K> InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V> for InferCtx
None None
} }
(&Some(ref v), &None) | (&None, &Some(ref v)) => { (&Some(ref v), &None) | (&None, &Some(ref v)) => {
Some((*v).clone()) Some(v.clone())
} }
(&Some(ref v1), &Some(ref v2)) => { (&Some(ref v1), &Some(ref v2)) => {
if *v1 != *v2 { if *v1 != *v2 {
return err(a_is_expected, (*v1).clone(), (*v2).clone()) return Err((v1.clone(), v2.clone()));
} }
Some((*v1).clone()) Some(v1.clone())
} }
} }
}; };
let (new_root, new_rank) = table.borrow_mut().unify(tcx, Ok(self.unify(&node_a, &node_b, combined))
&node_a,
&node_b);
table.borrow_mut().set(tcx, new_root, Root(combined, new_rank));
return Ok(())
} }
/// Sets the value of the key `a_id` to `b`. Because simple keys do not have any subtyping /// Sets the value of the key `a_id` to `b`. Because simple keys do not have any subtyping
/// relationships, if `a_id` already has a value, it must be the same as `b`. /// relationships, if `a_id` already has a value, it must be the same as `b`.
fn simple_var_t(&self, pub fn unify_var_value(&mut self,
a_is_expected: bool,
a_id: K, a_id: K,
b: V) b: V)
-> ures<'tcx> -> Result<(),(V,V)>
{ {
let tcx = self.tcx; let node_a = self.get(a_id);
let table = UnifyKey::unification_table(self);
let node_a = table.borrow_mut().get(tcx, a_id);
let a_id = node_a.key.clone(); let a_id = node_a.key.clone();
match node_a.value { match node_a.value {
None => { None => {
table.borrow_mut().set(tcx, a_id, Root(Some(b), node_a.rank)); self.set(a_id, Root(Some(b), node_a.rank));
return Ok(()); Ok(())
} }
Some(ref a_t) => { Some(ref a_t) => {
if *a_t == b { if *a_t == b {
return Ok(()); Ok(())
} else { } else {
return err(a_is_expected, (*a_t).clone(), b); Err((a_t.clone(), b))
} }
} }
} }
} }
fn probe_var(&self, a_id: K) -> Option<Ty<'tcx>> { pub fn has_value(&mut self, id: K) -> bool {
let tcx = self.tcx; self.get(id).value.is_some()
let table = UnifyKey::unification_table(self);
let node_a = table.borrow_mut().get(tcx, a_id);
match node_a.value {
None => None,
Some(ref a_t) => Some(a_t.to_type(tcx))
} }
pub fn probe(&mut self, a_id: K) -> Option<V> {
self.get(a_id).value.clone()
} }
} }
@ -355,33 +299,24 @@ impl<'a,'tcx,V,K> InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V> for InferCtx
// Integral type keys // Integral type keys
pub trait ToType<'tcx> {
fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx>;
}
impl UnifyKey for ty::IntVid { impl UnifyKey for ty::IntVid {
type Value = Option<IntVarValue>; type Value = Option<IntVarValue>;
fn index(&self) -> u32 { self.index }
fn index(&self) -> usize { self.index as usize } fn from_index(i: u32) -> ty::IntVid { ty::IntVid { index: i } }
fn tag(_: Option<ty::IntVid>) -> &'static str { "IntVid" }
fn from_index(i: usize) -> ty::IntVid { ty::IntVid { index: i as u32 } }
fn unification_table<'v>(infcx: &'v InferCtxt) -> &'v RefCell<UnificationTable<ty::IntVid>> {
return &infcx.int_unification_table;
} }
fn tag(_: Option<ty::IntVid>) -> &'static str { impl<'tcx> ToType<'tcx> for IntVarValue {
"IntVid"
}
}
impl<'tcx> SimplyUnifiable<'tcx> for IntVarValue {
fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> { fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
match *self { match *self {
ty::IntType(i) => ty::mk_mach_int(tcx, i), ty::IntType(i) => ty::mk_mach_int(tcx, i),
ty::UintType(i) => ty::mk_mach_uint(tcx, i), ty::UintType(i) => ty::mk_mach_uint(tcx, i),
} }
} }
fn to_type_err(err: expected_found<IntVarValue>) -> ty::type_err<'tcx> {
return ty::terr_int_mismatch(err);
}
} }
impl UnifyValue for Option<IntVarValue> { } impl UnifyValue for Option<IntVarValue> { }
@ -390,29 +325,16 @@ impl UnifyValue for Option<IntVarValue> { }
impl UnifyKey for ty::FloatVid { impl UnifyKey for ty::FloatVid {
type Value = Option<ast::FloatTy>; type Value = Option<ast::FloatTy>;
fn index(&self) -> u32 { self.index }
fn index(&self) -> usize { self.index as usize } fn from_index(i: u32) -> ty::FloatVid { ty::FloatVid { index: i } }
fn tag(_: Option<ty::FloatVid>) -> &'static str { "FloatVid" }
fn from_index(i: usize) -> ty::FloatVid { ty::FloatVid { index: i as u32 } }
fn unification_table<'v>(infcx: &'v InferCtxt) -> &'v RefCell<UnificationTable<ty::FloatVid>> {
return &infcx.float_unification_table;
}
fn tag(_: Option<ty::FloatVid>) -> &'static str {
"FloatVid"
}
} }
impl UnifyValue for Option<ast::FloatTy> { impl UnifyValue for Option<ast::FloatTy> {
} }
impl<'tcx> SimplyUnifiable<'tcx> for ast::FloatTy { impl<'tcx> ToType<'tcx> for ast::FloatTy {
fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> { fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
ty::mk_mach_float(tcx, *self) ty::mk_mach_float(tcx, *self)
} }
fn to_type_err(err: expected_found<ast::FloatTy>) -> ty::type_err<'tcx> {
ty::terr_float_mismatch(err)
}
} }

View file

@ -81,7 +81,7 @@ pub fn poly_project_and_unify_type<'cx,'tcx>(
obligation.repr(selcx.tcx())); obligation.repr(selcx.tcx()));
let infcx = selcx.infcx(); let infcx = selcx.infcx();
infcx.try(|snapshot| { infcx.commit_if_ok(|snapshot| {
let (skol_predicate, skol_map) = let (skol_predicate, skol_map) =
infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot); infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot);
@ -291,6 +291,7 @@ impl<'a,'b,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'b,'tcx> {
} }
} }
#[derive(Clone)]
pub struct Normalized<'tcx,T> { pub struct Normalized<'tcx,T> {
pub value: T, pub value: T,
pub obligations: Vec<PredicateObligation<'tcx>>, pub obligations: Vec<PredicateObligation<'tcx>>,

View file

@ -39,11 +39,13 @@ use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
use middle::infer; use middle::infer;
use middle::infer::{InferCtxt, TypeFreshener}; use middle::infer::{InferCtxt, TypeFreshener};
use middle::ty_fold::TypeFoldable; use middle::ty_fold::TypeFoldable;
use middle::ty_match;
use middle::ty_relate::TypeRelation;
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::hash_map::HashMap;
use std::rc::Rc; use std::rc::Rc;
use syntax::{abi, ast}; use syntax::{abi, ast};
use util::common::ErrorReported; use util::common::ErrorReported;
use util::nodemap::FnvHashMap;
use util::ppaux::Repr; use util::ppaux::Repr;
pub struct SelectionContext<'cx, 'tcx:'cx> { pub struct SelectionContext<'cx, 'tcx:'cx> {
@ -87,7 +89,7 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> {
#[derive(Clone)] #[derive(Clone)]
pub struct SelectionCache<'tcx> { pub struct SelectionCache<'tcx> {
hashmap: RefCell<HashMap<Rc<ty::TraitRef<'tcx>>, hashmap: RefCell<FnvHashMap<Rc<ty::TraitRef<'tcx>>,
SelectionResult<'tcx, SelectionCandidate<'tcx>>>>, SelectionResult<'tcx, SelectionCandidate<'tcx>>>>,
} }
@ -474,7 +476,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
unbound_input_types && unbound_input_types &&
(self.intercrate || (self.intercrate ||
stack.iter().skip(1).any( stack.iter().skip(1).any(
|prev| stack.fresh_trait_ref.def_id() == prev.fresh_trait_ref.def_id())) |prev| self.match_fresh_trait_refs(&stack.fresh_trait_ref,
&prev.fresh_trait_ref)))
{ {
debug!("evaluate_stack({}) --> unbound argument, recursion --> ambiguous", debug!("evaluate_stack({}) --> unbound argument, recursion --> ambiguous",
stack.fresh_trait_ref.repr(self.tcx())); stack.fresh_trait_ref.repr(self.tcx()));
@ -1271,7 +1274,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return; return;
} }
self.infcx.try(|snapshot| { self.infcx.commit_if_ok(|snapshot| {
let bound_self_ty = let bound_self_ty =
self.infcx.resolve_type_vars_if_possible(&obligation.self_ty()); self.infcx.resolve_type_vars_if_possible(&obligation.self_ty());
let (self_ty, _) = let (self_ty, _) =
@ -1808,7 +1811,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// For each type, produce a vector of resulting obligations // For each type, produce a vector of resulting obligations
let obligations: Result<Vec<Vec<_>>, _> = bound_types.iter().map(|nested_ty| { let obligations: Result<Vec<Vec<_>>, _> = bound_types.iter().map(|nested_ty| {
self.infcx.try(|snapshot| { self.infcx.commit_if_ok(|snapshot| {
let (skol_ty, skol_map) = let (skol_ty, skol_map) =
self.infcx().skolemize_late_bound_regions(nested_ty, snapshot); self.infcx().skolemize_late_bound_regions(nested_ty, snapshot);
let Normalized { value: normalized_ty, mut obligations } = let Normalized { value: normalized_ty, mut obligations } =
@ -1918,7 +1921,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation: &TraitObligation<'tcx>) obligation: &TraitObligation<'tcx>)
{ {
let _: Result<(),()> = let _: Result<(),()> =
self.infcx.try(|snapshot| { self.infcx.commit_if_ok(|snapshot| {
let result = let result =
self.match_projection_obligation_against_bounds_from_trait(obligation, self.match_projection_obligation_against_bounds_from_trait(obligation,
snapshot); snapshot);
@ -2073,7 +2076,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
trait_def_id, trait_def_id,
nested); nested);
let trait_obligations: Result<VecPerParamSpace<_>,()> = self.infcx.try(|snapshot| { let trait_obligations: Result<VecPerParamSpace<_>,()> = self.infcx.commit_if_ok(|snapshot| {
let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
let (trait_ref, skol_map) = let (trait_ref, skol_map) =
self.infcx().skolemize_late_bound_regions(&poly_trait_ref, snapshot); self.infcx().skolemize_late_bound_regions(&poly_trait_ref, snapshot);
@ -2107,7 +2110,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// First, create the substitutions by matching the impl again, // First, create the substitutions by matching the impl again,
// this time not in a probe. // this time not in a probe.
self.infcx.try(|snapshot| { self.infcx.commit_if_ok(|snapshot| {
let (skol_obligation_trait_ref, skol_map) = let (skol_obligation_trait_ref, skol_map) =
self.infcx().skolemize_late_bound_regions(&obligation.predicate, snapshot); self.infcx().skolemize_late_bound_regions(&obligation.predicate, snapshot);
let substs = let substs =
@ -2505,6 +2508,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Miscellany // Miscellany
fn match_fresh_trait_refs(&self,
previous: &ty::PolyTraitRef<'tcx>,
current: &ty::PolyTraitRef<'tcx>)
-> bool
{
let mut matcher = ty_match::Match::new(self.tcx());
matcher.relate(previous, current).is_ok()
}
fn push_stack<'o,'s:'o>(&mut self, fn push_stack<'o,'s:'o>(&mut self,
previous_stack: TraitObligationStackList<'s, 'tcx>, previous_stack: TraitObligationStackList<'s, 'tcx>,
obligation: &'o TraitObligation<'tcx>) obligation: &'o TraitObligation<'tcx>)
@ -2664,7 +2676,7 @@ impl<'tcx> Repr<'tcx> for SelectionCandidate<'tcx> {
impl<'tcx> SelectionCache<'tcx> { impl<'tcx> SelectionCache<'tcx> {
pub fn new() -> SelectionCache<'tcx> { pub fn new() -> SelectionCache<'tcx> {
SelectionCache { SelectionCache {
hashmap: RefCell::new(HashMap::new()) hashmap: RefCell::new(FnvHashMap())
} }
} }
} }

View file

@ -39,6 +39,8 @@ use middle::subst::VecPerParamSpace;
use middle::ty::{self, Ty}; use middle::ty::{self, Ty};
use middle::traits; use middle::traits;
use std::rc::Rc; use std::rc::Rc;
use syntax::abi;
use syntax::ast;
use syntax::owned_slice::OwnedSlice; use syntax::owned_slice::OwnedSlice;
use util::ppaux::Repr; use util::ppaux::Repr;
@ -47,7 +49,7 @@ use util::ppaux::Repr;
/// The TypeFoldable trait is implemented for every type that can be folded. /// The TypeFoldable trait is implemented for every type that can be folded.
/// Basically, every type that has a corresponding method in TypeFolder. /// Basically, every type that has a corresponding method in TypeFolder.
pub trait TypeFoldable<'tcx> { pub trait TypeFoldable<'tcx>: Repr<'tcx> + Clone {
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self; fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self;
} }
@ -149,11 +151,19 @@ pub trait TypeFolder<'tcx> : Sized {
// can easily refactor the folding into the TypeFolder trait as // can easily refactor the folding into the TypeFolder trait as
// needed. // needed.
impl<'tcx> TypeFoldable<'tcx> for () { macro_rules! CopyImpls {
fn fold_with<F:TypeFolder<'tcx>>(&self, _: &mut F) -> () { ($($ty:ty),+) => {
() $(
impl<'tcx> TypeFoldable<'tcx> for $ty {
fn fold_with<F:TypeFolder<'tcx>>(&self, _: &mut F) -> $ty {
*self
} }
} }
)+
}
}
CopyImpls! { (), ast::Unsafety, abi::Abi }
impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) { impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> (T, U) { fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> (T, U) {

View file

@ -0,0 +1,95 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use middle::ty::{self, Ty};
use middle::ty_relate::{self, Relate, TypeRelation, RelateResult};
use util::ppaux::Repr;
/// A type "A" *matches* "B" if the fresh types in B could be
/// substituted with values so as to make it equal to A. Matching is
/// intended to be used only on freshened types, and it basically
/// indicates if the non-freshened versions of A and B could have been
/// unified.
///
/// It is only an approximation. If it yields false, unification would
/// definitely fail, but a true result doesn't mean unification would
/// succeed. This is because we don't track the "side-constraints" on
/// type variables, nor do we track if the same freshened type appears
/// more than once. To some extent these approximations could be
/// fixed, given effort.
///
/// Like subtyping, matching is really a binary relation, so the only
/// important thing about the result is Ok/Err. Also, matching never
/// affects any type variables or unification state.
pub struct Match<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>
}
impl<'a, 'tcx> Match<'a, 'tcx> {
pub fn new(tcx: &'a ty::ctxt<'tcx>) -> Match<'a, 'tcx> {
Match { tcx: tcx }
}
}
impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Match<'a, 'tcx> {
fn tag(&self) -> &'static str { "Match" }
fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.tcx }
fn a_is_expected(&self) -> bool { true } // irrelevant
fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
_: ty::Variance,
a: &T,
b: &T)
-> RelateResult<'tcx, T>
{
self.relate(a, b)
}
fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
debug!("{}.regions({}, {})",
self.tag(),
a.repr(self.tcx()),
b.repr(self.tcx()));
Ok(a)
}
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
debug!("{}.tys({}, {})", self.tag(),
a.repr(self.tcx()), b.repr(self.tcx()));
if a == b { return Ok(a); }
match (&a.sty, &b.sty) {
(_, &ty::ty_infer(ty::FreshTy(_))) |
(_, &ty::ty_infer(ty::FreshIntTy(_))) => {
Ok(a)
}
(&ty::ty_infer(_), _) |
(_, &ty::ty_infer(_)) => {
Err(ty::terr_sorts(ty_relate::expected_found(self, &a, &b)))
}
(&ty::ty_err, _) | (_, &ty::ty_err) => {
Ok(self.tcx().types.err)
}
_ => {
ty_relate::super_relate_tys(self, a, b)
}
}
}
fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'a,'tcx>
{
Ok(ty::Binder(try!(self.relate(a.skip_binder(), b.skip_binder()))))
}
}

View file

@ -0,0 +1,655 @@
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Generalized type relating mechanism. A type relation R relates a
//! pair of values (A, B). A and B are usually types or regions but
//! can be other things. Examples of type relations are subtyping,
//! type equality, etc.
use middle::subst::{ErasedRegions, NonerasedRegions, ParamSpace, Substs};
use middle::ty::{self, Ty};
use middle::ty_fold::TypeFoldable;
use std::rc::Rc;
use syntax::abi;
use syntax::ast;
use util::ppaux::Repr;
pub type RelateResult<'tcx, T> = Result<T, ty::type_err<'tcx>>;
pub trait TypeRelation<'a,'tcx> : Sized {
fn tcx(&self) -> &'a ty::ctxt<'tcx>;
/// Returns a static string we can use for printouts.
fn tag(&self) -> &'static str;
/// Returns true if the value `a` is the "expected" type in the
/// relation. Just affects error messages.
fn a_is_expected(&self) -> bool;
/// Generic relation routine suitable for most anything.
fn relate<T:Relate<'a,'tcx>>(&mut self, a: &T, b: &T) -> RelateResult<'tcx, T> {
Relate::relate(self, a, b)
}
/// Switch variance for the purpose of relating `a` and `b`.
fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
variance: ty::Variance,
a: &T,
b: &T)
-> RelateResult<'tcx, T>;
// Overrideable relations. You shouldn't typically call these
// directly, instead call `relate()`, which in turn calls
// these. This is both more uniform but also allows us to add
// additional hooks for other types in the future if needed
// without making older code, which called `relate`, obsolete.
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>)
-> RelateResult<'tcx, Ty<'tcx>>;
fn regions(&mut self, a: ty::Region, b: ty::Region)
-> RelateResult<'tcx, ty::Region>;
fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'a,'tcx>;
}
pub trait Relate<'a,'tcx>: TypeFoldable<'tcx> {
fn relate<R:TypeRelation<'a,'tcx>>(relation: &mut R,
a: &Self,
b: &Self)
-> RelateResult<'tcx, Self>;
}
///////////////////////////////////////////////////////////////////////////
// Relate impls
impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::mt<'tcx> {
fn relate<R>(relation: &mut R,
a: &ty::mt<'tcx>,
b: &ty::mt<'tcx>)
-> RelateResult<'tcx, ty::mt<'tcx>>
where R: TypeRelation<'a,'tcx>
{
debug!("{}.mts({}, {})",
relation.tag(),
a.repr(relation.tcx()),
b.repr(relation.tcx()));
if a.mutbl != b.mutbl {
Err(ty::terr_mutability)
} else {
let mutbl = a.mutbl;
let variance = match mutbl {
ast::MutImmutable => ty::Covariant,
ast::MutMutable => ty::Invariant,
};
let ty = try!(relation.relate_with_variance(variance, &a.ty, &b.ty));
Ok(ty::mt {ty: ty, mutbl: mutbl})
}
}
}
// substitutions are not themselves relatable without more context,
// but they is an important subroutine for things that ARE relatable,
// like traits etc.
fn relate_item_substs<'a,'tcx:'a,R>(relation: &mut R,
item_def_id: ast::DefId,
a_subst: &Substs<'tcx>,
b_subst: &Substs<'tcx>)
-> RelateResult<'tcx, Substs<'tcx>>
where R: TypeRelation<'a,'tcx>
{
debug!("substs: item_def_id={} a_subst={} b_subst={}",
item_def_id.repr(relation.tcx()),
a_subst.repr(relation.tcx()),
b_subst.repr(relation.tcx()));
let variances;
let opt_variances = if relation.tcx().variance_computed.get() {
variances = ty::item_variances(relation.tcx(), item_def_id);
Some(&*variances)
} else {
None
};
relate_substs(relation, opt_variances, a_subst, b_subst)
}
fn relate_substs<'a,'tcx,R>(relation: &mut R,
variances: Option<&ty::ItemVariances>,
a_subst: &Substs<'tcx>,
b_subst: &Substs<'tcx>)
-> RelateResult<'tcx, Substs<'tcx>>
where R: TypeRelation<'a,'tcx>
{
let mut substs = Substs::empty();
for &space in &ParamSpace::all() {
let a_tps = a_subst.types.get_slice(space);
let b_tps = b_subst.types.get_slice(space);
let t_variances = variances.map(|v| v.types.get_slice(space));
let tps = try!(relate_type_params(relation, t_variances, a_tps, b_tps));
substs.types.replace(space, tps);
}
match (&a_subst.regions, &b_subst.regions) {
(&ErasedRegions, _) | (_, &ErasedRegions) => {
substs.regions = ErasedRegions;
}
(&NonerasedRegions(ref a), &NonerasedRegions(ref b)) => {
for &space in &ParamSpace::all() {
let a_regions = a.get_slice(space);
let b_regions = b.get_slice(space);
let r_variances = variances.map(|v| v.regions.get_slice(space));
let regions = try!(relate_region_params(relation,
r_variances,
a_regions,
b_regions));
substs.mut_regions().replace(space, regions);
}
}
}
Ok(substs)
}
fn relate_type_params<'a,'tcx,R>(relation: &mut R,
variances: Option<&[ty::Variance]>,
a_tys: &[Ty<'tcx>],
b_tys: &[Ty<'tcx>])
-> RelateResult<'tcx, Vec<Ty<'tcx>>>
where R: TypeRelation<'a,'tcx>
{
if a_tys.len() != b_tys.len() {
return Err(ty::terr_ty_param_size(expected_found(relation,
&a_tys.len(),
&b_tys.len())));
}
(0 .. a_tys.len())
.map(|i| {
let a_ty = a_tys[i];
let b_ty = b_tys[i];
let v = variances.map_or(ty::Invariant, |v| v[i]);
relation.relate_with_variance(v, &a_ty, &b_ty)
})
.collect()
}
fn relate_region_params<'a,'tcx:'a,R>(relation: &mut R,
variances: Option<&[ty::Variance]>,
a_rs: &[ty::Region],
b_rs: &[ty::Region])
-> RelateResult<'tcx, Vec<ty::Region>>
where R: TypeRelation<'a,'tcx>
{
let tcx = relation.tcx();
let num_region_params = a_rs.len();
debug!("relate_region_params(a_rs={}, \
b_rs={}, variances={})",
a_rs.repr(tcx),
b_rs.repr(tcx),
variances.repr(tcx));
assert_eq!(num_region_params,
variances.map_or(num_region_params,
|v| v.len()));
assert_eq!(num_region_params, b_rs.len());
(0..a_rs.len())
.map(|i| {
let a_r = a_rs[i];
let b_r = b_rs[i];
let variance = variances.map_or(ty::Invariant, |v| v[i]);
relation.relate_with_variance(variance, &a_r, &b_r)
})
.collect()
}
impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::BareFnTy<'tcx> {
fn relate<R>(relation: &mut R,
a: &ty::BareFnTy<'tcx>,
b: &ty::BareFnTy<'tcx>)
-> RelateResult<'tcx, ty::BareFnTy<'tcx>>
where R: TypeRelation<'a,'tcx>
{
let unsafety = try!(relation.relate(&a.unsafety, &b.unsafety));
let abi = try!(relation.relate(&a.abi, &b.abi));
let sig = try!(relation.relate(&a.sig, &b.sig));
Ok(ty::BareFnTy {unsafety: unsafety,
abi: abi,
sig: sig})
}
}
impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::FnSig<'tcx> {
fn relate<R>(relation: &mut R,
a: &ty::FnSig<'tcx>,
b: &ty::FnSig<'tcx>)
-> RelateResult<'tcx, ty::FnSig<'tcx>>
where R: TypeRelation<'a,'tcx>
{
if a.variadic != b.variadic {
return Err(ty::terr_variadic_mismatch(
expected_found(relation, &a.variadic, &b.variadic)));
}
let inputs = try!(relate_arg_vecs(relation,
&a.inputs,
&b.inputs));
let output = try!(match (a.output, b.output) {
(ty::FnConverging(a_ty), ty::FnConverging(b_ty)) =>
Ok(ty::FnConverging(try!(relation.relate(&a_ty, &b_ty)))),
(ty::FnDiverging, ty::FnDiverging) =>
Ok(ty::FnDiverging),
(a, b) =>
Err(ty::terr_convergence_mismatch(
expected_found(relation, &(a != ty::FnDiverging), &(b != ty::FnDiverging)))),
});
return Ok(ty::FnSig {inputs: inputs,
output: output,
variadic: a.variadic});
}
}
fn relate_arg_vecs<'a,'tcx,R>(relation: &mut R,
a_args: &[Ty<'tcx>],
b_args: &[Ty<'tcx>])
-> RelateResult<'tcx, Vec<Ty<'tcx>>>
where R: TypeRelation<'a,'tcx>
{
if a_args.len() != b_args.len() {
return Err(ty::terr_arg_count);
}
a_args.iter()
.zip(b_args.iter())
.map(|(a, b)| relation.relate_with_variance(ty::Contravariant, a, b))
.collect()
}
impl<'a,'tcx:'a> Relate<'a,'tcx> for ast::Unsafety {
fn relate<R>(relation: &mut R,
a: &ast::Unsafety,
b: &ast::Unsafety)
-> RelateResult<'tcx, ast::Unsafety>
where R: TypeRelation<'a,'tcx>
{
if a != b {
Err(ty::terr_unsafety_mismatch(expected_found(relation, a, b)))
} else {
Ok(*a)
}
}
}
impl<'a,'tcx:'a> Relate<'a,'tcx> for abi::Abi {
fn relate<R>(relation: &mut R,
a: &abi::Abi,
b: &abi::Abi)
-> RelateResult<'tcx, abi::Abi>
where R: TypeRelation<'a,'tcx>
{
if a == b {
Ok(*a)
} else {
Err(ty::terr_abi_mismatch(expected_found(relation, a, b)))
}
}
}
impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ProjectionTy<'tcx> {
fn relate<R>(relation: &mut R,
a: &ty::ProjectionTy<'tcx>,
b: &ty::ProjectionTy<'tcx>)
-> RelateResult<'tcx, ty::ProjectionTy<'tcx>>
where R: TypeRelation<'a,'tcx>
{
if a.item_name != b.item_name {
Err(ty::terr_projection_name_mismatched(
expected_found(relation, &a.item_name, &b.item_name)))
} else {
let trait_ref = try!(relation.relate(&*a.trait_ref, &*b.trait_ref));
Ok(ty::ProjectionTy { trait_ref: Rc::new(trait_ref), item_name: a.item_name })
}
}
}
impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ProjectionPredicate<'tcx> {
fn relate<R>(relation: &mut R,
a: &ty::ProjectionPredicate<'tcx>,
b: &ty::ProjectionPredicate<'tcx>)
-> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>>
where R: TypeRelation<'a,'tcx>
{
let projection_ty = try!(relation.relate(&a.projection_ty, &b.projection_ty));
let ty = try!(relation.relate(&a.ty, &b.ty));
Ok(ty::ProjectionPredicate { projection_ty: projection_ty, ty: ty })
}
}
impl<'a,'tcx:'a> Relate<'a,'tcx> for Vec<ty::PolyProjectionPredicate<'tcx>> {
fn relate<R>(relation: &mut R,
a: &Vec<ty::PolyProjectionPredicate<'tcx>>,
b: &Vec<ty::PolyProjectionPredicate<'tcx>>)
-> RelateResult<'tcx, Vec<ty::PolyProjectionPredicate<'tcx>>>
where R: TypeRelation<'a,'tcx>
{
// To be compatible, `a` and `b` must be for precisely the
// same set of traits and item names. We always require that
// projection bounds lists are sorted by trait-def-id and item-name,
// so we can just iterate through the lists pairwise, so long as they are the
// same length.
if a.len() != b.len() {
Err(ty::terr_projection_bounds_length(expected_found(relation, &a.len(), &b.len())))
} else {
a.iter()
.zip(b.iter())
.map(|(a, b)| relation.relate(a, b))
.collect()
}
}
}
impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ExistentialBounds<'tcx> {
fn relate<R>(relation: &mut R,
a: &ty::ExistentialBounds<'tcx>,
b: &ty::ExistentialBounds<'tcx>)
-> RelateResult<'tcx, ty::ExistentialBounds<'tcx>>
where R: TypeRelation<'a,'tcx>
{
let r = try!(relation.relate_with_variance(ty::Contravariant,
&a.region_bound,
&b.region_bound));
let nb = try!(relation.relate(&a.builtin_bounds, &b.builtin_bounds));
let pb = try!(relation.relate(&a.projection_bounds, &b.projection_bounds));
Ok(ty::ExistentialBounds { region_bound: r,
builtin_bounds: nb,
projection_bounds: pb })
}
}
impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::BuiltinBounds {
fn relate<R>(relation: &mut R,
a: &ty::BuiltinBounds,
b: &ty::BuiltinBounds)
-> RelateResult<'tcx, ty::BuiltinBounds>
where R: TypeRelation<'a,'tcx>
{
// Two sets of builtin bounds are only relatable if they are
// precisely the same (but see the coercion code).
if a != b {
Err(ty::terr_builtin_bounds(expected_found(relation, a, b)))
} else {
Ok(*a)
}
}
}
impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::TraitRef<'tcx> {
fn relate<R>(relation: &mut R,
a: &ty::TraitRef<'tcx>,
b: &ty::TraitRef<'tcx>)
-> RelateResult<'tcx, ty::TraitRef<'tcx>>
where R: TypeRelation<'a,'tcx>
{
// Different traits cannot be related
if a.def_id != b.def_id {
Err(ty::terr_traits(expected_found(relation, &a.def_id, &b.def_id)))
} else {
let substs = try!(relate_item_substs(relation, a.def_id, a.substs, b.substs));
Ok(ty::TraitRef { def_id: a.def_id, substs: relation.tcx().mk_substs(substs) })
}
}
}
impl<'a,'tcx:'a> Relate<'a,'tcx> for Ty<'tcx> {
fn relate<R>(relation: &mut R,
a: &Ty<'tcx>,
b: &Ty<'tcx>)
-> RelateResult<'tcx, Ty<'tcx>>
where R: TypeRelation<'a,'tcx>
{
relation.tys(a, b)
}
}
/// The main "type relation" routine. Note that this does not handle
/// inference artifacts, so you should filter those out before calling
/// it.
pub fn super_relate_tys<'a,'tcx:'a,R>(relation: &mut R,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> RelateResult<'tcx, Ty<'tcx>>
where R: TypeRelation<'a,'tcx>
{
let tcx = relation.tcx();
let a_sty = &a.sty;
let b_sty = &b.sty;
debug!("super_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty);
match (a_sty, b_sty) {
(&ty::ty_infer(_), _) |
(_, &ty::ty_infer(_)) =>
{
// The caller should handle these cases!
tcx.sess.bug("var types encountered in super_relate_tys")
}
(&ty::ty_err, _) | (_, &ty::ty_err) =>
{
Ok(tcx.types.err)
}
(&ty::ty_char, _) |
(&ty::ty_bool, _) |
(&ty::ty_int(_), _) |
(&ty::ty_uint(_), _) |
(&ty::ty_float(_), _) |
(&ty::ty_str, _)
if a == b =>
{
Ok(a)
}
(&ty::ty_param(ref a_p), &ty::ty_param(ref b_p))
if a_p.idx == b_p.idx && a_p.space == b_p.space =>
{
Ok(a)
}
(&ty::ty_enum(a_id, a_substs), &ty::ty_enum(b_id, b_substs))
if a_id == b_id =>
{
let substs = try!(relate_item_substs(relation, a_id, a_substs, b_substs));
Ok(ty::mk_enum(tcx, a_id, tcx.mk_substs(substs)))
}
(&ty::ty_trait(ref a_), &ty::ty_trait(ref b_)) =>
{
let principal = try!(relation.relate(&a_.principal, &b_.principal));
let bounds = try!(relation.relate(&a_.bounds, &b_.bounds));
Ok(ty::mk_trait(tcx, principal, bounds))
}
(&ty::ty_struct(a_id, a_substs), &ty::ty_struct(b_id, b_substs))
if a_id == b_id =>
{
let substs = try!(relate_item_substs(relation, a_id, a_substs, b_substs));
Ok(ty::mk_struct(tcx, a_id, tcx.mk_substs(substs)))
}
(&ty::ty_closure(a_id, a_substs),
&ty::ty_closure(b_id, b_substs))
if a_id == b_id =>
{
// All ty_closure types with the same id represent
// the (anonymous) type of the same closure expression. So
// all of their regions should be equated.
let substs = try!(relate_substs(relation, None, a_substs, b_substs));
Ok(ty::mk_closure(tcx, a_id, tcx.mk_substs(substs)))
}
(&ty::ty_uniq(a_inner), &ty::ty_uniq(b_inner)) =>
{
let typ = try!(relation.relate(&a_inner, &b_inner));
Ok(ty::mk_uniq(tcx, typ))
}
(&ty::ty_ptr(ref a_mt), &ty::ty_ptr(ref b_mt)) =>
{
let mt = try!(relation.relate(a_mt, b_mt));
Ok(ty::mk_ptr(tcx, mt))
}
(&ty::ty_rptr(a_r, ref a_mt), &ty::ty_rptr(b_r, ref b_mt)) =>
{
let r = try!(relation.relate_with_variance(ty::Contravariant, a_r, b_r));
let mt = try!(relation.relate(a_mt, b_mt));
Ok(ty::mk_rptr(tcx, tcx.mk_region(r), mt))
}
(&ty::ty_vec(a_t, Some(sz_a)), &ty::ty_vec(b_t, Some(sz_b))) =>
{
let t = try!(relation.relate(&a_t, &b_t));
if sz_a == sz_b {
Ok(ty::mk_vec(tcx, t, Some(sz_a)))
} else {
Err(ty::terr_fixed_array_size(expected_found(relation, &sz_a, &sz_b)))
}
}
(&ty::ty_vec(a_t, None), &ty::ty_vec(b_t, None)) =>
{
let t = try!(relation.relate(&a_t, &b_t));
Ok(ty::mk_vec(tcx, t, None))
}
(&ty::ty_tup(ref as_), &ty::ty_tup(ref bs)) =>
{
if as_.len() == bs.len() {
let ts = try!(as_.iter()
.zip(bs.iter())
.map(|(a, b)| relation.relate(a, b))
.collect::<Result<_, _>>());
Ok(ty::mk_tup(tcx, ts))
} else if as_.len() != 0 && bs.len() != 0 {
Err(ty::terr_tuple_size(
expected_found(relation, &as_.len(), &bs.len())))
} else {
Err(ty::terr_sorts(expected_found(relation, &a, &b)))
}
}
(&ty::ty_bare_fn(a_opt_def_id, a_fty), &ty::ty_bare_fn(b_opt_def_id, b_fty))
if a_opt_def_id == b_opt_def_id =>
{
let fty = try!(relation.relate(a_fty, b_fty));
Ok(ty::mk_bare_fn(tcx, a_opt_def_id, tcx.mk_bare_fn(fty)))
}
(&ty::ty_projection(ref a_data), &ty::ty_projection(ref b_data)) =>
{
let projection_ty = try!(relation.relate(a_data, b_data));
Ok(ty::mk_projection(tcx, projection_ty.trait_ref, projection_ty.item_name))
}
_ =>
{
Err(ty::terr_sorts(expected_found(relation, &a, &b)))
}
}
}
impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::Region {
fn relate<R>(relation: &mut R,
a: &ty::Region,
b: &ty::Region)
-> RelateResult<'tcx, ty::Region>
where R: TypeRelation<'a,'tcx>
{
relation.regions(*a, *b)
}
}
impl<'a,'tcx:'a,T> Relate<'a,'tcx> for ty::Binder<T>
where T: Relate<'a,'tcx>
{
fn relate<R>(relation: &mut R,
a: &ty::Binder<T>,
b: &ty::Binder<T>)
-> RelateResult<'tcx, ty::Binder<T>>
where R: TypeRelation<'a,'tcx>
{
relation.binders(a, b)
}
}
impl<'a,'tcx:'a,T> Relate<'a,'tcx> for Rc<T>
where T: Relate<'a,'tcx>
{
fn relate<R>(relation: &mut R,
a: &Rc<T>,
b: &Rc<T>)
-> RelateResult<'tcx, Rc<T>>
where R: TypeRelation<'a,'tcx>
{
let a: &T = a;
let b: &T = b;
Ok(Rc::new(try!(relation.relate(a, b))))
}
}
impl<'a,'tcx:'a,T> Relate<'a,'tcx> for Box<T>
where T: Relate<'a,'tcx>
{
fn relate<R>(relation: &mut R,
a: &Box<T>,
b: &Box<T>)
-> RelateResult<'tcx, Box<T>>
where R: TypeRelation<'a,'tcx>
{
let a: &T = a;
let b: &T = b;
Ok(Box::new(try!(relation.relate(a, b))))
}
}
///////////////////////////////////////////////////////////////////////////
// Error handling
pub fn expected_found<'a,'tcx,R,T>(relation: &mut R,
a: &T,
b: &T)
-> ty::expected_found<T>
where R: TypeRelation<'a,'tcx>, T: Clone
{
expected_found_bool(relation.a_is_expected(), a, b)
}
pub fn expected_found_bool<T>(a_is_expected: bool,
a: &T,
b: &T)
-> ty::expected_found<T>
where T: Clone
{
let a = a.clone();
let b = b.clone();
if a_is_expected {
ty::expected_found {expected: a, found: b}
} else {
ty::expected_found {expected: b, found: a}
}
}

View file

@ -1526,3 +1526,9 @@ impl<'tcx> UserString<'tcx> for ty::Predicate<'tcx> {
} }
} }
} }
impl<'tcx> Repr<'tcx> for ast::Unsafety {
fn repr(&self, _: &ctxt<'tcx>) -> String {
format!("{:?}", *self)
}
}

View file

@ -22,7 +22,7 @@ use rustc_typeck::middle::stability;
use rustc_typeck::middle::subst; use rustc_typeck::middle::subst;
use rustc_typeck::middle::subst::Subst; use rustc_typeck::middle::subst::Subst;
use rustc_typeck::middle::ty::{self, Ty}; use rustc_typeck::middle::ty::{self, Ty};
use rustc_typeck::middle::infer::combine::Combine; use rustc_typeck::middle::ty_relate::TypeRelation;
use rustc_typeck::middle::infer; use rustc_typeck::middle::infer;
use rustc_typeck::middle::infer::lub::Lub; use rustc_typeck::middle::infer::lub::Lub;
use rustc_typeck::middle::infer::glb::Glb; use rustc_typeck::middle::infer::glb::Glb;
@ -350,21 +350,21 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
pub fn sub(&self) -> Sub<'a, 'tcx> { pub fn sub(&self) -> Sub<'a, 'tcx> {
let trace = self.dummy_type_trace(); let trace = self.dummy_type_trace();
Sub(self.infcx.combine_fields(true, trace)) self.infcx.sub(true, trace)
} }
pub fn lub(&self) -> Lub<'a, 'tcx> { pub fn lub(&self) -> Lub<'a, 'tcx> {
let trace = self.dummy_type_trace(); let trace = self.dummy_type_trace();
Lub(self.infcx.combine_fields(true, trace)) self.infcx.lub(true, trace)
} }
pub fn glb(&self) -> Glb<'a, 'tcx> { pub fn glb(&self) -> Glb<'a, 'tcx> {
let trace = self.dummy_type_trace(); let trace = self.dummy_type_trace();
Glb(self.infcx.combine_fields(true, trace)) self.infcx.glb(true, trace)
} }
pub fn make_lub_ty(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> Ty<'tcx> { pub fn make_lub_ty(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> Ty<'tcx> {
match self.lub().tys(t1, t2) { match self.lub().relate(&t1, &t2) {
Ok(t) => t, Ok(t) => t,
Err(ref e) => panic!("unexpected error computing LUB: {}", Err(ref e) => panic!("unexpected error computing LUB: {}",
ty::type_err_to_str(self.infcx.tcx, e)) ty::type_err_to_str(self.infcx.tcx, e))
@ -374,7 +374,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
/// Checks that `t1 <: t2` is true (this may register additional /// Checks that `t1 <: t2` is true (this may register additional
/// region checks). /// region checks).
pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) { pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) {
match self.sub().tys(t1, t2) { match self.sub().relate(&t1, &t2) {
Ok(_) => { } Ok(_) => { }
Err(ref e) => { Err(ref e) => {
panic!("unexpected error computing sub({},{}): {}", panic!("unexpected error computing sub({},{}): {}",
@ -388,7 +388,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
/// Checks that `t1 <: t2` is false (this may register additional /// Checks that `t1 <: t2` is false (this may register additional
/// region checks). /// region checks).
pub fn check_not_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) { pub fn check_not_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) {
match self.sub().tys(t1, t2) { match self.sub().relate(&t1, &t2) {
Err(_) => { } Err(_) => { }
Ok(_) => { Ok(_) => {
panic!("unexpected success computing sub({},{})", panic!("unexpected success computing sub({},{})",
@ -400,7 +400,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
/// Checks that `LUB(t1,t2) == t_lub` /// Checks that `LUB(t1,t2) == t_lub`
pub fn check_lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_lub: Ty<'tcx>) { pub fn check_lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_lub: Ty<'tcx>) {
match self.lub().tys(t1, t2) { match self.lub().relate(&t1, &t2) {
Ok(t) => { Ok(t) => {
self.assert_eq(t, t_lub); self.assert_eq(t, t_lub);
} }
@ -417,7 +417,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
self.ty_to_string(t1), self.ty_to_string(t1),
self.ty_to_string(t2), self.ty_to_string(t2),
self.ty_to_string(t_glb)); self.ty_to_string(t_glb));
match self.glb().tys(t1, t2) { match self.glb().relate(&t1, &t2) {
Err(e) => { Err(e) => {
panic!("unexpected error computing LUB: {:?}", e) panic!("unexpected error computing LUB: {:?}", e)
} }

View file

@ -83,9 +83,7 @@ pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
UnresolvedTypeAction::Error, UnresolvedTypeAction::Error,
LvaluePreference::NoPreference, LvaluePreference::NoPreference,
|adj_ty, idx| { |adj_ty, idx| {
let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None }; try_overloaded_call_step(fcx, call_expr, callee_expr, adj_ty, idx)
try_overloaded_call_step(fcx, call_expr, callee_expr,
adj_ty, autoderefref)
}); });
match result { match result {
@ -119,13 +117,15 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
call_expr: &'tcx ast::Expr, call_expr: &'tcx ast::Expr,
callee_expr: &'tcx ast::Expr, callee_expr: &'tcx ast::Expr,
adjusted_ty: Ty<'tcx>, adjusted_ty: Ty<'tcx>,
autoderefref: ty::AutoDerefRef<'tcx>) autoderefs: usize)
-> Option<CallStep<'tcx>> -> Option<CallStep<'tcx>>
{ {
debug!("try_overloaded_call_step(call_expr={}, adjusted_ty={}, autoderefref={})", debug!("try_overloaded_call_step(call_expr={}, adjusted_ty={}, autoderefs={})",
call_expr.repr(fcx.tcx()), call_expr.repr(fcx.tcx()),
adjusted_ty.repr(fcx.tcx()), adjusted_ty.repr(fcx.tcx()),
autoderefref.repr(fcx.tcx())); autoderefs);
let autoderefref = ty::AutoDerefRef { autoderefs: autoderefs, autoref: None };
// If the callee is a bare function or a closure, then we're all set. // If the callee is a bare function or a closure, then we're all set.
match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty { match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty {
@ -161,6 +161,18 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
} }
} }
// Hack: we know that there are traits implementing Fn for &F
// where F:Fn and so forth. In the particular case of types
// like `x: &mut FnMut()`, if there is a call `x()`, we would
// normally translate to `FnMut::call_mut(&mut x, ())`, but
// that winds up requiring `mut x: &mut FnMut()`. A little
// over the top. The simplest fix by far is to just ignore
// this case and deref again, so we wind up with
// `FnMut::call_mut(&mut *x, ())`.
ty::ty_rptr(..) if autoderefs == 0 => {
return None;
}
_ => {} _ => {}
} }

View file

@ -62,12 +62,11 @@
use check::{autoderef, FnCtxt, NoPreference, PreferMutLvalue, UnresolvedTypeAction}; use check::{autoderef, FnCtxt, NoPreference, PreferMutLvalue, UnresolvedTypeAction};
use middle::infer::{self, cres, Coercion, TypeTrace}; use middle::infer::{self, Coercion};
use middle::infer::combine::Combine;
use middle::infer::sub::Sub;
use middle::subst; use middle::subst;
use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe}; use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe};
use middle::ty::{self, mt, Ty}; use middle::ty::{self, mt, Ty};
use middle::ty_relate::RelateResult;
use util::common::indent; use util::common::indent;
use util::ppaux; use util::ppaux;
use util::ppaux::Repr; use util::ppaux::Repr;
@ -76,10 +75,10 @@ use syntax::ast;
struct Coerce<'a, 'tcx: 'a> { struct Coerce<'a, 'tcx: 'a> {
fcx: &'a FnCtxt<'a, 'tcx>, fcx: &'a FnCtxt<'a, 'tcx>,
trace: TypeTrace<'tcx> origin: infer::TypeOrigin,
} }
type CoerceResult<'tcx> = cres<'tcx, Option<ty::AutoAdjustment<'tcx>>>; type CoerceResult<'tcx> = RelateResult<'tcx, Option<ty::AutoAdjustment<'tcx>>>;
impl<'f, 'tcx> Coerce<'f, 'tcx> { impl<'f, 'tcx> Coerce<'f, 'tcx> {
fn tcx(&self) -> &ty::ctxt<'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> {
@ -87,14 +86,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
} }
fn subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { fn subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
let sub = Sub(self.fcx.infcx().combine_fields(false, self.trace.clone())); try!(self.fcx.infcx().sub_types(false, self.origin.clone(), a, b));
try!(sub.tys(a, b));
Ok(None) // No coercion required. Ok(None) // No coercion required.
} }
fn outlives(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ()> { fn outlives(&self,
let sub = Sub(self.fcx.infcx().combine_fields(false, self.trace.clone())); origin: infer::SubregionOrigin<'tcx>,
try!(sub.regions(b, a)); a: ty::Region,
b: ty::Region)
-> RelateResult<'tcx, ()> {
infer::mk_subr(self.fcx.infcx(), origin, b, a);
Ok(()) Ok(())
} }
@ -190,7 +191,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
_ => return self.subtype(a, b) _ => return self.subtype(a, b)
} }
let coercion = Coercion(self.trace.clone()); let coercion = Coercion(self.origin.span());
let r_borrow = self.fcx.infcx().next_region_var(coercion); let r_borrow = self.fcx.infcx().next_region_var(coercion);
let autoref = Some(AutoPtr(r_borrow, mutbl_b, None)); let autoref = Some(AutoPtr(r_borrow, mutbl_b, None));
@ -214,7 +215,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
} }
let ty = ty::mk_rptr(self.tcx(), r_borrow, let ty = ty::mk_rptr(self.tcx(), r_borrow,
mt {ty: inner_ty, mutbl: mutbl_b}); mt {ty: inner_ty, mutbl: mutbl_b});
if let Err(err) = self.fcx.infcx().try(|_| self.subtype(ty, b)) { if let Err(err) = self.subtype(ty, b) {
if first_error.is_none() { if first_error.is_none() {
first_error = Some(err); first_error = Some(err);
} }
@ -264,12 +265,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
return Err(ty::terr_mutability); return Err(ty::terr_mutability);
} }
let coercion = Coercion(self.trace.clone()); let coercion = Coercion(self.origin.span());
let r_borrow = self.fcx.infcx().next_region_var(coercion); let r_borrow = self.fcx.infcx().next_region_var(coercion);
let ty = ty::mk_rptr(self.tcx(), let ty = ty::mk_rptr(self.tcx(),
self.tcx().mk_region(r_borrow), self.tcx().mk_region(r_borrow),
ty::mt{ty: ty, mutbl: mt_b.mutbl}); ty::mt{ty: ty, mutbl: mt_b.mutbl});
try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); try!(self.subtype(ty, b));
debug!("Success, coerced with AutoDerefRef(1, \ debug!("Success, coerced with AutoDerefRef(1, \
AutoPtr(AutoUnsize({:?})))", kind); AutoPtr(AutoUnsize({:?})))", kind);
Ok(Some(AdjustDerefRef(AutoDerefRef { Ok(Some(AdjustDerefRef(AutoDerefRef {
@ -290,7 +291,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
let ty = ty::mk_ptr(self.tcx(), let ty = ty::mk_ptr(self.tcx(),
ty::mt{ty: ty, mutbl: mt_b.mutbl}); ty::mt{ty: ty, mutbl: mt_b.mutbl});
try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); try!(self.subtype(ty, b));
debug!("Success, coerced with AutoDerefRef(1, \ debug!("Success, coerced with AutoDerefRef(1, \
AutoPtr(AutoUnsize({:?})))", kind); AutoPtr(AutoUnsize({:?})))", kind);
Ok(Some(AdjustDerefRef(AutoDerefRef { Ok(Some(AdjustDerefRef(AutoDerefRef {
@ -306,7 +307,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
match self.unsize_ty(t_a, t_b) { match self.unsize_ty(t_a, t_b) {
Some((ty, kind)) => { Some((ty, kind)) => {
let ty = ty::mk_uniq(self.tcx(), ty); let ty = ty::mk_uniq(self.tcx(), ty);
try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); try!(self.subtype(ty, b));
debug!("Success, coerced with AutoDerefRef(1, \ debug!("Success, coerced with AutoDerefRef(1, \
AutoUnsizeUniq({:?}))", kind); AutoUnsizeUniq({:?}))", kind);
Ok(Some(AdjustDerefRef(AutoDerefRef { Ok(Some(AdjustDerefRef(AutoDerefRef {
@ -365,9 +366,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1); let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1);
// relate `a1` to `b` // relate `a1` to `b`
let result = self.fcx.infcx().try(|_| { let result = self.fcx.infcx().commit_if_ok(|_| {
// it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b // it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b
try!(self.outlives(data_a.bounds.region_bound, try!(self.outlives(infer::RelateObjectBound(self.origin.span()),
data_a.bounds.region_bound,
data_b.bounds.region_bound)); data_b.bounds.region_bound));
self.subtype(ty_a1, ty_b) self.subtype(ty_a1, ty_b)
}); });
@ -399,7 +401,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
let mut result = None; let mut result = None;
let tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate(); let tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate();
for (i, (tp_a, tp_b)) in tps { for (i, (tp_a, tp_b)) in tps {
if self.fcx.infcx().try(|_| self.subtype(*tp_a, *tp_b)).is_ok() { if self.subtype(*tp_a, *tp_b).is_ok() {
continue; continue;
} }
match self.unsize_ty(*tp_a, *tp_b) { match self.unsize_ty(*tp_a, *tp_b) {
@ -408,7 +410,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
let mut new_substs = substs_a.clone(); let mut new_substs = substs_a.clone();
new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp; new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp;
let ty = ty::mk_struct(tcx, did_a, tcx.mk_substs(new_substs)); let ty = ty::mk_struct(tcx, did_a, tcx.mk_substs(new_substs));
if self.fcx.infcx().try(|_| self.subtype(ty, ty_b)).is_err() { if self.subtype(ty, ty_b).is_err() {
debug!("Unsized type parameter '{}', but still \ debug!("Unsized type parameter '{}', but still \
could not match types {} and {}", could not match types {} and {}",
ppaux::ty_to_string(tcx, *tp_a), ppaux::ty_to_string(tcx, *tp_a),
@ -534,14 +536,13 @@ pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
expr: &ast::Expr, expr: &ast::Expr,
a: Ty<'tcx>, a: Ty<'tcx>,
b: Ty<'tcx>) b: Ty<'tcx>)
-> cres<'tcx, ()> { -> RelateResult<'tcx, ()> {
debug!("mk_assignty({} -> {})", a.repr(fcx.tcx()), b.repr(fcx.tcx())); debug!("mk_assignty({} -> {})", a.repr(fcx.tcx()), b.repr(fcx.tcx()));
let adjustment = try!(indent(|| { let adjustment = try!(indent(|| {
fcx.infcx().commit_if_ok(|| { fcx.infcx().commit_if_ok(|_| {
let origin = infer::ExprAssignable(expr.span);
Coerce { Coerce {
fcx: fcx, fcx: fcx,
trace: infer::TypeTrace::types(origin, false, a, b) origin: infer::ExprAssignable(expr.span),
}.coerce(expr, a, b) }.coerce(expr, a, b)
}) })
})); }));

View file

@ -282,7 +282,7 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
let trait_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(trait_m.fty.clone())); let trait_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(trait_m.fty.clone()));
let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs); let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs);
let err = infcx.try(|snapshot| { let err = infcx.commit_if_ok(|snapshot| {
let origin = infer::MethodCompatCheck(impl_m_span); let origin = infer::MethodCompatCheck(impl_m_span);
let (impl_sig, _) = let (impl_sig, _) =

View file

@ -95,7 +95,7 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
ty::lookup_item_type(tcx, self_type_did); ty::lookup_item_type(tcx, self_type_did);
let infcx = infer::new_infer_ctxt(tcx); let infcx = infer::new_infer_ctxt(tcx);
infcx.try(|snapshot| { infcx.commit_if_ok(|snapshot| {
let (named_type_to_skolem, skol_map) = let (named_type_to_skolem, skol_map) =
infcx.construct_skolemized_subst(named_type_generics, snapshot); infcx.construct_skolemized_subst(named_type_generics, snapshot);
let named_type_skolem = named_type.subst(tcx, &named_type_to_skolem); let named_type_skolem = named_type.subst(tcx, &named_type_to_skolem);

View file

@ -1130,7 +1130,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// MISCELLANY // MISCELLANY
fn make_sub_ty(&self, sub: Ty<'tcx>, sup: Ty<'tcx>) -> infer::ures<'tcx> { fn make_sub_ty(&self, sub: Ty<'tcx>, sup: Ty<'tcx>) -> infer::UnitResult<'tcx> {
self.infcx().sub_types(false, infer::Misc(DUMMY_SP), sub, sup) self.infcx().sub_types(false, infer::Misc(DUMMY_SP), sub, sup)
} }

View file

@ -1542,7 +1542,7 @@ fn projection_bounds<'a,'tcx>(rcx: &Rcx<'a, 'tcx>,
debug!("projection_bounds: outlives={} (2)", debug!("projection_bounds: outlives={} (2)",
outlives.repr(tcx)); outlives.repr(tcx));
let region_result = infcx.try(|_| { let region_result = infcx.commit_if_ok(|_| {
let (outlives, _) = let (outlives, _) =
infcx.replace_late_bound_regions_with_fresh_var( infcx.replace_late_bound_regions_with_fresh_var(
span, span,

View file

@ -30,7 +30,6 @@ use middle::ty::{ty_uint, ty_closure, ty_uniq, ty_bare_fn};
use middle::ty::ty_projection; use middle::ty::ty_projection;
use middle::ty; use middle::ty;
use CrateCtxt; use CrateCtxt;
use middle::infer::combine::Combine;
use middle::infer::InferCtxt; use middle::infer::InferCtxt;
use middle::infer::new_infer_ctxt; use middle::infer::new_infer_ctxt;
use std::collections::HashSet; use std::collections::HashSet;

View file

@ -23,10 +23,6 @@ pub fn main() {
let f2: &Fat<[isize; 3]> = &f1; let f2: &Fat<[isize; 3]> = &f1;
let f3: &Fat<[usize]> = f2; let f3: &Fat<[usize]> = f2;
//~^ ERROR mismatched types //~^ ERROR mismatched types
//~| expected `&Fat<[usize]>`
//~| found `&Fat<[isize; 3]>`
//~| expected usize
//~| found isize
// With a trait. // With a trait.
let f1 = Fat { ptr: Foo }; let f1 = Fat { ptr: Foo };

View file

@ -81,8 +81,8 @@ fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait {
// which fails to type check. // which fails to type check.
ss ss
//~^ ERROR cannot infer //~^ ERROR lifetime of the source pointer does not outlive lifetime bound
//~| ERROR mismatched types //~| ERROR cannot infer
} }
fn main() { fn main() {

View file

@ -25,7 +25,7 @@ fn load(ss: &mut SomeStruct) -> Box<SomeTrait> {
// `Box<SomeTrait>` defaults to a `'static` bound, so this return // `Box<SomeTrait>` defaults to a `'static` bound, so this return
// is illegal. // is illegal.
ss.r //~ ERROR mismatched types ss.r //~ ERROR lifetime of the source pointer does not outlive lifetime bound
} }
fn store(ss: &mut SomeStruct, b: Box<SomeTrait>) { fn store(ss: &mut SomeStruct, b: Box<SomeTrait>) {
@ -38,7 +38,7 @@ fn store(ss: &mut SomeStruct, b: Box<SomeTrait>) {
fn store1<'b>(ss: &mut SomeStruct, b: Box<SomeTrait+'b>) { fn store1<'b>(ss: &mut SomeStruct, b: Box<SomeTrait+'b>) {
// Here we override the lifetimes explicitly, and so naturally we get an error. // Here we override the lifetimes explicitly, and so naturally we get an error.
ss.r = b; //~ ERROR mismatched types ss.r = b; //~ ERROR lifetime of the source pointer does not outlive lifetime bound
} }
fn main() { fn main() {

View file

@ -27,7 +27,7 @@ fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box<SomeTrait+'b> {
fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<SomeTrait+'c> { fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<SomeTrait+'c> {
// A outlives 'a AND 'b...but not 'c. // A outlives 'a AND 'b...but not 'c.
box v as Box<SomeTrait+'a> //~ ERROR mismatched types box v as Box<SomeTrait+'a> //~ ERROR lifetime of the source pointer does not outlive
} }
fn main() { fn main() {

View file

@ -22,7 +22,7 @@ fn foo2<'a:'b,'b>(x: &'b mut (Dummy+'a)) -> &'b mut (Dummy+'b) {
fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy { fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy {
// Without knowing 'a:'b, we can't coerce // Without knowing 'a:'b, we can't coerce
x //~ ERROR mismatched types x //~ ERROR lifetime of the source pointer does not outlive
//~^ ERROR cannot infer //~^ ERROR cannot infer
} }

View file

@ -0,0 +1,37 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that you can supply `&F` where `F: FnMut()`.
// pretty-expanded FIXME #23616
#![feature(lang_items, unboxed_closures)]
fn a<F:FnMut() -> i32>(mut f: F) -> i32 {
f()
}
fn b(f: &mut FnMut() -> i32) -> i32 {
a(f)
}
fn c<F:FnMut() -> i32>(f: &mut F) -> i32 {
a(f)
}
fn main() {
let z: isize = 7;
let x = b(&mut || 22);
assert_eq!(x, 22);
let x = c(&mut || 22);
assert_eq!(x, 22);
}

View file

@ -0,0 +1,37 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that you can supply `&F` where `F: Fn()`.
// pretty-expanded FIXME #23616
#![feature(lang_items, unboxed_closures)]
fn a<F:Fn() -> i32>(f: F) -> i32 {
f()
}
fn b(f: &Fn() -> i32) -> i32 {
a(f)
}
fn c<F:Fn() -> i32>(f: &F) -> i32 {
a(f)
}
fn main() {
let z: isize = 7;
let x = b(&|| 22);
assert_eq!(x, 22);
let x = c(&|| 22);
assert_eq!(x, 22);
}