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:
commit
debac97a10
35 changed files with 1635 additions and 1278 deletions
|
@ -1145,3 +1145,52 @@ pub trait FnOnce<Args> {
|
|||
/// This is called when the call operator is used.
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -120,6 +120,8 @@ pub mod middle {
|
|||
pub mod traits;
|
||||
pub mod ty;
|
||||
pub mod ty_fold;
|
||||
pub mod ty_match;
|
||||
pub mod ty_relate;
|
||||
pub mod ty_walk;
|
||||
pub mod weak_lang_items;
|
||||
}
|
||||
|
|
|
@ -25,66 +25,54 @@
|
|||
//! In particular, it might be enough to say (A,B) are bivariant for
|
||||
//! 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::TyVar;
|
||||
use middle::infer::combine::*;
|
||||
use middle::infer::cres;
|
||||
use middle::infer::type_variable::BiTo;
|
||||
use util::ppaux::Repr;
|
||||
use middle::ty_relate::{Relate, RelateResult, TypeRelation};
|
||||
use util::ppaux::{Repr};
|
||||
|
||||
pub struct Bivariate<'f, 'tcx: 'f> {
|
||||
fields: CombineFields<'f, 'tcx>
|
||||
pub struct Bivariate<'a, 'tcx: 'a> {
|
||||
fields: CombineFields<'a, 'tcx>
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Bivariate<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Bivariate<'f, 'tcx> {
|
||||
Bivariate { fields: cf }
|
||||
impl<'a, 'tcx> Bivariate<'a, 'tcx> {
|
||||
pub fn new(fields: CombineFields<'a, 'tcx>) -> Bivariate<'a, 'tcx> {
|
||||
Bivariate { fields: fields }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'f, 'tcx> Combine<'tcx> for Bivariate<'f, 'tcx> {
|
||||
fn tag(&self) -> String { "Bivariate".to_string() }
|
||||
fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
|
||||
impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Bivariate<'a, 'tcx> {
|
||||
fn tag(&self) -> &'static str { "Bivariate" }
|
||||
|
||||
fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
|
||||
-> cres<'tcx, Ty<'tcx>>
|
||||
fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.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 {
|
||||
ty::Invariant => self.equate().tys(a, b),
|
||||
ty::Covariant => self.tys(a, b),
|
||||
ty::Contravariant => self.tys(a, b),
|
||||
ty::Bivariant => self.tys(a, b),
|
||||
match variance {
|
||||
// If we have Foo<A> and Foo is invariant w/r/t A,
|
||||
// and we want to assert that
|
||||
//
|
||||
// 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)
|
||||
-> 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>> {
|
||||
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
debug!("{}.tys({}, {})", self.tag(),
|
||||
a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
|
||||
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>>
|
||||
where T : Combineable<'tcx>
|
||||
fn regions(&mut self, a: ty::Region, _: ty::Region) -> RelateResult<'tcx, ty::Region> {
|
||||
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 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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,395 +37,21 @@ use super::equate::Equate;
|
|||
use super::glb::Glb;
|
||||
use super::lub::Lub;
|
||||
use super::sub::Sub;
|
||||
use super::unify::InferCtxtMethodsForSimplyUnifiableTypes;
|
||||
use super::{InferCtxt, cres};
|
||||
use super::{InferCtxt};
|
||||
use super::{MiscVariable, TypeTrace};
|
||||
use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf};
|
||||
|
||||
use middle::subst;
|
||||
use middle::subst::{ErasedRegions, NonerasedRegions, Substs};
|
||||
use middle::ty::{FloatVar, FnSig, IntVar, TyVar};
|
||||
use middle::ty::{TyVar};
|
||||
use middle::ty::{IntType, UintType};
|
||||
use middle::ty::BuiltinBounds;
|
||||
use middle::ty::{self, Ty};
|
||||
use middle::ty_fold;
|
||||
use middle::ty_fold::{TypeFolder, TypeFoldable};
|
||||
use middle::ty_relate::{self, Relate, RelateResult, TypeRelation};
|
||||
use util::ppaux::Repr;
|
||||
|
||||
use std::rc::Rc;
|
||||
use syntax::ast::Unsafety;
|
||||
use syntax::ast;
|
||||
use syntax::abi;
|
||||
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)]
|
||||
pub struct CombineFields<'a, 'tcx: 'a> {
|
||||
pub infcx: &'a InferCtxt<'a, 'tcx>,
|
||||
|
@ -433,234 +59,133 @@ pub struct CombineFields<'a, 'tcx: 'a> {
|
|||
pub trace: TypeTrace<'tcx>,
|
||||
}
|
||||
|
||||
pub fn expected_found<'tcx, C, T>(this: &C,
|
||||
a: T,
|
||||
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>,
|
||||
b: Ty<'tcx>)
|
||||
-> cres<'tcx, Ty<'tcx>>
|
||||
where C: Combine<'tcx> {
|
||||
let tcx = this.infcx().tcx;
|
||||
let a_sty = &a.sty;
|
||||
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),
|
||||
pub fn super_combine_tys<'a,'tcx:'a,R>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
relation: &mut R,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>)
|
||||
-> RelateResult<'tcx, Ty<'tcx>>
|
||||
where R: TypeRelation<'a,'tcx>
|
||||
{
|
||||
let a_is_expected = relation.a_is_expected();
|
||||
|
||||
match (&a.sty, &b.sty) {
|
||||
// Relate integral variables to other types
|
||||
(&ty::ty_infer(IntVar(a_id)), &ty::ty_infer(IntVar(b_id))) => {
|
||||
try!(this.infcx().simple_vars(this.a_is_expected(),
|
||||
a_id, b_id));
|
||||
(&ty::ty_infer(ty::IntVar(a_id)), &ty::ty_infer(ty::IntVar(b_id))) => {
|
||||
try!(infcx.int_unification_table
|
||||
.borrow_mut()
|
||||
.unify_var_var(a_id, b_id)
|
||||
.map_err(|e| int_unification_error(a_is_expected, e)));
|
||||
Ok(a)
|
||||
}
|
||||
(&ty::ty_infer(IntVar(v_id)), &ty::ty_int(v)) => {
|
||||
unify_integral_variable(this, this.a_is_expected(),
|
||||
v_id, IntType(v))
|
||||
(&ty::ty_infer(ty::IntVar(v_id)), &ty::ty_int(v)) => {
|
||||
unify_integral_variable(infcx, a_is_expected, v_id, IntType(v))
|
||||
}
|
||||
(&ty::ty_int(v), &ty::ty_infer(IntVar(v_id))) => {
|
||||
unify_integral_variable(this, !this.a_is_expected(),
|
||||
v_id, IntType(v))
|
||||
(&ty::ty_int(v), &ty::ty_infer(ty::IntVar(v_id))) => {
|
||||
unify_integral_variable(infcx, !a_is_expected, v_id, IntType(v))
|
||||
}
|
||||
(&ty::ty_infer(IntVar(v_id)), &ty::ty_uint(v)) => {
|
||||
unify_integral_variable(this, this.a_is_expected(),
|
||||
v_id, UintType(v))
|
||||
(&ty::ty_infer(ty::IntVar(v_id)), &ty::ty_uint(v)) => {
|
||||
unify_integral_variable(infcx, a_is_expected, v_id, UintType(v))
|
||||
}
|
||||
(&ty::ty_uint(v), &ty::ty_infer(IntVar(v_id))) => {
|
||||
unify_integral_variable(this, !this.a_is_expected(),
|
||||
v_id, UintType(v))
|
||||
(&ty::ty_uint(v), &ty::ty_infer(ty::IntVar(v_id))) => {
|
||||
unify_integral_variable(infcx, !a_is_expected, v_id, UintType(v))
|
||||
}
|
||||
|
||||
// Relate floating-point variables to other types
|
||||
(&ty::ty_infer(FloatVar(a_id)), &ty::ty_infer(FloatVar(b_id))) => {
|
||||
try!(this.infcx().simple_vars(this.a_is_expected(), a_id, b_id));
|
||||
(&ty::ty_infer(ty::FloatVar(a_id)), &ty::ty_infer(ty::FloatVar(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)
|
||||
}
|
||||
(&ty::ty_infer(FloatVar(v_id)), &ty::ty_float(v)) => {
|
||||
unify_float_variable(this, this.a_is_expected(), v_id, v)
|
||||
(&ty::ty_infer(ty::FloatVar(v_id)), &ty::ty_float(v)) => {
|
||||
unify_float_variable(infcx, a_is_expected, v_id, v)
|
||||
}
|
||||
(&ty::ty_float(v), &ty::ty_infer(FloatVar(v_id))) => {
|
||||
unify_float_variable(this, !this.a_is_expected(), v_id, v)
|
||||
(&ty::ty_float(v), &ty::ty_infer(ty::FloatVar(v_id))) => {
|
||||
unify_float_variable(infcx, !a_is_expected, v_id, v)
|
||||
}
|
||||
|
||||
(&ty::ty_char, _)
|
||||
| (&ty::ty_bool, _)
|
||||
| (&ty::ty_int(_), _)
|
||||
| (&ty::ty_uint(_), _)
|
||||
| (&ty::ty_float(_), _) => {
|
||||
if a == b {
|
||||
Ok(a)
|
||||
} else {
|
||||
Err(ty::terr_sorts(expected_found(this, a, b)))
|
||||
}
|
||||
// All other cases of inference are errors
|
||||
(&ty::ty_infer(_), _) |
|
||||
(_, &ty::ty_infer(_)) => {
|
||||
Err(ty::terr_sorts(ty_relate::expected_found(relation, &a, &b)))
|
||||
}
|
||||
|
||||
(&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!(this.substs(a_id, a_substs, b_substs));
|
||||
Ok(ty::mk_enum(tcx, a_id, tcx.mk_substs(substs)))
|
||||
_ => {
|
||||
ty_relate::super_relate_tys(relation, a, b)
|
||||
}
|
||||
|
||||
(&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: ty::IntVid,
|
||||
val: ty::IntVarValue)
|
||||
-> cres<'tcx, Ty<'tcx>>
|
||||
where C: Combine<'tcx> {
|
||||
try!(this.infcx().simple_var_t(vid_is_expected, vid, val));
|
||||
match val {
|
||||
IntType(v) => Ok(ty::mk_mach_int(this.tcx(), v)),
|
||||
UintType(v) => Ok(ty::mk_mach_uint(this.tcx(), v)),
|
||||
}
|
||||
}
|
||||
|
||||
fn unify_float_variable<'tcx, C>(this: &C,
|
||||
vid_is_expected: bool,
|
||||
vid: ty::FloatVid,
|
||||
val: ast::FloatTy)
|
||||
-> cres<'tcx, Ty<'tcx>>
|
||||
where C: Combine<'tcx> {
|
||||
try!(this.infcx().simple_var_t(vid_is_expected, vid, val));
|
||||
Ok(ty::mk_mach_float(this.tcx(), val))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'f, 'tcx> CombineFields<'f, 'tcx> {
|
||||
pub fn switch_expected(&self) -> CombineFields<'f, 'tcx> {
|
||||
fn unify_integral_variable<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
||||
vid_is_expected: bool,
|
||||
vid: ty::IntVid,
|
||||
val: ty::IntVarValue)
|
||||
-> RelateResult<'tcx, Ty<'tcx>>
|
||||
{
|
||||
try!(infcx
|
||||
.int_unification_table
|
||||
.borrow_mut()
|
||||
.unify_var_value(vid, val)
|
||||
.map_err(|e| int_unification_error(vid_is_expected, e)));
|
||||
match val {
|
||||
IntType(v) => Ok(ty::mk_mach_int(infcx.tcx, v)),
|
||||
UintType(v) => Ok(ty::mk_mach_uint(infcx.tcx, v)),
|
||||
}
|
||||
}
|
||||
|
||||
fn unify_float_variable<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
||||
vid_is_expected: bool,
|
||||
vid: ty::FloatVid,
|
||||
val: ast::FloatTy)
|
||||
-> RelateResult<'tcx, Ty<'tcx>>
|
||||
{
|
||||
try!(infcx
|
||||
.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<'a, 'tcx> CombineFields<'a, 'tcx> {
|
||||
pub fn tcx(&self) -> &'a ty::ctxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
||||
pub fn switch_expected(&self) -> CombineFields<'a, 'tcx> {
|
||||
CombineFields {
|
||||
a_is_expected: !self.a_is_expected,
|
||||
..(*self).clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn equate(&self) -> Equate<'f, 'tcx> {
|
||||
Equate((*self).clone())
|
||||
pub fn equate(&self) -> Equate<'a, 'tcx> {
|
||||
Equate::new(self.clone())
|
||||
}
|
||||
|
||||
fn bivariate(&self) -> Bivariate<'f, 'tcx> {
|
||||
Bivariate((*self).clone())
|
||||
pub fn bivariate(&self) -> Bivariate<'a, 'tcx> {
|
||||
Bivariate::new(self.clone())
|
||||
}
|
||||
|
||||
fn sub(&self) -> Sub<'f, 'tcx> {
|
||||
Sub((*self).clone())
|
||||
pub fn sub(&self) -> Sub<'a, 'tcx> {
|
||||
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,
|
||||
a_ty: Ty<'tcx>,
|
||||
dir: RelationDir,
|
||||
b_vid: ty::TyVid)
|
||||
-> cres<'tcx, ()>
|
||||
-> RelateResult<'tcx, ()>
|
||||
{
|
||||
let tcx = self.infcx.tcx;
|
||||
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
|
||||
// to associate causes/spans with each of the relations in
|
||||
// the stack to get this right.
|
||||
match dir {
|
||||
BiTo => try!(self.bivariate().tys(a_ty, b_ty)),
|
||||
|
||||
EqTo => try!(self.equate().tys(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)),
|
||||
};
|
||||
try!(match dir {
|
||||
BiTo => self.bivariate().relate(&a_ty, &b_ty),
|
||||
EqTo => self.equate().relate(&a_ty, &b_ty),
|
||||
SubtypeOf => self.sub().relate(&a_ty, &b_ty),
|
||||
SupertypeOf => self.sub().relate_with_variance(ty::Contravariant, &a_ty, &b_ty),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -746,7 +268,7 @@ impl<'f, 'tcx> CombineFields<'f, 'tcx> {
|
|||
ty: Ty<'tcx>,
|
||||
for_vid: ty::TyVid,
|
||||
make_region_vars: bool)
|
||||
-> cres<'tcx, Ty<'tcx>>
|
||||
-> RelateResult<'tcx, Ty<'tcx>>
|
||||
{
|
||||
let mut generalize = Generalizer {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
|
|
@ -8,51 +8,43 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// 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::TyVar;
|
||||
use middle::infer::combine::*;
|
||||
use middle::infer::cres;
|
||||
use middle::infer::Subtype;
|
||||
use middle::infer::type_variable::EqTo;
|
||||
use util::ppaux::Repr;
|
||||
use middle::ty_relate::{Relate, RelateResult, TypeRelation};
|
||||
use util::ppaux::{Repr};
|
||||
|
||||
pub struct Equate<'f, 'tcx: 'f> {
|
||||
fields: CombineFields<'f, 'tcx>
|
||||
pub struct Equate<'a, 'tcx: 'a> {
|
||||
fields: CombineFields<'a, 'tcx>
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Equate<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Equate<'f, 'tcx> {
|
||||
Equate { fields: cf }
|
||||
impl<'a, 'tcx> Equate<'a, 'tcx> {
|
||||
pub fn new(fields: CombineFields<'a, 'tcx>) -> Equate<'a, 'tcx> {
|
||||
Equate { fields: fields }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'f, 'tcx> Combine<'tcx> for Equate<'f, 'tcx> {
|
||||
fn tag(&self) -> String { "Equate".to_string() }
|
||||
fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
|
||||
impl<'a, 'tcx> TypeRelation<'a,'tcx> for Equate<'a, 'tcx> {
|
||||
fn tag(&self) -> &'static str { "Equate" }
|
||||
|
||||
fn tys_with_variance(&self, _: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
|
||||
-> cres<'tcx, Ty<'tcx>>
|
||||
fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.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.tys(a, b)
|
||||
self.relate(a, b)
|
||||
}
|
||||
|
||||
fn regions_with_variance(&self, _: ty::Variance, a: ty::Region, b: ty::Region)
|
||||
-> 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>> {
|
||||
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
debug!("{}.tys({}, {})", self.tag(),
|
||||
a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
|
||||
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>>
|
||||
where T : Combineable<'tcx>
|
||||
fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
|
||||
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));
|
||||
self.sub().binders(b, a)
|
||||
try!(self.fields.higher_ranked_sub(a, b));
|
||||
self.fields.higher_ranked_sub(b, a)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ use middle::ty_fold::TypeFolder;
|
|||
use std::collections::hash_map::{self, Entry};
|
||||
|
||||
use super::InferCtxt;
|
||||
use super::unify::InferCtxtMethodsForSimplyUnifiableTypes;
|
||||
use super::unify::ToType;
|
||||
|
||||
pub struct TypeFreshener<'a, 'tcx:'a> {
|
||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||
|
@ -104,29 +104,38 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||
let tcx = self.infcx.tcx;
|
||||
|
||||
match t.sty {
|
||||
ty::ty_infer(ty::TyVar(v)) => {
|
||||
self.freshen(self.infcx.type_variables.borrow().probe(v),
|
||||
ty::TyVar(v),
|
||||
ty::FreshTy)
|
||||
self.freshen(
|
||||
self.infcx.type_variables.borrow().probe(v),
|
||||
ty::TyVar(v),
|
||||
ty::FreshTy)
|
||||
}
|
||||
|
||||
ty::ty_infer(ty::IntVar(v)) => {
|
||||
self.freshen(self.infcx.probe_var(v),
|
||||
ty::IntVar(v),
|
||||
ty::FreshIntTy)
|
||||
self.freshen(
|
||||
self.infcx.int_unification_table.borrow_mut()
|
||||
.probe(v)
|
||||
.map(|v| v.to_type(tcx)),
|
||||
ty::IntVar(v),
|
||||
ty::FreshIntTy)
|
||||
}
|
||||
|
||||
ty::ty_infer(ty::FloatVar(v)) => {
|
||||
self.freshen(self.infcx.probe_var(v),
|
||||
ty::FloatVar(v),
|
||||
ty::FreshIntTy)
|
||||
self.freshen(
|
||||
self.infcx.float_unification_table.borrow_mut()
|
||||
.probe(v)
|
||||
.map(|v| v.to_type(tcx)),
|
||||
ty::FloatVar(v),
|
||||
ty::FreshIntTy)
|
||||
}
|
||||
|
||||
ty::ty_infer(ty::FreshTy(c)) |
|
||||
ty::ty_infer(ty::FreshIntTy(c)) => {
|
||||
if c >= self.freshen_count {
|
||||
self.tcx().sess.bug(
|
||||
tcx.sess.bug(
|
||||
&format!("Encountered a freshend type with id {} \
|
||||
but our counter is only at {}",
|
||||
c,
|
||||
|
|
|
@ -8,67 +8,79 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use super::combine::*;
|
||||
use super::lattice::*;
|
||||
use super::combine::CombineFields;
|
||||
use super::higher_ranked::HigherRankedRelations;
|
||||
use super::cres;
|
||||
use super::InferCtxt;
|
||||
use super::lattice::{self, LatticeDir};
|
||||
use super::Subtype;
|
||||
|
||||
use middle::ty::{self, Ty};
|
||||
use middle::ty_relate::{Relate, RelateResult, TypeRelation};
|
||||
use util::ppaux::Repr;
|
||||
|
||||
/// "Greatest lower bound" (common subtype)
|
||||
pub struct Glb<'f, 'tcx: 'f> {
|
||||
fields: CombineFields<'f, 'tcx>
|
||||
pub struct Glb<'a, 'tcx: 'a> {
|
||||
fields: CombineFields<'a, 'tcx>
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Glb<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Glb<'f, 'tcx> {
|
||||
Glb { fields: cf }
|
||||
impl<'a, 'tcx> Glb<'a, 'tcx> {
|
||||
pub fn new(fields: CombineFields<'a, 'tcx>) -> Glb<'a, 'tcx> {
|
||||
Glb { fields: fields }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> {
|
||||
fn tag(&self) -> String { "Glb".to_string() }
|
||||
fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
|
||||
impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Glb<'a, 'tcx> {
|
||||
fn tag(&self) -> &'static str { "Glb" }
|
||||
|
||||
fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
|
||||
-> cres<'tcx, Ty<'tcx>>
|
||||
fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.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 {
|
||||
ty::Invariant => self.equate().tys(a, b),
|
||||
ty::Covariant => self.tys(a, b),
|
||||
ty::Bivariant => self.bivariate().tys(a, b),
|
||||
ty::Contravariant => self.lub().tys(a, b),
|
||||
match variance {
|
||||
ty::Invariant => self.fields.equate().relate(a, b),
|
||||
ty::Covariant => self.relate(a, b),
|
||||
ty::Bivariant => self.fields.bivariate().relate(a, b),
|
||||
ty::Contravariant => self.fields.lub().relate(a, b),
|
||||
}
|
||||
}
|
||||
|
||||
fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region)
|
||||
-> cres<'tcx, ty::Region>
|
||||
{
|
||||
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 tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
lattice::super_lattice_tys(self, 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({}, {})",
|
||||
self.tag(),
|
||||
a.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>> {
|
||||
super_lattice_tys(self, a, b)
|
||||
}
|
||||
|
||||
fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>>
|
||||
where T : Combineable<'tcx>
|
||||
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_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(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,25 +11,26 @@
|
|||
//! Helper routines for higher-ranked things. See the `doc` module at
|
||||
//! the end of the file for details.
|
||||
|
||||
use super::{CombinedSnapshot, cres, InferCtxt, HigherRankedType, SkolemizationMap};
|
||||
use super::combine::{Combine, Combineable};
|
||||
use super::{CombinedSnapshot, InferCtxt, HigherRankedType, SkolemizationMap};
|
||||
use super::combine::CombineFields;
|
||||
|
||||
use middle::subst;
|
||||
use middle::ty::{self, Binder};
|
||||
use middle::ty_fold::{self, TypeFoldable};
|
||||
use middle::ty_relate::{Relate, RelateResult, TypeRelation};
|
||||
use syntax::codemap::Span;
|
||||
use util::nodemap::{FnvHashMap, FnvHashSet};
|
||||
use util::ppaux::Repr;
|
||||
|
||||
pub trait HigherRankedRelations<'tcx> {
|
||||
fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binder<T>>
|
||||
where T : Combineable<'tcx>;
|
||||
pub trait HigherRankedRelations<'a,'tcx> {
|
||||
fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> RelateResult<'tcx, Binder<T>>
|
||||
where T: Relate<'a,'tcx>;
|
||||
|
||||
fn higher_ranked_lub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binder<T>>
|
||||
where T : Combineable<'tcx>;
|
||||
fn higher_ranked_lub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> RelateResult<'tcx, Binder<T>>
|
||||
where T: Relate<'a,'tcx>;
|
||||
|
||||
fn higher_ranked_glb<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binder<T>>
|
||||
where T : Combineable<'tcx>;
|
||||
fn higher_ranked_glb<T>(&self, a: &Binder<T>, b: &Binder<T>) -> RelateResult<'tcx, Binder<T>>
|
||||
where T: Relate<'a,'tcx>;
|
||||
}
|
||||
|
||||
trait InferCtxtExt {
|
||||
|
@ -40,15 +41,15 @@ trait InferCtxtExt {
|
|||
-> Vec<ty::RegionVid>;
|
||||
}
|
||||
|
||||
impl<'tcx,C> HigherRankedRelations<'tcx> for C
|
||||
where C : Combine<'tcx>
|
||||
{
|
||||
impl<'a,'tcx> HigherRankedRelations<'a,'tcx> for CombineFields<'a,'tcx> {
|
||||
fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>)
|
||||
-> cres<'tcx, Binder<T>>
|
||||
where T : Combineable<'tcx>
|
||||
-> RelateResult<'tcx, Binder<T>>
|
||||
where T: Relate<'a,'tcx>
|
||||
{
|
||||
let tcx = self.infcx.tcx;
|
||||
|
||||
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`
|
||||
// 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
|
||||
// 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
|
||||
// region variable.
|
||||
let (a_prime, _) =
|
||||
self.infcx().replace_late_bound_regions_with_fresh_var(
|
||||
self.trace().origin.span(),
|
||||
self.infcx.replace_late_bound_regions_with_fresh_var(
|
||||
self.trace.origin.span(),
|
||||
HigherRankedType,
|
||||
a);
|
||||
|
||||
// Second, we instantiate each bound region in the supertype with a
|
||||
// fresh concrete region.
|
||||
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!("b_prime={}", b_prime.repr(self.tcx()));
|
||||
debug!("a_prime={}", a_prime.repr(tcx));
|
||||
debug!("b_prime={}", b_prime.repr(tcx));
|
||||
|
||||
// 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
|
||||
// that the skolemized regions do not "leak".
|
||||
match leak_check(self.infcx(), &skol_map, snapshot) {
|
||||
match leak_check(self.infcx, &skol_map, snapshot) {
|
||||
Ok(()) => { }
|
||||
Err((skol_br, tainted_region)) => {
|
||||
if self.a_is_expected() {
|
||||
if self.a_is_expected {
|
||||
debug!("Not as polymorphic!");
|
||||
return Err(ty::terr_regions_insufficiently_polymorphic(skol_br,
|
||||
tainted_region));
|
||||
|
@ -98,42 +99,42 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C
|
|||
}
|
||||
|
||||
debug!("higher_ranked_sub: OK result={}",
|
||||
result.repr(self.tcx()));
|
||||
result.repr(tcx));
|
||||
|
||||
Ok(ty::Binder(result))
|
||||
});
|
||||
}
|
||||
|
||||
fn higher_ranked_lub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binder<T>>
|
||||
where T : Combineable<'tcx>
|
||||
fn higher_ranked_lub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> RelateResult<'tcx, Binder<T>>
|
||||
where T: Relate<'a,'tcx>
|
||||
{
|
||||
// Start a snapshot so we can examine "all bindings that were
|
||||
// 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.
|
||||
let span = self.trace().origin.span();
|
||||
let span = self.trace.origin.span();
|
||||
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);
|
||||
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);
|
||||
|
||||
// Collect constraints.
|
||||
let result0 =
|
||||
try!(Combineable::combine(self, &a_with_fresh, &b_with_fresh));
|
||||
try!(self.lub().relate(&a_with_fresh, &b_with_fresh));
|
||||
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()));
|
||||
|
||||
// Generalize the regions appearing in result0 if possible
|
||||
let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot);
|
||||
let span = self.trace().origin.span();
|
||||
let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
|
||||
let span = self.trace.origin.span();
|
||||
let result1 =
|
||||
fold_regions_in(
|
||||
self.tcx(),
|
||||
&result0,
|
||||
|r, debruijn| generalize_region(self.infcx(), span, snapshot, debruijn,
|
||||
|r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn,
|
||||
&new_vars, &a_map, r));
|
||||
|
||||
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>>
|
||||
where T : Combineable<'tcx>
|
||||
fn higher_ranked_glb<T>(&self, a: &Binder<T>, b: &Binder<T>) -> RelateResult<'tcx, Binder<T>>
|
||||
where T: Relate<'a,'tcx>
|
||||
{
|
||||
debug!("{}.higher_ranked_glb({}, {})",
|
||||
self.tag(), a.repr(self.tcx()), b.repr(self.tcx()));
|
||||
debug!("higher_ranked_glb({}, {})",
|
||||
a.repr(self.tcx()), b.repr(self.tcx()));
|
||||
|
||||
// Make a snapshot so we can examine "all bindings that were
|
||||
// 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.
|
||||
let (a_with_fresh, a_map) =
|
||||
self.infcx().replace_late_bound_regions_with_fresh_var(
|
||||
self.trace().origin.span(), HigherRankedType, a);
|
||||
self.infcx.replace_late_bound_regions_with_fresh_var(
|
||||
self.trace.origin.span(), HigherRankedType, a);
|
||||
let (b_with_fresh, b_map) =
|
||||
self.infcx().replace_late_bound_regions_with_fresh_var(
|
||||
self.trace().origin.span(), HigherRankedType, b);
|
||||
self.infcx.replace_late_bound_regions_with_fresh_var(
|
||||
self.trace.origin.span(), HigherRankedType, b);
|
||||
let a_vars = var_ids(self, &a_map);
|
||||
let b_vars = var_ids(self, &b_map);
|
||||
|
||||
// Collect constraints.
|
||||
let result0 =
|
||||
try!(Combineable::combine(self, &a_with_fresh, &b_with_fresh));
|
||||
try!(self.glb().relate(&a_with_fresh, &b_with_fresh));
|
||||
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()));
|
||||
|
||||
// Generalize the regions appearing in result0 if possible
|
||||
let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot);
|
||||
let span = self.trace().origin.span();
|
||||
let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
|
||||
let span = self.trace.origin.span();
|
||||
let result1 =
|
||||
fold_regions_in(
|
||||
self.tcx(),
|
||||
&result0,
|
||||
|r, debruijn| generalize_region(self.infcx(), span, snapshot, debruijn,
|
||||
|r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn,
|
||||
&new_vars,
|
||||
&a_map, &a_vars, &b_vars,
|
||||
r));
|
||||
|
@ -332,17 +333,19 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C
|
|||
}
|
||||
}
|
||||
|
||||
fn var_ids<'tcx, T: Combine<'tcx>>(combiner: &T,
|
||||
map: &FnvHashMap<ty::BoundRegion, ty::Region>)
|
||||
-> Vec<ty::RegionVid> {
|
||||
map.iter().map(|(_, r)| match *r {
|
||||
ty::ReInfer(ty::ReVar(r)) => { r }
|
||||
r => {
|
||||
combiner.infcx().tcx.sess.span_bug(
|
||||
combiner.trace().origin.span(),
|
||||
&format!("found non-region-vid: {:?}", r));
|
||||
}
|
||||
}).collect()
|
||||
fn var_ids<'a, 'tcx>(fields: &CombineFields<'a, 'tcx>,
|
||||
map: &FnvHashMap<ty::BoundRegion, ty::Region>)
|
||||
-> Vec<ty::RegionVid> {
|
||||
map.iter()
|
||||
.map(|(_, r)| match *r {
|
||||
ty::ReInfer(ty::ReVar(r)) => { r }
|
||||
r => {
|
||||
fields.tcx().sess.span_bug(
|
||||
fields.trace.origin.span(),
|
||||
&format!("found non-region-vid: {:?}", r));
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn is_var_in_set(new_vars: &[ty::RegionVid], r: ty::Region) -> bool {
|
||||
|
@ -356,8 +359,8 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>,
|
|||
unbound_value: &T,
|
||||
mut fldr: F)
|
||||
-> T
|
||||
where T : Combineable<'tcx>,
|
||||
F : FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region,
|
||||
where T: TypeFoldable<'tcx>,
|
||||
F: FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region,
|
||||
{
|
||||
unbound_value.fold_with(&mut ty_fold::RegionFolder::new(tcx, &mut |region, current_depth| {
|
||||
// we should only be encountering "escaping" late-bound regions here,
|
||||
|
|
|
@ -29,48 +29,32 @@
|
|||
//! over a `LatticeValue`, which is a value defined with respect to
|
||||
//! a lattice.
|
||||
|
||||
use super::*;
|
||||
use super::combine::*;
|
||||
use super::glb::Glb;
|
||||
use super::lub::Lub;
|
||||
use super::combine;
|
||||
use super::InferCtxt;
|
||||
|
||||
use middle::ty::TyVar;
|
||||
use middle::ty::{self, Ty};
|
||||
use middle::ty_relate::{RelateResult, TypeRelation};
|
||||
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
|
||||
// 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> {
|
||||
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>,
|
||||
b: Ty<'tcx>)
|
||||
-> cres<'tcx, Ty<'tcx>>
|
||||
pub fn super_lattice_tys<'a,'tcx,L:LatticeDir<'a,'tcx>>(this: &mut L,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>)
|
||||
-> RelateResult<'tcx, Ty<'tcx>>
|
||||
where 'tcx: 'a
|
||||
{
|
||||
debug!("{}.lattice_tys({}, {})",
|
||||
this.tag(),
|
||||
a.repr(this.infcx().tcx),
|
||||
b.repr(this.infcx().tcx));
|
||||
a.repr(this.tcx()),
|
||||
b.repr(this.tcx()));
|
||||
|
||||
if a == b {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,67 +8,80 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use super::combine::*;
|
||||
use super::combine::CombineFields;
|
||||
use super::higher_ranked::HigherRankedRelations;
|
||||
use super::lattice::*;
|
||||
use super::cres;
|
||||
use super::InferCtxt;
|
||||
use super::lattice::{self, LatticeDir};
|
||||
use super::Subtype;
|
||||
|
||||
use middle::ty::{self, Ty};
|
||||
use middle::ty_relate::{Relate, RelateResult, TypeRelation};
|
||||
use util::ppaux::Repr;
|
||||
|
||||
/// "Least upper bound" (common supertype)
|
||||
pub struct Lub<'f, 'tcx: 'f> {
|
||||
fields: CombineFields<'f, 'tcx>
|
||||
pub struct Lub<'a, 'tcx: 'a> {
|
||||
fields: CombineFields<'a, 'tcx>
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Lub<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Lub<'f, 'tcx> {
|
||||
Lub { fields: cf }
|
||||
impl<'a, 'tcx> Lub<'a, 'tcx> {
|
||||
pub fn new(fields: CombineFields<'a, 'tcx>) -> Lub<'a, 'tcx> {
|
||||
Lub { fields: fields }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> {
|
||||
fn tag(&self) -> String { "Lub".to_string() }
|
||||
fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
|
||||
impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Lub<'a, 'tcx> {
|
||||
fn tag(&self) -> &'static str { "Lub" }
|
||||
|
||||
fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
|
||||
-> cres<'tcx, Ty<'tcx>>
|
||||
fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.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 {
|
||||
ty::Invariant => self.equate().tys(a, b),
|
||||
ty::Covariant => self.tys(a, b),
|
||||
ty::Bivariant => self.bivariate().tys(a, b),
|
||||
ty::Contravariant => self.glb().tys(a, b),
|
||||
match variance {
|
||||
ty::Invariant => self.fields.equate().relate(a, b),
|
||||
ty::Covariant => self.relate(a, b),
|
||||
ty::Bivariant => self.fields.bivariate().relate(a, b),
|
||||
ty::Contravariant => self.fields.glb().relate(a, b),
|
||||
}
|
||||
}
|
||||
|
||||
fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region)
|
||||
-> cres<'tcx, ty::Region>
|
||||
{
|
||||
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 tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
lattice::super_lattice_tys(self, 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({}, {})",
|
||||
self.tag(),
|
||||
a.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>> {
|
||||
super_lattice_tys(self, a, b)
|
||||
}
|
||||
|
||||
fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>>
|
||||
where T : Combineable<'tcx>
|
||||
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_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(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,8 @@ use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, UnconstrainedNumeric};
|
|||
use middle::ty::replace_late_bound_regions;
|
||||
use middle::ty::{self, Ty};
|
||||
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::rc::Rc;
|
||||
use syntax::ast;
|
||||
|
@ -38,12 +39,9 @@ use util::nodemap::FnvHashMap;
|
|||
use util::ppaux::ty_to_string;
|
||||
use util::ppaux::{Repr, UserString};
|
||||
|
||||
use self::combine::{Combine, Combineable, CombineFields};
|
||||
use self::combine::CombineFields;
|
||||
use self::region_inference::{RegionVarBindings, RegionSnapshot};
|
||||
use self::equate::Equate;
|
||||
use self::sub::Sub;
|
||||
use self::lub::Lub;
|
||||
use self::unify::{UnificationTable, InferCtxtMethodsForSimplyUnifiableTypes};
|
||||
use self::unify::{ToType, UnificationTable};
|
||||
use self::error_reporting::ErrorReporting;
|
||||
|
||||
pub mod bivariate;
|
||||
|
@ -62,9 +60,7 @@ pub mod type_variable;
|
|||
pub mod unify;
|
||||
|
||||
pub type Bound<T> = Option<T>;
|
||||
|
||||
pub type cres<'tcx, T> = Result<T,ty::type_err<'tcx>>; // "combine result"
|
||||
pub type ures<'tcx> = cres<'tcx, ()>; // "unify result"
|
||||
pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
|
||||
pub type fres<T> = Result<T, fixup_err>; // "fixup result"
|
||||
|
||||
pub struct InferCtxt<'a, 'tcx: 'a> {
|
||||
|
@ -265,7 +261,7 @@ pub enum LateBoundRegionConversionTime {
|
|||
///
|
||||
/// See `error_reporting.rs` for more details
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum RegionVariableOrigin<'tcx> {
|
||||
pub enum RegionVariableOrigin {
|
||||
// Region variables created for ill-categorized reasons,
|
||||
// mostly indicates places in need of refactoring
|
||||
MiscVariable(Span),
|
||||
|
@ -280,7 +276,7 @@ pub enum RegionVariableOrigin<'tcx> {
|
|||
Autoref(Span),
|
||||
|
||||
// Regions created as part of an automatic coercion
|
||||
Coercion(TypeTrace<'tcx>),
|
||||
Coercion(Span),
|
||||
|
||||
// Region variables created as the values for early-bound regions
|
||||
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))
|
||||
};
|
||||
|
||||
let result =
|
||||
cx.commit_if_ok(|| cx.lub(a_is_expected, trace.clone()).tys(a, b));
|
||||
let result = cx.commit_if_ok(|_| cx.lub(a_is_expected, trace.clone()).relate(&a, &b));
|
||||
match result {
|
||||
Ok(t) => t,
|
||||
Err(ref err) => {
|
||||
|
@ -359,29 +354,28 @@ pub fn mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
|
|||
origin: TypeOrigin,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>)
|
||||
-> ures<'tcx>
|
||||
-> UnitResult<'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>,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>)
|
||||
-> ures<'tcx> {
|
||||
-> UnitResult<'tcx> {
|
||||
debug!("can_mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
|
||||
cx.probe(|_| {
|
||||
let trace = TypeTrace {
|
||||
origin: Misc(codemap::DUMMY_SP),
|
||||
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)
|
||||
}
|
||||
|
@ -401,11 +395,10 @@ pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
|
|||
origin: TypeOrigin,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>)
|
||||
-> ures<'tcx>
|
||||
-> UnitResult<'tcx>
|
||||
{
|
||||
debug!("mk_eqty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
|
||||
cx.commit_if_ok(
|
||||
|| cx.eq_types(a_is_expected, origin, a, b))
|
||||
cx.commit_if_ok(|_| cx.eq_types(a_is_expected, origin, a, b))
|
||||
}
|
||||
|
||||
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,
|
||||
a: ty::PolyTraitRef<'tcx>,
|
||||
b: ty::PolyTraitRef<'tcx>)
|
||||
-> ures<'tcx>
|
||||
-> UnitResult<'tcx>
|
||||
{
|
||||
debug!("mk_sub_trait_refs({} <: {})",
|
||||
a.repr(cx.tcx), b.repr(cx.tcx));
|
||||
cx.commit_if_ok(
|
||||
|| cx.sub_poly_trait_refs(a_is_expected, origin, a.clone(), b.clone()))
|
||||
cx.commit_if_ok(|_| cx.sub_poly_trait_refs(a_is_expected, origin, a.clone(), b.clone()))
|
||||
}
|
||||
|
||||
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"]
|
||||
pub struct CombinedSnapshot {
|
||||
type_snapshot: type_variable::Snapshot,
|
||||
|
@ -512,41 +453,56 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
use middle::ty::UnconstrainedNumeric::{Neither, UnconstrainedInt, UnconstrainedFloat};
|
||||
match ty.sty {
|
||||
ty::ty_infer(ty::IntVar(vid)) => {
|
||||
match self.int_unification_table.borrow_mut().get(self.tcx, vid).value {
|
||||
None => UnconstrainedInt,
|
||||
_ => Neither,
|
||||
if self.int_unification_table.borrow_mut().has_value(vid) {
|
||||
Neither
|
||||
} else {
|
||||
UnconstrainedInt
|
||||
}
|
||||
},
|
||||
ty::ty_infer(ty::FloatVar(vid)) => {
|
||||
match self.float_unification_table.borrow_mut().get(self.tcx, vid).value {
|
||||
None => return UnconstrainedFloat,
|
||||
_ => Neither,
|
||||
if self.float_unification_table.borrow_mut().has_value(vid) {
|
||||
Neither
|
||||
} else {
|
||||
UnconstrainedFloat
|
||||
}
|
||||
},
|
||||
_ => Neither,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn combine_fields<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>)
|
||||
-> CombineFields<'b, 'tcx> {
|
||||
fn combine_fields(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
|
||||
-> CombineFields<'a, 'tcx> {
|
||||
CombineFields {infcx: self,
|
||||
a_is_expected: a_is_expected,
|
||||
trace: trace}
|
||||
}
|
||||
|
||||
pub fn equate<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>)
|
||||
-> Equate<'b, 'tcx> {
|
||||
Equate(self.combine_fields(a_is_expected, trace))
|
||||
// public so that it can be used from the rustc_driver unit tests
|
||||
pub fn equate(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
|
||||
-> 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>)
|
||||
-> Sub<'b, 'tcx> {
|
||||
Sub(self.combine_fields(a_is_expected, trace))
|
||||
// public so that it can be used from the rustc_driver unit tests
|
||||
pub fn sub(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
|
||||
-> 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>)
|
||||
-> Lub<'b, 'tcx> {
|
||||
Lub(self.combine_fields(a_is_expected, trace))
|
||||
// public so that it can be used from the rustc_driver unit tests
|
||||
pub fn lub(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
|
||||
-> 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 {
|
||||
|
@ -609,11 +565,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
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
|
||||
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.
|
||||
|
@ -628,7 +592,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
float_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
|
||||
// inside `f`, with, e.g. `resolve_type_vars_if_possible`.
|
||||
|
@ -649,25 +613,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
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
|
||||
pub fn probe<R, F>(&self, f: F) -> R where
|
||||
F: FnOnce(&CombinedSnapshot) -> R,
|
||||
|
@ -691,12 +636,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
origin: TypeOrigin,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>)
|
||||
-> ures<'tcx>
|
||||
-> UnitResult<'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);
|
||||
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,
|
||||
a: 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);
|
||||
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,
|
||||
a: Rc<ty::TraitRef<'tcx>>,
|
||||
b: Rc<ty::TraitRef<'tcx>>)
|
||||
-> ures<'tcx>
|
||||
-> UnitResult<'tcx>
|
||||
{
|
||||
debug!("sub_trait_refs({} <: {})",
|
||||
a.repr(self.tcx),
|
||||
b.repr(self.tcx));
|
||||
self.commit_if_ok(|| {
|
||||
self.commit_if_ok(|_| {
|
||||
let trace = TypeTrace {
|
||||
origin: origin,
|
||||
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,
|
||||
a: ty::PolyTraitRef<'tcx>,
|
||||
b: ty::PolyTraitRef<'tcx>)
|
||||
-> ures<'tcx>
|
||||
-> UnitResult<'tcx>
|
||||
{
|
||||
debug!("sub_poly_trait_refs({} <: {})",
|
||||
a.repr(self.tcx),
|
||||
b.repr(self.tcx));
|
||||
self.commit_if_ok(|| {
|
||||
self.commit_if_ok(|_| {
|
||||
let trace = TypeTrace {
|
||||
origin: origin,
|
||||
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,
|
||||
skol_map: &SkolemizationMap,
|
||||
snapshot: &CombinedSnapshot)
|
||||
-> ures<'tcx>
|
||||
-> UnitResult<'tcx>
|
||||
{
|
||||
/*! See `higher_ranked::leak_check` */
|
||||
|
||||
|
@ -799,8 +744,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
pub fn equality_predicate(&self,
|
||||
span: Span,
|
||||
predicate: &ty::PolyEquatePredicate<'tcx>)
|
||||
-> ures<'tcx> {
|
||||
self.try(|snapshot| {
|
||||
-> UnitResult<'tcx> {
|
||||
self.commit_if_ok(|snapshot| {
|
||||
let (ty::EquatePredicate(a, b), skol_map) =
|
||||
self.skolemize_late_bound_regions(predicate, snapshot);
|
||||
let origin = EquatePredicate(span);
|
||||
|
@ -812,8 +757,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
pub fn region_outlives_predicate(&self,
|
||||
span: Span,
|
||||
predicate: &ty::PolyRegionOutlivesPredicate)
|
||||
-> ures<'tcx> {
|
||||
self.try(|snapshot| {
|
||||
-> UnitResult<'tcx> {
|
||||
self.commit_if_ok(|snapshot| {
|
||||
let (ty::OutlivesPredicate(r_a, r_b), skol_map) =
|
||||
self.skolemize_late_bound_regions(predicate, snapshot);
|
||||
let origin = RelateRegionParamBound(span);
|
||||
|
@ -852,7 +797,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
.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)))
|
||||
}
|
||||
|
||||
|
@ -948,12 +893,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -1104,8 +1055,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
self.region_vars.verify_generic_bound(origin, kind, a, bs);
|
||||
}
|
||||
|
||||
pub fn can_equate<T>(&self, a: &T, b: &T) -> ures<'tcx>
|
||||
where T : Combineable<'tcx> + Repr<'tcx>
|
||||
pub fn can_equate<'b,T>(&'b self, a: &T, b: &T) -> UnitResult<'tcx>
|
||||
where T: Relate<'b,'tcx> + Repr<'tcx>
|
||||
{
|
||||
debug!("can_equate({}, {})", a.repr(self.tcx), b.repr(self.tcx));
|
||||
self.probe(|_| {
|
||||
|
@ -1116,9 +1067,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
let e = self.tcx.types.err;
|
||||
let trace = TypeTrace { origin: Misc(codemap::DUMMY_SP),
|
||||
values: Types(expected_found(true, e, e)) };
|
||||
let eq = self.equate(true, trace);
|
||||
Combineable::combine(&eq, a, b)
|
||||
}).to_ures()
|
||||
self.equate(true, trace).relate(a, b)
|
||||
}).map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1304,14 +1254,14 @@ impl<'tcx> Repr<'tcx> for SubregionOrigin<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> RegionVariableOrigin<'tcx> {
|
||||
impl RegionVariableOrigin {
|
||||
pub fn span(&self) -> Span {
|
||||
match *self {
|
||||
MiscVariable(a) => a,
|
||||
PatternRegion(a) => a,
|
||||
AddrOfRegion(a) => a,
|
||||
Autoref(a) => a,
|
||||
Coercion(ref a) => a.span(),
|
||||
Coercion(a) => a,
|
||||
EarlyBoundRegion(a, _) => a,
|
||||
LateBoundRegion(a, _, _) => a,
|
||||
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 {
|
||||
match *self {
|
||||
MiscVariable(a) => {
|
||||
|
@ -1333,7 +1283,7 @@ impl<'tcx> Repr<'tcx> for RegionVariableOrigin<'tcx> {
|
|||
format!("AddrOfRegion({})", 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) => {
|
||||
format!("EarlyBoundRegion({},{})", a.repr(tcx), b.repr(tcx))
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ pub use self::RegionResolutionError::*;
|
|||
pub use self::VarValue::*;
|
||||
use self::Classification::*;
|
||||
|
||||
use super::cres;
|
||||
use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable};
|
||||
|
||||
use middle::region;
|
||||
|
@ -26,6 +25,7 @@ use middle::ty::{self, Ty};
|
|||
use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid};
|
||||
use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound};
|
||||
use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh};
|
||||
use middle::ty_relate::RelateResult;
|
||||
use middle::graph;
|
||||
use middle::graph::{Direction, NodeIndex};
|
||||
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
|
||||
/// `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and
|
||||
/// `sub_r <= sup_r` does not hold.
|
||||
SubSupConflict(RegionVariableOrigin<'tcx>,
|
||||
SubSupConflict(RegionVariableOrigin,
|
||||
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
|
||||
/// `origin1`) and `v <= r2` (due to `origin2`) and
|
||||
/// `r1` and `r2` have no intersection.
|
||||
SupSupConflict(RegionVariableOrigin<'tcx>,
|
||||
SupSupConflict(RegionVariableOrigin,
|
||||
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
|
||||
/// should put a lifetime. In those cases we process and put those errors
|
||||
/// into `ProcessedErrors` before we do any reporting.
|
||||
ProcessedErrors(Vec<RegionVariableOrigin<'tcx>>,
|
||||
ProcessedErrors(Vec<RegionVariableOrigin>,
|
||||
Vec<(TypeTrace<'tcx>, ty::type_err<'tcx>)>,
|
||||
Vec<SameRegions>),
|
||||
}
|
||||
|
@ -168,7 +168,7 @@ pub type CombineMap = FnvHashMap<TwoRegions, RegionVid>;
|
|||
|
||||
pub struct RegionVarBindings<'a, 'tcx: 'a> {
|
||||
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
|
||||
// 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
|
||||
}
|
||||
|
||||
pub fn new_region_var(&self, origin: RegionVariableOrigin<'tcx>) -> RegionVid {
|
||||
pub fn new_region_var(&self, origin: RegionVariableOrigin) -> RegionVid {
|
||||
let id = self.num_vars();
|
||||
self.var_origins.borrow_mut().push(origin.clone());
|
||||
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.
|
||||
fn lub_free_regions(&self,
|
||||
a: &FreeRegion,
|
||||
b: &FreeRegion) -> ty::Region
|
||||
b: &FreeRegion)
|
||||
-> ty::Region
|
||||
{
|
||||
return match a.cmp(b) {
|
||||
Less => helper(self, a, b),
|
||||
|
@ -823,7 +824,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
|
|||
fn glb_concrete_regions(&self,
|
||||
a: Region,
|
||||
b: Region)
|
||||
-> cres<'tcx, Region> {
|
||||
-> RelateResult<'tcx, Region>
|
||||
{
|
||||
debug!("glb_concrete_regions({:?}, {:?})", a, b);
|
||||
match (a, b) {
|
||||
(ReLateBound(..), _) |
|
||||
|
@ -898,7 +900,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
|
|||
/// returned.
|
||||
fn glb_free_regions(&self,
|
||||
a: &FreeRegion,
|
||||
b: &FreeRegion) -> cres<'tcx, ty::Region>
|
||||
b: &FreeRegion)
|
||||
-> RelateResult<'tcx, ty::Region>
|
||||
{
|
||||
return match a.cmp(b) {
|
||||
Less => helper(self, a, b),
|
||||
|
@ -908,7 +911,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
|
|||
|
||||
fn helper<'a, 'tcx>(this: &RegionVarBindings<'a, 'tcx>,
|
||||
a: &FreeRegion,
|
||||
b: &FreeRegion) -> cres<'tcx, ty::Region>
|
||||
b: &FreeRegion) -> RelateResult<'tcx, ty::Region>
|
||||
{
|
||||
if this.tcx.region_maps.sub_free_region(*a, *b) {
|
||||
Ok(ty::ReFree(*a))
|
||||
|
@ -926,7 +929,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
|
|||
region_a: ty::Region,
|
||||
region_b: ty::Region,
|
||||
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
|
||||
// scopes or two free regions. So, if one of
|
||||
|
|
|
@ -8,64 +8,49 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use super::combine::*;
|
||||
use super::cres;
|
||||
use super::combine::{self, CombineFields};
|
||||
use super::higher_ranked::HigherRankedRelations;
|
||||
use super::Subtype;
|
||||
use super::type_variable::{SubtypeOf, SupertypeOf};
|
||||
|
||||
use middle::ty::{self, Ty};
|
||||
use middle::ty::TyVar;
|
||||
use util::ppaux::Repr;
|
||||
use middle::ty_relate::{Relate, RelateResult, TypeRelation};
|
||||
use util::ppaux::{Repr};
|
||||
|
||||
/// "Greatest lower bound" (common subtype)
|
||||
pub struct Sub<'f, 'tcx: 'f> {
|
||||
fields: CombineFields<'f, 'tcx>
|
||||
pub struct Sub<'a, 'tcx: 'a> {
|
||||
fields: CombineFields<'a, 'tcx>
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Sub<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Sub<'f, 'tcx> {
|
||||
Sub { fields: cf }
|
||||
impl<'a, 'tcx> Sub<'a, 'tcx> {
|
||||
pub fn new(f: CombineFields<'a, 'tcx>) -> Sub<'a, 'tcx> {
|
||||
Sub { fields: f }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> {
|
||||
fn tag(&self) -> String { "Sub".to_string() }
|
||||
fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
|
||||
impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Sub<'a, 'tcx> {
|
||||
fn tag(&self) -> &'static str { "Sub" }
|
||||
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>)
|
||||
-> cres<'tcx, Ty<'tcx>>
|
||||
fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
|
||||
variance: ty::Variance,
|
||||
a: &T,
|
||||
b: &T)
|
||||
-> RelateResult<'tcx, T>
|
||||
{
|
||||
match v {
|
||||
ty::Invariant => self.equate().tys(a, b),
|
||||
ty::Covariant => self.tys(a, b),
|
||||
ty::Bivariant => self.bivariate().tys(a, b),
|
||||
ty::Contravariant => Sub(self.fields.switch_expected()).tys(b, a),
|
||||
match variance {
|
||||
ty::Invariant => self.fields.equate().relate(a, b),
|
||||
ty::Covariant => self.relate(a, b),
|
||||
ty::Bivariant => self.fields.bivariate().relate(a, b),
|
||||
ty::Contravariant => self.fields.switch_expected().sub().relate(b, a),
|
||||
}
|
||||
}
|
||||
|
||||
fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region)
|
||||
-> cres<'tcx, ty::Region>
|
||||
{
|
||||
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 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()));
|
||||
|
||||
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); }
|
||||
|
||||
let infcx = self.fields.infcx;
|
||||
|
@ -80,8 +65,8 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> {
|
|||
}
|
||||
(&ty::ty_infer(TyVar(a_id)), _) => {
|
||||
try!(self.fields
|
||||
.switch_expected()
|
||||
.instantiate(b, SupertypeOf, a_id));
|
||||
.switch_expected()
|
||||
.instantiate(b, SupertypeOf, a_id));
|
||||
Ok(a)
|
||||
}
|
||||
(_, &ty::ty_infer(TyVar(b_id))) => {
|
||||
|
@ -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>>
|
||||
where T : Combineable<'tcx>
|
||||
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()));
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,11 +12,8 @@ pub use self::VarValue::*;
|
|||
|
||||
use std::marker;
|
||||
|
||||
use middle::ty::{expected_found, IntVarValue};
|
||||
use middle::ty::{IntVarValue};
|
||||
use middle::ty::{self, Ty};
|
||||
use middle::infer::{uok, ures};
|
||||
use middle::infer::InferCtxt;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::Debug;
|
||||
use std::marker::PhantomData;
|
||||
use syntax::ast;
|
||||
|
@ -35,14 +32,9 @@ use util::snapshot_vec as sv;
|
|||
pub trait UnifyKey : Clone + Debug + PartialEq {
|
||||
type Value : UnifyValue;
|
||||
|
||||
fn index(&self) -> usize;
|
||||
fn index(&self) -> u32;
|
||||
|
||||
fn from_index(u: usize) -> 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 from_index(u: u32) -> Self;
|
||||
|
||||
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 {
|
||||
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: {:?}",
|
||||
UnifyKey::tag(None::<K>),
|
||||
k);
|
||||
k
|
||||
}
|
||||
|
||||
/// Find the root node for `vid`. This uses the standard union-find algorithm with path
|
||||
/// compression: http://en.wikipedia.org/wiki/Disjoint-set_data_structure
|
||||
pub fn get(&mut self, tcx: &ty::ctxt, vid: K) -> Node<K> {
|
||||
let index = vid.index();
|
||||
/// Find the root node for `vid`. This uses the standard
|
||||
/// union-find algorithm with path compression:
|
||||
/// <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>.
|
||||
///
|
||||
/// 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();
|
||||
match value {
|
||||
Redirect(redirect) => {
|
||||
let node: Node<K> = self.get(tcx, redirect.clone());
|
||||
let node: Node<K> = self.get(redirect.clone());
|
||||
if node.key != redirect {
|
||||
// Path compression
|
||||
self.values.set(index, Redirect(node.key.clone()));
|
||||
|
@ -158,58 +154,58 @@ impl<K:UnifyKey> UnificationTable<K> {
|
|||
}
|
||||
|
||||
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,
|
||||
Root(..) => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the value for `vid` to `new_value`. `vid` MUST be a root node! Also, we must be in the
|
||||
/// middle of a snapshot.
|
||||
pub fn set<'tcx>(&mut self,
|
||||
_tcx: &ty::ctxt<'tcx>,
|
||||
key: K,
|
||||
new_value: VarValue<K>)
|
||||
{
|
||||
/// Sets the value for `vid` to `new_value`. `vid` MUST be a root
|
||||
/// node! This is an internal operation used to impl other things.
|
||||
fn set(&mut self, key: K, new_value: VarValue<K>) {
|
||||
assert!(self.is_root(&key));
|
||||
|
||||
debug!("Updating variable {:?} to {:?}",
|
||||
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
|
||||
/// the new root and rank. You should then update the value of the new root to something
|
||||
/// suitable.
|
||||
pub fn unify<'tcx>(&mut self,
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
node_a: &Node<K>,
|
||||
node_b: &Node<K>)
|
||||
-> (K, usize)
|
||||
{
|
||||
/// Either redirects `node_a` to `node_b` or vice versa, depending
|
||||
/// on the relative rank. The value associated with the new root
|
||||
/// will be `new_value`.
|
||||
///
|
||||
/// NB: This is the "union" operation of "union-find". It is
|
||||
/// really more of a building block. If the values associated with
|
||||
/// your key are non-trivial, you would probably prefer to call
|
||||
/// `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={:?}))",
|
||||
node_a.key,
|
||||
node_a.rank,
|
||||
node_b.key,
|
||||
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,
|
||||
// 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)
|
||||
} else if node_a.rank < node_b.rank {
|
||||
// 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)
|
||||
} else {
|
||||
// If equal, redirect one to the other and increment the
|
||||
// other's 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)
|
||||
}
|
||||
};
|
||||
|
||||
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
|
||||
// doesn't have a subtyping relationship we need to worry about.
|
||||
// Code to handle keys which carry a value, like ints,
|
||||
// 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
|
||||
/// 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>>,
|
||||
V : SimplyUnifiable<'tcx>,
|
||||
Option<V> : UnifyValue,
|
||||
impl<'tcx,K,V> UnificationTable<K>
|
||||
where K: UnifyKey<Value=Option<V>>,
|
||||
V: Clone+PartialEq,
|
||||
Option<V>: UnifyValue,
|
||||
{
|
||||
fn simple_vars(&self,
|
||||
a_is_expected: bool,
|
||||
a_id: K,
|
||||
b_id: K)
|
||||
-> ures<'tcx>;
|
||||
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
|
||||
/// both keys have already been associated with a value, then those two values must be the
|
||||
/// same.
|
||||
fn simple_vars(&self,
|
||||
a_is_expected: bool,
|
||||
a_id: K,
|
||||
b_id: K)
|
||||
-> ures<'tcx>
|
||||
pub fn unify_var_var(&mut self,
|
||||
a_id: K,
|
||||
b_id: K)
|
||||
-> Result<(),(V,V)>
|
||||
{
|
||||
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 node_a = self.get(a_id);
|
||||
let node_b = self.get(b_id);
|
||||
let a_id = node_a.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 = {
|
||||
match (&node_a.value, &node_b.value) {
|
||||
|
@ -293,61 +246,52 @@ impl<'a,'tcx,V,K> InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V> for InferCtx
|
|||
None
|
||||
}
|
||||
(&Some(ref v), &None) | (&None, &Some(ref v)) => {
|
||||
Some((*v).clone())
|
||||
Some(v.clone())
|
||||
}
|
||||
(&Some(ref v1), &Some(ref 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,
|
||||
&node_a,
|
||||
&node_b);
|
||||
table.borrow_mut().set(tcx, new_root, Root(combined, new_rank));
|
||||
return Ok(())
|
||||
Ok(self.unify(&node_a, &node_b, combined))
|
||||
}
|
||||
|
||||
/// 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`.
|
||||
fn simple_var_t(&self,
|
||||
a_is_expected: bool,
|
||||
a_id: K,
|
||||
b: V)
|
||||
-> ures<'tcx>
|
||||
pub fn unify_var_value(&mut self,
|
||||
a_id: K,
|
||||
b: V)
|
||||
-> Result<(),(V,V)>
|
||||
{
|
||||
let tcx = self.tcx;
|
||||
let table = UnifyKey::unification_table(self);
|
||||
let node_a = table.borrow_mut().get(tcx, a_id);
|
||||
let node_a = self.get(a_id);
|
||||
let a_id = node_a.key.clone();
|
||||
|
||||
match node_a.value {
|
||||
None => {
|
||||
table.borrow_mut().set(tcx, a_id, Root(Some(b), node_a.rank));
|
||||
return Ok(());
|
||||
self.set(a_id, Root(Some(b), node_a.rank));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Some(ref a_t) => {
|
||||
if *a_t == b {
|
||||
return Ok(());
|
||||
Ok(())
|
||||
} 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>> {
|
||||
let tcx = self.tcx;
|
||||
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 has_value(&mut self, id: K) -> bool {
|
||||
self.get(id).value.is_some()
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
impl UnifyKey for ty::IntVid {
|
||||
type Value = Option<IntVarValue>;
|
||||
|
||||
fn index(&self) -> usize { self.index as usize }
|
||||
|
||||
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 {
|
||||
"IntVid"
|
||||
}
|
||||
pub trait ToType<'tcx> {
|
||||
fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx>;
|
||||
}
|
||||
|
||||
impl<'tcx> SimplyUnifiable<'tcx> for IntVarValue {
|
||||
impl UnifyKey for ty::IntVid {
|
||||
type Value = Option<IntVarValue>;
|
||||
fn index(&self) -> u32 { self.index }
|
||||
fn from_index(i: u32) -> ty::IntVid { ty::IntVid { index: i } }
|
||||
fn tag(_: Option<ty::IntVid>) -> &'static str { "IntVid" }
|
||||
}
|
||||
|
||||
impl<'tcx> ToType<'tcx> for IntVarValue {
|
||||
fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
|
||||
match *self {
|
||||
ty::IntType(i) => ty::mk_mach_int(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> { }
|
||||
|
@ -390,29 +325,16 @@ impl UnifyValue for Option<IntVarValue> { }
|
|||
|
||||
impl UnifyKey for ty::FloatVid {
|
||||
type Value = Option<ast::FloatTy>;
|
||||
|
||||
fn index(&self) -> usize { self.index as usize }
|
||||
|
||||
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"
|
||||
}
|
||||
fn index(&self) -> u32 { self.index }
|
||||
fn from_index(i: u32) -> ty::FloatVid { ty::FloatVid { index: i } }
|
||||
fn tag(_: Option<ty::FloatVid>) -> &'static str { "FloatVid" }
|
||||
}
|
||||
|
||||
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> {
|
||||
ty::mk_mach_float(tcx, *self)
|
||||
}
|
||||
|
||||
fn to_type_err(err: expected_found<ast::FloatTy>) -> ty::type_err<'tcx> {
|
||||
ty::terr_float_mismatch(err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ pub fn poly_project_and_unify_type<'cx,'tcx>(
|
|||
obligation.repr(selcx.tcx()));
|
||||
|
||||
let infcx = selcx.infcx();
|
||||
infcx.try(|snapshot| {
|
||||
infcx.commit_if_ok(|snapshot| {
|
||||
let (skol_predicate, skol_map) =
|
||||
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 value: T,
|
||||
pub obligations: Vec<PredicateObligation<'tcx>>,
|
||||
|
|
|
@ -39,11 +39,13 @@ use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
|
|||
use middle::infer;
|
||||
use middle::infer::{InferCtxt, TypeFreshener};
|
||||
use middle::ty_fold::TypeFoldable;
|
||||
use middle::ty_match;
|
||||
use middle::ty_relate::TypeRelation;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::hash_map::HashMap;
|
||||
use std::rc::Rc;
|
||||
use syntax::{abi, ast};
|
||||
use util::common::ErrorReported;
|
||||
use util::nodemap::FnvHashMap;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
pub struct SelectionContext<'cx, 'tcx:'cx> {
|
||||
|
@ -87,8 +89,8 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> {
|
|||
|
||||
#[derive(Clone)]
|
||||
pub struct SelectionCache<'tcx> {
|
||||
hashmap: RefCell<HashMap<Rc<ty::TraitRef<'tcx>>,
|
||||
SelectionResult<'tcx, SelectionCandidate<'tcx>>>>,
|
||||
hashmap: RefCell<FnvHashMap<Rc<ty::TraitRef<'tcx>>,
|
||||
SelectionResult<'tcx, SelectionCandidate<'tcx>>>>,
|
||||
}
|
||||
|
||||
pub enum MethodMatchResult {
|
||||
|
@ -474,7 +476,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
unbound_input_types &&
|
||||
(self.intercrate ||
|
||||
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",
|
||||
stack.fresh_trait_ref.repr(self.tcx()));
|
||||
|
@ -1271,7 +1274,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
self.infcx.try(|snapshot| {
|
||||
self.infcx.commit_if_ok(|snapshot| {
|
||||
let bound_self_ty =
|
||||
self.infcx.resolve_type_vars_if_possible(&obligation.self_ty());
|
||||
let (self_ty, _) =
|
||||
|
@ -1808,7 +1811,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
|
||||
// For each type, produce a vector of resulting obligations
|
||||
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) =
|
||||
self.infcx().skolemize_late_bound_regions(nested_ty, snapshot);
|
||||
let Normalized { value: normalized_ty, mut obligations } =
|
||||
|
@ -1918,7 +1921,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
obligation: &TraitObligation<'tcx>)
|
||||
{
|
||||
let _: Result<(),()> =
|
||||
self.infcx.try(|snapshot| {
|
||||
self.infcx.commit_if_ok(|snapshot| {
|
||||
let result =
|
||||
self.match_projection_obligation_against_bounds_from_trait(obligation,
|
||||
snapshot);
|
||||
|
@ -2073,7 +2076,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
trait_def_id,
|
||||
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 (trait_ref, skol_map) =
|
||||
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,
|
||||
// this time not in a probe.
|
||||
self.infcx.try(|snapshot| {
|
||||
self.infcx.commit_if_ok(|snapshot| {
|
||||
let (skol_obligation_trait_ref, skol_map) =
|
||||
self.infcx().skolemize_late_bound_regions(&obligation.predicate, snapshot);
|
||||
let substs =
|
||||
|
@ -2505,6 +2508,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// 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,
|
||||
previous_stack: TraitObligationStackList<'s, 'tcx>,
|
||||
obligation: &'o TraitObligation<'tcx>)
|
||||
|
@ -2664,7 +2676,7 @@ impl<'tcx> Repr<'tcx> for SelectionCandidate<'tcx> {
|
|||
impl<'tcx> SelectionCache<'tcx> {
|
||||
pub fn new() -> SelectionCache<'tcx> {
|
||||
SelectionCache {
|
||||
hashmap: RefCell::new(HashMap::new())
|
||||
hashmap: RefCell::new(FnvHashMap())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,8 @@ use middle::subst::VecPerParamSpace;
|
|||
use middle::ty::{self, Ty};
|
||||
use middle::traits;
|
||||
use std::rc::Rc;
|
||||
use syntax::abi;
|
||||
use syntax::ast;
|
||||
use syntax::owned_slice::OwnedSlice;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
|
@ -47,7 +49,7 @@ use util::ppaux::Repr;
|
|||
|
||||
/// The TypeFoldable trait is implemented for every type that can be folded.
|
||||
/// 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;
|
||||
}
|
||||
|
||||
|
@ -149,12 +151,20 @@ pub trait TypeFolder<'tcx> : Sized {
|
|||
// can easily refactor the folding into the TypeFolder trait as
|
||||
// needed.
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for () {
|
||||
fn fold_with<F:TypeFolder<'tcx>>(&self, _: &mut F) -> () {
|
||||
()
|
||||
macro_rules! CopyImpls {
|
||||
($($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) {
|
||||
fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> (T, U) {
|
||||
(self.0.fold_with(folder), self.1.fold_with(folder))
|
||||
|
|
95
src/librustc/middle/ty_match.rs
Normal file
95
src/librustc/middle/ty_match.rs
Normal 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()))))
|
||||
}
|
||||
}
|
655
src/librustc/middle/ty_relate/mod.rs
Normal file
655
src/librustc/middle/ty_relate/mod.rs
Normal 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}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ use rustc_typeck::middle::stability;
|
|||
use rustc_typeck::middle::subst;
|
||||
use rustc_typeck::middle::subst::Subst;
|
||||
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::lub::Lub;
|
||||
use rustc_typeck::middle::infer::glb::Glb;
|
||||
|
@ -350,21 +350,21 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
|
|||
|
||||
pub fn sub(&self) -> Sub<'a, 'tcx> {
|
||||
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> {
|
||||
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> {
|
||||
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> {
|
||||
match self.lub().tys(t1, t2) {
|
||||
match self.lub().relate(&t1, &t2) {
|
||||
Ok(t) => t,
|
||||
Err(ref e) => panic!("unexpected error computing LUB: {}",
|
||||
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
|
||||
/// region checks).
|
||||
pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) {
|
||||
match self.sub().tys(t1, t2) {
|
||||
match self.sub().relate(&t1, &t2) {
|
||||
Ok(_) => { }
|
||||
Err(ref e) => {
|
||||
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
|
||||
/// region checks).
|
||||
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(_) => { }
|
||||
Ok(_) => {
|
||||
panic!("unexpected success computing sub({},{})",
|
||||
|
@ -400,7 +400,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
|
|||
|
||||
/// Checks that `LUB(t1,t2) == t_lub`
|
||||
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) => {
|
||||
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(t2),
|
||||
self.ty_to_string(t_glb));
|
||||
match self.glb().tys(t1, t2) {
|
||||
match self.glb().relate(&t1, &t2) {
|
||||
Err(e) => {
|
||||
panic!("unexpected error computing LUB: {:?}", e)
|
||||
}
|
||||
|
|
|
@ -83,9 +83,7 @@ pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
UnresolvedTypeAction::Error,
|
||||
LvaluePreference::NoPreference,
|
||||
|adj_ty, idx| {
|
||||
let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None };
|
||||
try_overloaded_call_step(fcx, call_expr, callee_expr,
|
||||
adj_ty, autoderefref)
|
||||
try_overloaded_call_step(fcx, call_expr, callee_expr, adj_ty, idx)
|
||||
});
|
||||
|
||||
match result {
|
||||
|
@ -119,13 +117,15 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
call_expr: &'tcx ast::Expr,
|
||||
callee_expr: &'tcx ast::Expr,
|
||||
adjusted_ty: Ty<'tcx>,
|
||||
autoderefref: ty::AutoDerefRef<'tcx>)
|
||||
autoderefs: usize)
|
||||
-> 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()),
|
||||
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.
|
||||
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;
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
|
|
@ -62,12 +62,11 @@
|
|||
|
||||
use check::{autoderef, FnCtxt, NoPreference, PreferMutLvalue, UnresolvedTypeAction};
|
||||
|
||||
use middle::infer::{self, cres, Coercion, TypeTrace};
|
||||
use middle::infer::combine::Combine;
|
||||
use middle::infer::sub::Sub;
|
||||
use middle::infer::{self, Coercion};
|
||||
use middle::subst;
|
||||
use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe};
|
||||
use middle::ty::{self, mt, Ty};
|
||||
use middle::ty_relate::RelateResult;
|
||||
use util::common::indent;
|
||||
use util::ppaux;
|
||||
use util::ppaux::Repr;
|
||||
|
@ -76,10 +75,10 @@ use syntax::ast;
|
|||
|
||||
struct Coerce<'a, 'tcx: 'a> {
|
||||
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> {
|
||||
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> {
|
||||
let sub = Sub(self.fcx.infcx().combine_fields(false, self.trace.clone()));
|
||||
try!(sub.tys(a, b));
|
||||
try!(self.fcx.infcx().sub_types(false, self.origin.clone(), a, b));
|
||||
Ok(None) // No coercion required.
|
||||
}
|
||||
|
||||
fn outlives(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ()> {
|
||||
let sub = Sub(self.fcx.infcx().combine_fields(false, self.trace.clone()));
|
||||
try!(sub.regions(b, a));
|
||||
fn outlives(&self,
|
||||
origin: infer::SubregionOrigin<'tcx>,
|
||||
a: ty::Region,
|
||||
b: ty::Region)
|
||||
-> RelateResult<'tcx, ()> {
|
||||
infer::mk_subr(self.fcx.infcx(), origin, b, a);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -190,7 +191,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
_ => 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 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,
|
||||
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() {
|
||||
first_error = Some(err);
|
||||
}
|
||||
|
@ -264,12 +265,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
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 ty = ty::mk_rptr(self.tcx(),
|
||||
self.tcx().mk_region(r_borrow),
|
||||
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, \
|
||||
AutoPtr(AutoUnsize({:?})))", kind);
|
||||
Ok(Some(AdjustDerefRef(AutoDerefRef {
|
||||
|
@ -290,7 +291,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
|
||||
let ty = ty::mk_ptr(self.tcx(),
|
||||
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, \
|
||||
AutoPtr(AutoUnsize({:?})))", kind);
|
||||
Ok(Some(AdjustDerefRef(AutoDerefRef {
|
||||
|
@ -306,7 +307,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
match self.unsize_ty(t_a, t_b) {
|
||||
Some((ty, kind)) => {
|
||||
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, \
|
||||
AutoUnsizeUniq({:?}))", kind);
|
||||
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);
|
||||
|
||||
// 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
|
||||
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));
|
||||
self.subtype(ty_a1, ty_b)
|
||||
});
|
||||
|
@ -399,7 +401,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
let mut result = None;
|
||||
let tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate();
|
||||
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;
|
||||
}
|
||||
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();
|
||||
new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp;
|
||||
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 \
|
||||
could not match types {} and {}",
|
||||
ppaux::ty_to_string(tcx, *tp_a),
|
||||
|
@ -534,14 +536,13 @@ pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
expr: &ast::Expr,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>)
|
||||
-> cres<'tcx, ()> {
|
||||
-> RelateResult<'tcx, ()> {
|
||||
debug!("mk_assignty({} -> {})", a.repr(fcx.tcx()), b.repr(fcx.tcx()));
|
||||
let adjustment = try!(indent(|| {
|
||||
fcx.infcx().commit_if_ok(|| {
|
||||
let origin = infer::ExprAssignable(expr.span);
|
||||
fcx.infcx().commit_if_ok(|_| {
|
||||
Coerce {
|
||||
fcx: fcx,
|
||||
trace: infer::TypeTrace::types(origin, false, a, b)
|
||||
origin: infer::ExprAssignable(expr.span),
|
||||
}.coerce(expr, a, b)
|
||||
})
|
||||
}));
|
||||
|
|
|
@ -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 = 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 (impl_sig, _) =
|
||||
|
|
|
@ -95,7 +95,7 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
|
|||
ty::lookup_item_type(tcx, self_type_did);
|
||||
|
||||
let infcx = infer::new_infer_ctxt(tcx);
|
||||
infcx.try(|snapshot| {
|
||||
infcx.commit_if_ok(|snapshot| {
|
||||
let (named_type_to_skolem, skol_map) =
|
||||
infcx.construct_skolemized_subst(named_type_generics, snapshot);
|
||||
let named_type_skolem = named_type.subst(tcx, &named_type_to_skolem);
|
||||
|
|
|
@ -1130,7 +1130,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// 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)
|
||||
}
|
||||
|
||||
|
|
|
@ -1542,7 +1542,7 @@ fn projection_bounds<'a,'tcx>(rcx: &Rcx<'a, 'tcx>,
|
|||
debug!("projection_bounds: outlives={} (2)",
|
||||
outlives.repr(tcx));
|
||||
|
||||
let region_result = infcx.try(|_| {
|
||||
let region_result = infcx.commit_if_ok(|_| {
|
||||
let (outlives, _) =
|
||||
infcx.replace_late_bound_regions_with_fresh_var(
|
||||
span,
|
||||
|
|
|
@ -30,7 +30,6 @@ use middle::ty::{ty_uint, ty_closure, ty_uniq, ty_bare_fn};
|
|||
use middle::ty::ty_projection;
|
||||
use middle::ty;
|
||||
use CrateCtxt;
|
||||
use middle::infer::combine::Combine;
|
||||
use middle::infer::InferCtxt;
|
||||
use middle::infer::new_infer_ctxt;
|
||||
use std::collections::HashSet;
|
||||
|
|
|
@ -23,10 +23,6 @@ pub fn main() {
|
|||
let f2: &Fat<[isize; 3]> = &f1;
|
||||
let f3: &Fat<[usize]> = f2;
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected `&Fat<[usize]>`
|
||||
//~| found `&Fat<[isize; 3]>`
|
||||
//~| expected usize
|
||||
//~| found isize
|
||||
|
||||
// With a trait.
|
||||
let f1 = Fat { ptr: Foo };
|
||||
|
|
|
@ -81,8 +81,8 @@ fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait {
|
|||
// which fails to type check.
|
||||
|
||||
ss
|
||||
//~^ ERROR cannot infer
|
||||
//~| ERROR mismatched types
|
||||
//~^ ERROR lifetime of the source pointer does not outlive lifetime bound
|
||||
//~| ERROR cannot infer
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -25,7 +25,7 @@ fn load(ss: &mut SomeStruct) -> Box<SomeTrait> {
|
|||
// `Box<SomeTrait>` defaults to a `'static` bound, so this return
|
||||
// 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>) {
|
||||
|
@ -38,7 +38,7 @@ fn store(ss: &mut SomeStruct, b: Box<SomeTrait>) {
|
|||
fn store1<'b>(ss: &mut SomeStruct, b: Box<SomeTrait+'b>) {
|
||||
// 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() {
|
||||
|
|
|
@ -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> {
|
||||
// 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() {
|
||||
|
|
|
@ -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 {
|
||||
// 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
|
||||
}
|
||||
|
||||
|
|
37
src/test/run-pass/unboxed-closures-blanket-fn-mut.rs
Normal file
37
src/test/run-pass/unboxed-closures-blanket-fn-mut.rs
Normal 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);
|
||||
}
|
37
src/test/run-pass/unboxed-closures-blanket-fn.rs
Normal file
37
src/test/run-pass/unboxed-closures-blanket-fn.rs
Normal 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);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue