diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 399aec9afd440..21af342b1bf78 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -1145,3 +1145,52 @@ pub trait FnOnce { /// 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 for &'a F + where F : Fn + { + extern "rust-call" fn call(&self, args: A) -> F::Output { + (**self).call(args) + } + } + + impl<'a,A,F:?Sized> FnMut for &'a F + where F : Fn + { + extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { + (**self).call(args) + } + } + + impl<'a,A,F:?Sized> FnOnce for &'a F + where F : Fn + { + type Output = F::Output; + + extern "rust-call" fn call_once(self, args: A) -> F::Output { + (*self).call(args) + } + } + + impl<'a,A,F:?Sized> FnMut for &'a mut F + where F : FnMut + { + extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { + (*self).call_mut(args) + } + } + + impl<'a,A,F:?Sized> FnOnce for &'a mut F + where F : FnMut + { + type Output = F::Output; + extern "rust-call" fn call_once(mut self, args: A) -> F::Output { + (*self).call_mut(args) + } + } +} diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index b3ad96c4b5f16..a4bb17bc35476 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -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; } diff --git a/src/librustc/middle/infer/bivariate.rs b/src/librustc/middle/infer/bivariate.rs index 17b0d788590c4..940dc75271c22 100644 --- a/src/librustc/middle/infer/bivariate.rs +++ b/src/librustc/middle/infer/bivariate.rs @@ -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>> - { - 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), - } - } + fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() } - 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 a_is_expected(&self) -> bool { self.fields.a_is_expected } - 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> + fn relate_with_variance>(&mut self, + variance: ty::Variance, + a: &T, + b: &T) + -> RelateResult<'tcx, T> { - if a != b { - Err(ty::terr_builtin_bounds(expected_found(self, a, b))) - } else { - Ok(a) + match variance { + // If we have Foo and Foo is invariant w/r/t A, + // and we want to assert that + // + // Foo <: Foo || + // Foo <: Foo + // + // 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 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(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'tcx, ty::Binder> - where T : Combineable<'tcx> + fn regions(&mut self, a: ty::Region, _: ty::Region) -> RelateResult<'tcx, ty::Region> { + Ok(a) + } + + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + 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)) } } diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index 9aa17b2b1d9fe..86f12b669b35e 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -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>> - { - 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> - { - 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>> - 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>, - b: &Vec>) - -> cres<'tcx, Vec>> - { - // 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(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'tcx, ty::Binder> - 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>(combiner: &C, a: &Self, b: &Self) -> cres<'tcx, Self>; -} - -impl<'tcx,T> Combineable<'tcx> for Rc - where T : Combineable<'tcx> -{ - fn combine(combiner: &C, - a: &Rc, - b: &Rc) - -> cres<'tcx, Rc> - where C: Combine<'tcx> { - Ok(Rc::new(try!(Combineable::combine(combiner, &**a, &**b)))) - } -} - -impl<'tcx> Combineable<'tcx> for ty::TraitRef<'tcx> { - fn combine(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(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(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(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 - 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_float(v), &ty::ty_infer(FloatVar(v_id))) => { - 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_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))) - } + (&ty::ty_float(v), &ty::ty_infer(ty::FloatVar(v_id))) => { + unify_float_variable(infcx, !a_is_expected, v_id, v) } - (&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))) + // 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_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::>() - .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)), + _ => { + ty_relate::super_relate_tys(relation, a, b) } } +} - 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)) +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)), } } -impl<'f, 'tcx> CombineFields<'f, 'tcx> { - pub fn switch_expected(&self) -> CombineFields<'f, 'tcx> { +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()) + } + + pub fn bivariate(&self) -> Bivariate<'a, 'tcx> { + Bivariate::new(self.clone()) + } + + pub fn sub(&self) -> Sub<'a, 'tcx> { + Sub::new(self.clone()) } - fn bivariate(&self) -> Bivariate<'f, 'tcx> { - Bivariate((*self).clone()) + pub fn lub(&self) -> Lub<'a, 'tcx> { + Lub::new(self.clone()) } - fn sub(&self) -> Sub<'f, 'tcx> { - Sub((*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(&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(&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)) +} diff --git a/src/librustc/middle/infer/equate.rs b/src/librustc/middle/infer/equate.rs index 59ed2dfd24f25..2003f459d89b4 100644 --- a/src/librustc/middle/infer/equate.rs +++ b/src/librustc/middle/infer/equate.rs @@ -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>> - { - // Once we're equating, it doesn't matter what the variance is. - self.tys(a, b) - } + fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() } - 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 a_is_expected(&self) -> bool { self.fields.a_is_expected } - 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 relate_with_variance>(&mut self, + _: ty::Variance, + a: &T, + b: &T) + -> RelateResult<'tcx, T> + { + self.relate(a, b) } - 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(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'tcx, ty::Binder> - 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(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + 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) } } diff --git a/src/librustc/middle/infer/freshen.rs b/src/librustc/middle/infer/freshen.rs index e41b949d5df1d..29f74d12ea3e8 100644 --- a/src/librustc/middle/infer/freshen.rs +++ b/src/librustc/middle/infer/freshen.rs @@ -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, diff --git a/src/librustc/middle/infer/glb.rs b/src/librustc/middle/infer/glb.rs index 3b83d37f58234..5822fb0f2d432 100644 --- a/src/librustc/middle/infer/glb.rs +++ b/src/librustc/middle/infer/glb.rs @@ -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 tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.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>(&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(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a, 'tcx> + { + self.fields.higher_ranked_glb(a, b) } +} - fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'tcx, ty::Binder> - where T : Combineable<'tcx> - { - self.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(()) } } diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index 16b387330b9ef..f347d28b93c2b 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -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(&self, a: &Binder, b: &Binder) -> cres<'tcx, Binder> - where T : Combineable<'tcx>; +pub trait HigherRankedRelations<'a,'tcx> { + fn higher_ranked_sub(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> + where T: Relate<'a,'tcx>; - fn higher_ranked_lub(&self, a: &Binder, b: &Binder) -> cres<'tcx, Binder> - where T : Combineable<'tcx>; + fn higher_ranked_lub(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> + where T: Relate<'a,'tcx>; - fn higher_ranked_glb(&self, a: &Binder, b: &Binder) -> cres<'tcx, Binder> - where T : Combineable<'tcx>; + fn higher_ranked_glb(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> + where T: Relate<'a,'tcx>; } trait InferCtxtExt { @@ -40,15 +41,15 @@ trait InferCtxtExt { -> Vec; } -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(&self, a: &Binder, b: &Binder) - -> cres<'tcx, Binder> - where T : Combineable<'tcx> + -> RelateResult<'tcx, Binder> + 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(&self, a: &Binder, b: &Binder) -> cres<'tcx, Binder> - where T : Combineable<'tcx> + fn higher_ranked_lub(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> + 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(&self, a: &Binder, b: &Binder) -> cres<'tcx, Binder> - where T : Combineable<'tcx> + fn higher_ranked_glb(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> + 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) - -> Vec { - 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) + -> Vec { + 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, diff --git a/src/librustc/middle/infer/lattice.rs b/src/librustc/middle/infer/lattice.rs index 9c764628c14f8..57001083b03e2 100644 --- a/src/librustc/middle/infer/lattice.rs +++ b/src/librustc/middle/infer/lattice.rs @@ -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, ()>; -} - -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(()) - } + fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>; } -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) } } } diff --git a/src/librustc/middle/infer/lub.rs b/src/librustc/middle/infer/lub.rs index 5000ab32ff671..f456687be13ac 100644 --- a/src/librustc/middle/infer/lub.rs +++ b/src/librustc/middle/infer/lub.rs @@ -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 tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.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>(&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(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a, 'tcx> + { + self.fields.higher_ranked_lub(a, b) } +} - fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'tcx, ty::Binder> - where T : Combineable<'tcx> - { - self.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(()) } } + diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 4cc9b65c2dab3..da811c354578d 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -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 = Option; - -pub type cres<'tcx, T> = Result>; // "combine result" -pub type ures<'tcx> = cres<'tcx, ()>; // "unify result" +pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result" pub type fres = Result; // "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(a_is_expected: bool, @@ -433,57 +425,6 @@ fn expected_found(a_is_expected: bool, } } -trait then<'tcx> { - fn then(&self, f: F) -> Result> where - T: Clone, - F: FnOnce() -> Result>; -} - -impl<'tcx> then<'tcx> for ures<'tcx> { - fn then(&self, f: F) -> Result> where - T: Clone, - F: FnOnce() -> Result>, - { - 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(&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(&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(&self, f: F) -> Result where - F: FnOnce() -> Result + F: FnOnce(&CombinedSnapshot) -> Result { - 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(&self, f: F) -> Result where - F: FnOnce(&CombinedSnapshot) -> Result - { - 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(&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>, b: Rc>) - -> 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(&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)) } diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index b539dded12e8a..98347e97e09c3 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -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>, + ProcessedErrors(Vec, Vec<(TypeTrace<'tcx>, ty::type_err<'tcx>)>, Vec), } @@ -168,7 +168,7 @@ pub type CombineMap = FnvHashMap; pub struct RegionVarBindings<'a, 'tcx: 'a> { tcx: &'a ty::ctxt<'tcx>, - var_origins: RefCell>>, + var_origins: RefCell>, // 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 diff --git a/src/librustc/middle/infer/sub.rs b/src/librustc/middle/infer/sub.rs index 5d23fe3f1348d..31b654a5b3fd3 100644 --- a/src/librustc/middle/infer/sub.rs +++ b/src/librustc/middle/infer/sub.rs @@ -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 } - - fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) - -> cres<'tcx, Ty<'tcx>> - { - 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), - } - } +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 regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region) - -> cres<'tcx, ty::Region> + fn relate_with_variance>(&mut self, + variance: ty::Variance, + a: &T, + b: &T) + -> RelateResult<'tcx, T> { - 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), + 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(&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(&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 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(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'tcx, ty::Binder> - 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(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a,'tcx> { - self.higher_ranked_sub(a, b) + self.fields.higher_ranked_sub(a, b) } } diff --git a/src/librustc/middle/infer/unify.rs b/src/librustc/middle/infer/unify.rs index 8a736d47b5d89..39271d4cdc597 100644 --- a/src/librustc/middle/infer/unify.rs +++ b/src/librustc/middle/infer/unify.rs @@ -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>; + fn from_index(u: u32) -> Self; fn tag(k: Option) -> &'static str; } @@ -130,21 +122,25 @@ impl UnificationTable { 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 } - /// 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 { - let index = vid.index(); + /// Find the root node for `vid`. This uses the standard + /// union-find algorithm with path compression: + /// . + /// + /// NB. This is a building-block operation and you would probably + /// prefer to call `probe` below. + fn get(&mut self, vid: K) -> Node { + let index = vid.index() as usize; let value = (*self.values.get(index)).clone(); match value { Redirect(redirect) => { - let node: Node = self.get(tcx, redirect.clone()); + let node: Node = self.get(redirect.clone()); if node.key != redirect { // Path compression self.values.set(index, Redirect(node.key.clone())); @@ -158,58 +154,58 @@ impl UnificationTable { } 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) - { + /// 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) { 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, - node_b: &Node) - -> (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, node_b: &Node, 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 sv::SnapshotVecDelegate for Delegate { } /////////////////////////////////////////////////////////////////////////// -// Code to handle simple keys 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) -> 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>, - V : SimplyUnifiable<'tcx>, - Option : 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>; -} - -impl<'a,'tcx,V,K> InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V> for InferCtxt<'a,'tcx> - where K : UnifyKey>, - V : SimplyUnifiable<'tcx>, - Option : UnifyValue, +// Code to handle keys which carry a value, like ints, +// floats---anything that doesn't have a subtyping relationship we +// need to worry about. + +impl<'tcx,K,V> UnificationTable + where K: UnifyKey>, + V: Clone+PartialEq, + Option: 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 = table.borrow_mut().get(tcx, a_id); - let node_b: Node = 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> { - 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 { + self.get(a_id).value.clone() } } @@ -355,33 +299,24 @@ impl<'a,'tcx,V,K> InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V> for InferCtx // Integral type keys +pub trait ToType<'tcx> { + fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx>; +} + impl UnifyKey for ty::IntVid { type Value = Option; - - 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> { - return &infcx.int_unification_table; - } - - fn tag(_: Option) -> &'static str { - "IntVid" - } + fn index(&self) -> u32 { self.index } + fn from_index(i: u32) -> ty::IntVid { ty::IntVid { index: i } } + fn tag(_: Option) -> &'static str { "IntVid" } } -impl<'tcx> SimplyUnifiable<'tcx> for IntVarValue { +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) -> ty::type_err<'tcx> { - return ty::terr_int_mismatch(err); - } } impl UnifyValue for Option { } @@ -390,29 +325,16 @@ impl UnifyValue for Option { } impl UnifyKey for ty::FloatVid { type Value = Option; - - 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> { - return &infcx.float_unification_table; - } - - fn tag(_: Option) -> &'static str { - "FloatVid" - } + fn index(&self) -> u32 { self.index } + fn from_index(i: u32) -> ty::FloatVid { ty::FloatVid { index: i } } + fn tag(_: Option) -> &'static str { "FloatVid" } } impl UnifyValue for Option { } -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) -> ty::type_err<'tcx> { - ty::terr_float_mismatch(err) - } } diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index 1594d8b2e0d04..7488b8f046e74 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -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>, diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index cb9d90744a446..bb2d37c944c86 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -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>, - SelectionResult<'tcx, SelectionCandidate<'tcx>>>>, + hashmap: RefCell>, + 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>, _> = 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,()> = self.infcx.try(|snapshot| { + let trait_obligations: Result,()> = 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()) } } } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index f17ba78007bb2..5f77574f65ed4 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -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>(&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>(&self, _: &mut F) -> () { - () +macro_rules! CopyImpls { + ($($ty:ty),+) => { + $( + impl<'tcx> TypeFoldable<'tcx> for $ty { + fn fold_with>(&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>(&self, folder: &mut F) -> (T, U) { (self.0.fold_with(folder), self.1.fold_with(folder)) diff --git a/src/librustc/middle/ty_match.rs b/src/librustc/middle/ty_match.rs new file mode 100644 index 0000000000000..bb00fadc39c95 --- /dev/null +++ b/src/librustc/middle/ty_match.rs @@ -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 or the MIT license +// , 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>(&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(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a,'tcx> + { + Ok(ty::Binder(try!(self.relate(a.skip_binder(), b.skip_binder())))) + } +} diff --git a/src/librustc/middle/ty_relate/mod.rs b/src/librustc/middle/ty_relate/mod.rs new file mode 100644 index 0000000000000..1205b7d957930 --- /dev/null +++ b/src/librustc/middle/ty_relate/mod.rs @@ -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 or the MIT license +// , 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>; + +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>(&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>(&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(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a,'tcx>; +} + +pub trait Relate<'a,'tcx>: TypeFoldable<'tcx> { + fn relate>(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(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>> + 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> + 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(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(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>> + 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(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(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(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(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> { + fn relate(relation: &mut R, + a: &Vec>, + b: &Vec>) + -> RelateResult<'tcx, Vec>> + 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(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(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(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(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::>()); + 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(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 + where T: Relate<'a,'tcx> +{ + fn relate(relation: &mut R, + a: &ty::Binder, + b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where R: TypeRelation<'a,'tcx> + { + relation.binders(a, b) + } +} + +impl<'a,'tcx:'a,T> Relate<'a,'tcx> for Rc + where T: Relate<'a,'tcx> +{ + fn relate(relation: &mut R, + a: &Rc, + b: &Rc) + -> RelateResult<'tcx, Rc> + 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 + where T: Relate<'a,'tcx> +{ + fn relate(relation: &mut R, + a: &Box, + b: &Box) + -> RelateResult<'tcx, Box> + 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 + where R: TypeRelation<'a,'tcx>, T: Clone +{ + expected_found_bool(relation.a_is_expected(), a, b) +} + +pub fn expected_found_bool(a_is_expected: bool, + a: &T, + b: &T) + -> ty::expected_found + 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} + } +} + diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 4405a9d75ee62..60b422b3769d5 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -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) + } +} diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index ed4d30f300c78..f9be71561e384 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -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) } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 31ac0a57ba0e1..3f9c14e0afe39 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -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> { - 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; + } + _ => {} } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index ae1dbbb1b00ad..ced6cec3ef0dc 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -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>>; +type CoerceResult<'tcx> = RelateResult<'tcx, Option>>; 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) }) })); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 1c5f2c5607857..532277d75b2e0 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -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, _) = diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 49f4399b2c7b4..2f7e0073e1751 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -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); diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 6349ea57f2ff1..e203019bd0638 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -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) } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 3edea6d300444..9171367468026 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -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, diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index eaf07a3ef13a7..51d0c18872dc4 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -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; diff --git a/src/test/compile-fail/dst-bad-coerce1.rs b/src/test/compile-fail/dst-bad-coerce1.rs index ddc929017718d..2d87345db2245 100644 --- a/src/test/compile-fail/dst-bad-coerce1.rs +++ b/src/test/compile-fail/dst-bad-coerce1.rs @@ -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 }; diff --git a/src/test/compile-fail/object-lifetime-default-elision.rs b/src/test/compile-fail/object-lifetime-default-elision.rs index 0077d10e6ca82..4fba45e2a66c5 100644 --- a/src/test/compile-fail/object-lifetime-default-elision.rs +++ b/src/test/compile-fail/object-lifetime-default-elision.rs @@ -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() { diff --git a/src/test/compile-fail/object-lifetime-default-from-box-error.rs b/src/test/compile-fail/object-lifetime-default-from-box-error.rs index 70752cbfda19f..7fae530984f89 100644 --- a/src/test/compile-fail/object-lifetime-default-from-box-error.rs +++ b/src/test/compile-fail/object-lifetime-default-from-box-error.rs @@ -25,7 +25,7 @@ fn load(ss: &mut SomeStruct) -> Box { // `Box` 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) { @@ -38,7 +38,7 @@ fn store(ss: &mut SomeStruct, b: Box) { fn store1<'b>(ss: &mut SomeStruct, b: Box) { // 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() { diff --git a/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs b/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs index 0f8bc6d684f12..10b883d4dc830 100644 --- a/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs +++ b/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs @@ -27,7 +27,7 @@ fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box { fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box { // A outlives 'a AND 'b...but not 'c. - box v as Box //~ ERROR mismatched types + box v as Box //~ ERROR lifetime of the source pointer does not outlive } fn main() { diff --git a/src/test/compile-fail/regions-trait-object-subtyping.rs b/src/test/compile-fail/regions-trait-object-subtyping.rs index 8d05cb67e77b1..f3722690ef895 100644 --- a/src/test/compile-fail/regions-trait-object-subtyping.rs +++ b/src/test/compile-fail/regions-trait-object-subtyping.rs @@ -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 } diff --git a/src/test/run-pass/unboxed-closures-blanket-fn-mut.rs b/src/test/run-pass/unboxed-closures-blanket-fn-mut.rs new file mode 100644 index 0000000000000..37dccca1e2245 --- /dev/null +++ b/src/test/run-pass/unboxed-closures-blanket-fn-mut.rs @@ -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 or the MIT license +// , 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 i32>(mut f: F) -> i32 { + f() +} + +fn b(f: &mut FnMut() -> i32) -> i32 { + a(f) +} + +fn c 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); +} diff --git a/src/test/run-pass/unboxed-closures-blanket-fn.rs b/src/test/run-pass/unboxed-closures-blanket-fn.rs new file mode 100644 index 0000000000000..0f93966077bc3 --- /dev/null +++ b/src/test/run-pass/unboxed-closures-blanket-fn.rs @@ -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 or the MIT license +// , 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 i32>(f: F) -> i32 { + f() +} + +fn b(f: &Fn() -> i32) -> i32 { + a(f) +} + +fn c 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); +}