diff --git a/src/librustc/middle/infer/bivariate.rs b/src/librustc/middle/infer/bivariate.rs index 2d9432b75e719..a7edf546d6865 100644 --- a/src/librustc/middle/infer/bivariate.rs +++ b/src/librustc/middle/infer/bivariate.rs @@ -28,25 +28,28 @@ use super::combine::{self, CombineFields}; use super::type_variable::{BiTo}; +use middle::traits::PredicateObligation; use middle::ty::{self, Ty}; use middle::ty::TyVar; use middle::ty::relate::{Relate, RelateResult, TypeRelation}; -pub struct Bivariate<'a, 'tcx: 'a> { - fields: CombineFields<'a, 'tcx> +pub struct Bivariate<'a, 'o, 'tcx: 'a + 'o> { + fields: CombineFields<'a, 'o, 'tcx> } -impl<'a, 'tcx> Bivariate<'a, 'tcx> { - pub fn new(fields: CombineFields<'a, 'tcx>) -> Bivariate<'a, 'tcx> { +impl<'a, 'o, 'tcx> Bivariate<'a, 'o, 'tcx> { + pub fn new(fields: CombineFields<'a, 'o, 'tcx>) -> Bivariate<'a, 'o, 'tcx> { Bivariate { fields: fields } } } -impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Bivariate<'a, 'tcx> { +impl<'a, 'o, 'tcx> TypeRelation<'a, 'tcx> for Bivariate<'a, 'o, 'tcx> { fn tag(&self) -> &'static str { "Bivariate" } fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() } + fn obligations(&self) -> &Vec> { self.fields.obligations } + fn a_is_expected(&self) -> bool { self.fields.a_is_expected } fn relate_with_variance>(&mut self, diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index faf1bdb0ce504..5f2979c837e91 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -41,6 +41,7 @@ use super::{InferCtxt}; use super::{MiscVariable, TypeTrace}; use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf}; +use middle::traits::PredicateObligation; use middle::ty::{IntType, UintType}; use middle::ty::{self, Ty}; use middle::ty::error::TypeError; @@ -50,12 +51,12 @@ use middle::ty::relate::{Relate, RelateResult, TypeRelation}; use syntax::ast; use syntax::codemap::Span; -#[derive(Clone)] -pub struct CombineFields<'a, 'tcx: 'a> { +pub struct CombineFields<'a, 'o, 'tcx: 'a + 'o> { pub infcx: &'a InferCtxt<'a, 'tcx>, pub a_is_expected: bool, pub trace: TypeTrace<'tcx>, pub cause: Option, + pub obligations: &'o mut Vec>, } pub fn super_combine_tys<'a,'tcx:'a,R>(infcx: &InferCtxt<'a, 'tcx>, @@ -148,39 +149,49 @@ fn unify_float_variable<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, Ok(infcx.tcx.mk_mach_float(val)) } -impl<'a, 'tcx> CombineFields<'a, 'tcx> { +impl<'a, 'o, 'tcx> CombineFields<'a, 'o, 'tcx> { pub fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.infcx.tcx } - pub fn switch_expected(&self) -> CombineFields<'a, 'tcx> { + pub fn switch_expected<'s>(&'s mut self) -> CombineFields<'a, 's, 'tcx> { CombineFields { a_is_expected: !self.a_is_expected, - ..(*self).clone() + ..(*self).clone_and_reborrow() } } - pub fn equate(&self) -> Equate<'a, 'tcx> { - Equate::new(self.clone()) + pub fn clone_and_reborrow<'s>(&'s mut self) -> CombineFields<'a, 's, 'tcx> { + CombineFields { + infcx: self.infcx, + a_is_expected: self.a_is_expected, + trace: self.trace.clone(), + cause: self.cause.clone(), + obligations: self.obligations, + } + } + + pub fn equate<'s>(&'s mut self) -> Equate<'a, 's, 'tcx> { + Equate::new(self.clone_and_reborrow()) } - pub fn bivariate(&self) -> Bivariate<'a, 'tcx> { - Bivariate::new(self.clone()) + pub fn bivariate<'s>(&'s mut self) -> Bivariate<'a, 's, 'tcx> { + Bivariate::new(self.clone_and_reborrow()) } - pub fn sub(&self) -> Sub<'a, 'tcx> { - Sub::new(self.clone()) + pub fn sub<'s>(&'s mut self) -> Sub<'a, 's, 'tcx> { + Sub::new(self.clone_and_reborrow()) } - pub fn lub(&self) -> Lub<'a, 'tcx> { - Lub::new(self.clone()) + pub fn lub<'s>(&'s mut self) -> Lub<'a, 's, 'tcx> { + Lub::new(self.clone_and_reborrow()) } - pub fn glb(&self) -> Glb<'a, 'tcx> { - Glb::new(self.clone()) + pub fn glb<'s>(&'s mut self) -> Glb<'a, 's, 'tcx> { + Glb::new(self.clone_and_reborrow()) } - pub fn instantiate(&self, + pub fn instantiate(&mut self, a_ty: Ty<'tcx>, dir: RelationDir, b_vid: ty::TyVid) diff --git a/src/librustc/middle/infer/equate.rs b/src/librustc/middle/infer/equate.rs index d1dad4921ae21..8d2740c9a31ae 100644 --- a/src/librustc/middle/infer/equate.rs +++ b/src/librustc/middle/infer/equate.rs @@ -13,26 +13,29 @@ use super::higher_ranked::HigherRankedRelations; use super::{Subtype}; use super::type_variable::{EqTo}; +use middle::traits::PredicateObligation; use middle::ty::{self, Ty}; use middle::ty::TyVar; use middle::ty::relate::{Relate, RelateResult, TypeRelation}; /// Ensures `a` is made equal to `b`. Returns `a` on success. -pub struct Equate<'a, 'tcx: 'a> { - fields: CombineFields<'a, 'tcx> +pub struct Equate<'a, 'o, 'tcx: 'a + 'o> { + fields: CombineFields<'a, 'o, 'tcx> } -impl<'a, 'tcx> Equate<'a, 'tcx> { - pub fn new(fields: CombineFields<'a, 'tcx>) -> Equate<'a, 'tcx> { +impl<'a, 'o, 'tcx> Equate<'a, 'o, 'tcx> { + pub fn new(fields: CombineFields<'a, 'o, 'tcx>) -> Equate<'a, 'o, 'tcx> { Equate { fields: fields } } } -impl<'a, 'tcx> TypeRelation<'a,'tcx> for Equate<'a, 'tcx> { +impl<'a, 'o, 'tcx> TypeRelation<'a,'tcx> for Equate<'a, 'o, 'tcx> { fn tag(&self) -> &'static str { "Equate" } fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() } + fn obligations(&self) -> &Vec> { self.fields.obligations } + fn a_is_expected(&self) -> bool { self.fields.a_is_expected } fn relate_with_variance>(&mut self, diff --git a/src/librustc/middle/infer/glb.rs b/src/librustc/middle/infer/glb.rs index 0035f31e8db94..971ff84932e8f 100644 --- a/src/librustc/middle/infer/glb.rs +++ b/src/librustc/middle/infer/glb.rs @@ -14,25 +14,28 @@ use super::InferCtxt; use super::lattice::{self, LatticeDir}; use super::Subtype; +use middle::traits::PredicateObligation; use middle::ty::{self, Ty}; use middle::ty::relate::{Relate, RelateResult, TypeRelation}; /// "Greatest lower bound" (common subtype) -pub struct Glb<'a, 'tcx: 'a> { - fields: CombineFields<'a, 'tcx> +pub struct Glb<'a, 'o, 'tcx: 'a + 'o> { + fields: CombineFields<'a, 'o, 'tcx> } -impl<'a, 'tcx> Glb<'a, 'tcx> { - pub fn new(fields: CombineFields<'a, 'tcx>) -> Glb<'a, 'tcx> { +impl<'a, 'o, 'tcx> Glb<'a, 'o, 'tcx> { + pub fn new(fields: CombineFields<'a, 'o, 'tcx>) -> Glb<'a, 'o, 'tcx> { Glb { fields: fields } } } -impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Glb<'a, 'tcx> { +impl<'a, 'o, 'tcx> TypeRelation<'a, 'tcx> for Glb<'a, 'o, 'tcx> { fn tag(&self) -> &'static str { "Glb" } fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() } + fn obligations(&self) -> &Vec> { self.fields.obligations } + fn a_is_expected(&self) -> bool { self.fields.a_is_expected } fn relate_with_variance>(&mut self, @@ -71,12 +74,12 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Glb<'a, 'tcx> { } } -impl<'a, 'tcx> LatticeDir<'a,'tcx> for Glb<'a, 'tcx> { +impl<'a, 'o, 'tcx> LatticeDir<'a,'tcx> for Glb<'a, 'o, '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, ()> { + fn relate_bound(&mut 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)); diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index e8f542db933cb..10d89a7fce92d 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -21,13 +21,16 @@ use syntax::codemap::Span; use util::nodemap::{FnvHashMap, FnvHashSet}; pub trait HigherRankedRelations<'a,'tcx> { - fn higher_ranked_sub(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> + fn higher_ranked_sub(&mut self, a: &Binder, b: &Binder) + -> RelateResult<'tcx, Binder> where T: Relate<'a,'tcx>; - fn higher_ranked_lub(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> + fn higher_ranked_lub(&mut self, a: &Binder, b: &Binder) + -> RelateResult<'tcx, Binder> where T: Relate<'a,'tcx>; - fn higher_ranked_glb(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> + fn higher_ranked_glb(&mut self, a: &Binder, b: &Binder) + -> RelateResult<'tcx, Binder> where T: Relate<'a,'tcx>; } @@ -39,8 +42,8 @@ trait InferCtxtExt { -> Vec; } -impl<'a,'tcx> HigherRankedRelations<'a,'tcx> for CombineFields<'a,'tcx> { - fn higher_ranked_sub(&self, a: &Binder, b: &Binder) +impl<'a,'o,'tcx> HigherRankedRelations<'a,'tcx> for CombineFields<'a,'o,'tcx> { + fn higher_ranked_sub(&mut self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> where T: Relate<'a,'tcx> { @@ -101,7 +104,8 @@ impl<'a,'tcx> HigherRankedRelations<'a,'tcx> for CombineFields<'a,'tcx> { }); } - fn higher_ranked_lub(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> + fn higher_ranked_lub(&mut self, a: &Binder, b: &Binder) + -> RelateResult<'tcx, Binder> where T: Relate<'a,'tcx> { // Start a snapshot so we can examine "all bindings that were @@ -191,7 +195,8 @@ impl<'a,'tcx> HigherRankedRelations<'a,'tcx> for CombineFields<'a,'tcx> { } } - fn higher_ranked_glb(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> + fn higher_ranked_glb(&mut self, a: &Binder, b: &Binder) + -> RelateResult<'tcx, Binder> where T: Relate<'a,'tcx> { debug!("higher_ranked_glb({:?}, {:?})", @@ -329,9 +334,10 @@ impl<'a,'tcx> HigherRankedRelations<'a,'tcx> for CombineFields<'a,'tcx> { } } -fn var_ids<'a, 'tcx>(fields: &CombineFields<'a, 'tcx>, - map: &FnvHashMap) - -> Vec { +fn var_ids<'a, 'o, 'tcx>(fields: &CombineFields<'a, 'o, 'tcx>, + map: &FnvHashMap) + -> Vec +{ map.iter() .map(|(_, r)| match *r { ty::ReVar(r) => { r } @@ -486,7 +492,7 @@ pub fn leak_check<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, -> Result<(),(ty::BoundRegion,ty::Region)> { /*! - * Searches the region constriants created since `snapshot` was started + * Searches the region constraints created since `snapshot` was started * and checks to determine whether any of the skolemized regions created * in `skol_map` would "escape" -- meaning that they are related to * other regions in some way. If so, the higher-ranked subtyping doesn't @@ -531,7 +537,7 @@ pub fn leak_check<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, /// /// This routine is only intended to be used when the leak-check has /// passed; currently, it's used in the trait matching code to create -/// a set of nested obligations frmo an impl that matches against +/// a set of nested obligations from an impl that matches against /// something higher-ranked. More details can be found in /// `librustc/middle/traits/README.md`. /// diff --git a/src/librustc/middle/infer/lattice.rs b/src/librustc/middle/infer/lattice.rs index 2a560ec8a1d23..8877a5c3f14c3 100644 --- a/src/librustc/middle/infer/lattice.rs +++ b/src/librustc/middle/infer/lattice.rs @@ -41,7 +41,7 @@ pub trait LatticeDir<'f,'tcx> : TypeRelation<'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>) -> RelateResult<'tcx, ()>; + fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>; } pub fn super_lattice_tys<'a,'tcx,L:LatticeDir<'a,'tcx>>(this: &mut L, diff --git a/src/librustc/middle/infer/lub.rs b/src/librustc/middle/infer/lub.rs index 238dad65ef0d9..e72e9beb9c1d2 100644 --- a/src/librustc/middle/infer/lub.rs +++ b/src/librustc/middle/infer/lub.rs @@ -14,25 +14,28 @@ use super::InferCtxt; use super::lattice::{self, LatticeDir}; use super::Subtype; +use middle::traits::PredicateObligation; use middle::ty::{self, Ty}; use middle::ty::relate::{Relate, RelateResult, TypeRelation}; /// "Least upper bound" (common supertype) -pub struct Lub<'a, 'tcx: 'a> { - fields: CombineFields<'a, 'tcx> +pub struct Lub<'a, 'o, 'tcx: 'a + 'o> { + fields: CombineFields<'a, 'o, 'tcx> } -impl<'a, 'tcx> Lub<'a, 'tcx> { - pub fn new(fields: CombineFields<'a, 'tcx>) -> Lub<'a, 'tcx> { +impl<'a, 'o, 'tcx> Lub<'a, 'o, 'tcx> { + pub fn new(fields: CombineFields<'a, 'o, 'tcx>) -> Lub<'a, 'o, 'tcx> { Lub { fields: fields } } } -impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Lub<'a, 'tcx> { +impl<'a, 'o, 'tcx> TypeRelation<'a, 'tcx> for Lub<'a, 'o, 'tcx> { fn tag(&self) -> &'static str { "Lub" } fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() } + fn obligations(&self) -> &Vec> { self.fields.obligations } + fn a_is_expected(&self) -> bool { self.fields.a_is_expected } fn relate_with_variance>(&mut self, @@ -71,12 +74,12 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Lub<'a, 'tcx> { } } -impl<'a, 'tcx> LatticeDir<'a,'tcx> for Lub<'a, 'tcx> { +impl<'a, 'o, 'tcx> LatticeDir<'a,'tcx> for Lub<'a, 'o, '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, ()> { + fn relate_bound(&mut 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)); diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 26ea5454693e1..63bb4dc6b08cb 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -27,13 +27,13 @@ use middle::region::CodeExtent; use middle::subst; use middle::subst::Substs; use middle::subst::Subst; -use middle::traits; +use middle::traits::{self, PredicateObligation}; use middle::ty::adjustment; use middle::ty::{TyVid, IntVid, FloatVid}; use middle::ty::{self, Ty}; use middle::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; use middle::ty::fold::{TypeFolder, TypeFoldable}; -use middle::ty::relate::{Relate, RelateResult, TypeRelation}; +use middle::ty::relate::{Relate, TypeRelation}; use rustc_data_structures::unify::{self, UnificationTable}; use std::cell::{RefCell, Ref}; use std::fmt; @@ -63,8 +63,14 @@ pub mod sub; pub mod type_variable; pub mod unify_key; +pub struct InferOk<'tcx, T> { + pub value: T, + pub obligations: Vec>, +} +pub type InferResult<'tcx> = Result, TypeError<'tcx>>; + pub type Bound = Option; -pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result" +pub type UnitResult<'tcx> = Result<(), TypeError<'tcx>>; // "unify result" pub type FixupResult = Result; // "fixup result" pub struct InferCtxt<'a, 'tcx: 'a> { @@ -385,7 +391,7 @@ pub fn common_supertype<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a_is_expected: bool, a: Ty<'tcx>, b: Ty<'tcx>) - -> Ty<'tcx> + -> InferOk<'tcx, Ty<'tcx>> { debug!("common_supertype({:?}, {:?})", a, b); @@ -395,12 +401,15 @@ 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()).relate(&a, &b)); + let mut obligations = Vec::new(); + let result = cx.commit_if_ok(|_| { + cx.lub(a_is_expected, trace.clone(), &mut obligations).relate(&a, &b) + }); match result { - Ok(t) => t, + Ok(t) => InferOk { value: t, obligations: obligations }, Err(ref err) => { cx.report_and_explain_type_error(trace, err); - cx.tcx.types.err + InferOk { value: cx.tcx.types.err, obligations: Vec::new() } } } } @@ -410,7 +419,7 @@ pub fn mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, origin: TypeOrigin, a: Ty<'tcx>, b: Ty<'tcx>) - -> UnitResult<'tcx> + -> InferResult<'tcx> { debug!("mk_subty({:?} <: {:?})", a, b); cx.sub_types(a_is_expected, origin, a, b) @@ -419,19 +428,21 @@ pub fn mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) - -> UnitResult<'tcx> { + -> InferResult<'tcx> { debug!("can_mk_subty({:?} <: {:?})", a, b); cx.probe(|_| { let trace = TypeTrace { origin: TypeOrigin::Misc(codemap::DUMMY_SP), values: Types(expected_found(true, a, b)) }; - cx.sub(true, trace).relate(&a, &b).map(|_| ()) + let mut obligations = Vec::new(); + cx.sub(true, trace, &mut obligations).relate(&a, &b) + .map(|_| InferOk { value: (), obligations: obligations }) }) } pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) - -> UnitResult<'tcx> + -> InferResult<'tcx> { cx.can_equate(&a, &b) } @@ -451,7 +462,7 @@ pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, origin: TypeOrigin, a: Ty<'tcx>, b: Ty<'tcx>) - -> UnitResult<'tcx> + -> InferResult<'tcx> { debug!("mk_eqty({:?} <: {:?})", a, b); cx.commit_if_ok(|_| cx.eq_types(a_is_expected, origin, a, b)) @@ -462,7 +473,7 @@ pub fn mk_eq_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, origin: TypeOrigin, a: ty::TraitRef<'tcx>, b: ty::TraitRef<'tcx>) - -> UnitResult<'tcx> + -> InferResult<'tcx> { debug!("mk_eq_trait_refs({:?} <: {:?})", a, b); @@ -474,7 +485,7 @@ pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, origin: TypeOrigin, a: ty::PolyTraitRef<'tcx>, b: ty::PolyTraitRef<'tcx>) - -> UnitResult<'tcx> + -> InferResult<'tcx> { debug!("mk_sub_poly_trait_refs({:?} <: {:?})", a, b); @@ -661,40 +672,49 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { return variables; } - 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, - cause: None} + fn combine_fields<'o>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, + obligations: &'o mut Vec>) + -> CombineFields<'a, 'o, 'tcx> + { + CombineFields { + infcx: self, + a_is_expected: a_is_expected, + trace: trace, + cause: None, + obligations: obligations + } } // 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> + pub fn equate<'o>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, + obligations: &'o mut Vec>) + -> equate::Equate<'a, 'o, 'tcx> { - self.combine_fields(a_is_expected, trace).equate() + equate::Equate::new(self.combine_fields(a_is_expected, trace, obligations)) } // 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> + pub fn sub<'o>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, + obligations: &'o mut Vec>) + -> sub::Sub<'a, 'o, 'tcx> { - self.combine_fields(a_is_expected, trace).sub() + sub::Sub::new(self.combine_fields(a_is_expected, trace, obligations)) } // 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> + pub fn lub<'o>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, + obligations: &'o mut Vec>) + -> lub::Lub<'a, 'o, 'tcx> { - self.combine_fields(a_is_expected, trace).lub() + lub::Lub::new(self.combine_fields(a_is_expected, trace, obligations)) } // 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> + pub fn glb<'o>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, + obligations: &'o mut Vec>) + -> glb::Glb<'a, 'o, 'tcx> { - self.combine_fields(a_is_expected, trace).glb() + glb::Glb::new(self.combine_fields(a_is_expected, trace, obligations)) } fn start_snapshot(&self) -> CombinedSnapshot { @@ -830,12 +850,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: TypeOrigin, a: Ty<'tcx>, b: Ty<'tcx>) - -> UnitResult<'tcx> + -> InferResult<'tcx> { debug!("sub_types({:?} <: {:?})", a, b); self.commit_if_ok(|_| { let trace = TypeTrace::types(origin, a_is_expected, a, b); - self.sub(a_is_expected, trace).relate(&a, &b).map(|_| ()) + let mut obligations = Vec::new(); + self.sub(a_is_expected, trace, &mut obligations).relate(&a, &b) + .map(|_| InferOk { value: (), obligations: obligations }) }) } @@ -844,11 +866,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: TypeOrigin, a: Ty<'tcx>, b: Ty<'tcx>) - -> UnitResult<'tcx> + -> InferResult<'tcx> { self.commit_if_ok(|_| { let trace = TypeTrace::types(origin, a_is_expected, a, b); - self.equate(a_is_expected, trace).relate(&a, &b).map(|_| ()) + let mut obligations = Vec::new(); + self.equate(a_is_expected, trace, &mut obligations).relate(&a, &b) + .map(|_| InferOk { value: (), obligations: obligations }) }) } @@ -857,7 +881,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: TypeOrigin, a: ty::TraitRef<'tcx>, b: ty::TraitRef<'tcx>) - -> UnitResult<'tcx> + -> InferResult<'tcx> { debug!("eq_trait_refs({:?} <: {:?})", a, @@ -867,7 +891,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: origin, values: TraitRefs(expected_found(a_is_expected, a.clone(), b.clone())) }; - self.equate(a_is_expected, trace).relate(&a, &b).map(|_| ()) + let mut obligations = Vec::new(); + self.equate(a_is_expected, trace, &mut obligations).relate(&a, &b) + .map(|_| InferOk { value: (), obligations: obligations }) }) } @@ -876,7 +902,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: TypeOrigin, a: ty::PolyTraitRef<'tcx>, b: ty::PolyTraitRef<'tcx>) - -> UnitResult<'tcx> + -> InferResult<'tcx> { debug!("sub_poly_trait_refs({:?} <: {:?})", a, @@ -886,7 +912,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: origin, values: PolyTraitRefs(expected_found(a_is_expected, a.clone(), b.clone())) }; - self.sub(a_is_expected, trace).relate(&a, &b).map(|_| ()) + let mut obligations = Vec::new(); + self.sub(a_is_expected, trace, &mut obligations).relate(&a, &b) + .map(|_| InferOk { value: (), obligations: obligations }) }) } @@ -929,13 +957,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn equality_predicate(&self, span: Span, predicate: &ty::PolyEquatePredicate<'tcx>) - -> UnitResult<'tcx> { + -> InferResult<'tcx> { self.commit_if_ok(|snapshot| { let (ty::EquatePredicate(a, b), skol_map) = self.skolemize_late_bound_regions(predicate, snapshot); let origin = TypeOrigin::EquatePredicate(span); - let () = try!(mk_eqty(self, false, origin, a, b)); + let InferOk { obligations, .. } = try!(mk_eqty(self, false, origin, a, b)); self.leak_check(&skol_map, snapshot) + .map(|_| InferOk { value: (), obligations: obligations }) }) } @@ -1411,7 +1440,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.region_vars.verify_generic_bound(origin, kind, a, bound); } - pub fn can_equate<'b,T>(&'b self, a: &T, b: &T) -> UnitResult<'tcx> + pub fn can_equate<'b,T>(&'b self, a: &T, b: &T) -> InferResult<'tcx> where T: Relate<'b,'tcx> + fmt::Debug { debug!("can_equate({:?}, {:?})", a, b); @@ -1425,8 +1454,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: TypeOrigin::Misc(codemap::DUMMY_SP), values: Types(expected_found(true, e, e)) }; - self.equate(true, trace).relate(a, b) - }).map(|_| ()) + let mut obligations = Vec::new(); + self.equate(true, trace, &mut obligations).relate(a, b) + .map(|_| InferOk { value: (), obligations: obligations }) + }) } pub fn node_ty(&self, id: ast::NodeId) -> McResult> { diff --git a/src/librustc/middle/infer/sub.rs b/src/librustc/middle/infer/sub.rs index 2cd686fde156e..4d2efbf91eabb 100644 --- a/src/librustc/middle/infer/sub.rs +++ b/src/librustc/middle/infer/sub.rs @@ -13,25 +13,27 @@ use super::higher_ranked::HigherRankedRelations; use super::SubregionOrigin; use super::type_variable::{SubtypeOf, SupertypeOf}; +use middle::traits::PredicateObligation; use middle::ty::{self, Ty}; use middle::ty::TyVar; use middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation}; use std::mem; /// Ensures `a` is made a subtype of `b`. Returns `a` on success. -pub struct Sub<'a, 'tcx: 'a> { - fields: CombineFields<'a, 'tcx>, +pub struct Sub<'a, 'o, 'tcx: 'a + 'o> { + fields: CombineFields<'a, 'o, 'tcx>, } -impl<'a, 'tcx> Sub<'a, 'tcx> { - pub fn new(f: CombineFields<'a, 'tcx>) -> Sub<'a, 'tcx> { +impl<'a, 'o, 'tcx> Sub<'a, 'o, 'tcx> { + pub fn new(f: CombineFields<'a, 'o, 'tcx>) -> Sub<'a, 'o, 'tcx> { Sub { fields: f } } } -impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Sub<'a, 'tcx> { +impl<'a, 'o, 'tcx> TypeRelation<'a, 'tcx> for Sub<'a, 'o, 'tcx> { fn tag(&self) -> &'static str { "Sub" } fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.infcx.tcx } + fn obligations(&self) -> &Vec> { self.fields.obligations } fn a_is_expected(&self) -> bool { self.fields.a_is_expected } fn with_cause(&mut self, cause: Cause, f: F) -> R diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index de70cdbd29a35..5527b74ba9717 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -9,7 +9,7 @@ // except according to those terms. use dep_graph::DepGraph; -use middle::infer::InferCtxt; +use middle::infer::{InferCtxt, InferOk}; use middle::ty::{self, Ty, TypeFoldable, ToPolyTraitRef}; use rustc_data_structures::obligation_forest::{Backtrace, ObligationForest, Error}; use std::iter; @@ -526,7 +526,7 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, ty::Predicate::Equate(ref binder) => { match selcx.infcx().equality_predicate(obligation.cause.span, binder) { - Ok(()) => Ok(Some(Vec::new())), + Ok(InferOk { obligations, .. }) => Ok(Some(obligations)), Err(_) => Err(CodeSelectionError(Unimplemented)), } } diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index c363425db85b0..b530017c34b8a 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -10,6 +10,8 @@ //! Code for projecting associated types out of trait references. +use std::mem; + use super::elaborate_predicates; use super::report_overflow_error; use super::Obligation; @@ -21,7 +23,7 @@ use super::VtableClosureData; use super::VtableImplData; use super::util; -use middle::infer::{self, TypeOrigin}; +use middle::infer::{self, TypeOrigin, InferOk}; use middle::subst::Subst; use middle::ty::{self, ToPredicate, ToPolyTraitRef, Ty}; use middle::ty::fold::{TypeFoldable, TypeFolder}; @@ -121,15 +123,14 @@ fn project_and_unify_type<'cx,'tcx>( debug!("project_and_unify_type(obligation={:?})", obligation); - let Normalized { value: normalized_ty, obligations } = + let Normalized { value: normalized_ty, mut obligations } = match opt_normalize_projection_type(selcx, obligation.predicate.projection_ty.clone(), obligation.cause.clone(), obligation.recursion_depth) { Some(n) => n, None => { - consider_unification_despite_ambiguity(selcx, obligation); - return Ok(None); + return Ok(consider_unification_despite_ambiguity(selcx, obligation)); } }; @@ -140,20 +141,25 @@ fn project_and_unify_type<'cx,'tcx>( let infcx = selcx.infcx(); let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); match infer::mk_eqty(infcx, true, origin, normalized_ty, obligation.predicate.ty) { - Ok(()) => Ok(Some(obligations)), + Ok(InferOk { obligations: new_obligations, .. }) => { + obligations.extend(new_obligations); + Ok(Some(obligations)) + }, Err(err) => Err(MismatchedProjectionTypes { err: err }), } } fn consider_unification_despite_ambiguity<'cx,'tcx>(selcx: &mut SelectionContext<'cx,'tcx>, - obligation: &ProjectionObligation<'tcx>) { + obligation: &ProjectionObligation<'tcx>) + -> Option>> +{ debug!("consider_unification_despite_ambiguity(obligation={:?})", obligation); let def_id = obligation.predicate.projection_ty.trait_ref.def_id; match selcx.tcx().lang_items.fn_trait_kind(def_id) { Some(_) => { } - None => { return; } + None => { return None; } } let infcx = selcx.infcx(); @@ -186,11 +192,11 @@ fn consider_unification_despite_ambiguity<'cx,'tcx>(selcx: &mut SelectionContext let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); let obligation_ty = obligation.predicate.ty; match infer::mk_eqty(infcx, true, origin, obligation_ty, ret_type) { - Ok(()) => { } - Err(_) => { /* ignore errors */ } + Ok(InferOk { obligations, .. }) => { Some(obligations) } + Err(_) => { /* ignore errors */ None } } } - _ => { } + _ => { None } } } @@ -917,11 +923,12 @@ fn confirm_param_env_candidate<'cx,'tcx>( obligation.predicate.item_name); let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); + let mut infer_obligations = Vec::new(); match infcx.eq_trait_refs(false, origin, obligation.predicate.trait_ref.clone(), projection.projection_ty.trait_ref.clone()) { - Ok(()) => { } + Ok(InferOk { obligations, .. }) => { mem::replace(&mut infer_obligations, obligations); } Err(e) => { selcx.tcx().sess.span_bug( obligation.cause.span, @@ -932,7 +939,7 @@ fn confirm_param_env_candidate<'cx,'tcx>( } } - (projection.ty, vec!()) + (projection.ty, infer_obligations) } fn confirm_impl_candidate<'cx,'tcx>( diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 29355e0684d96..11eb56171ad6d 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -37,7 +37,7 @@ use super::util; use middle::def_id::DefId; use middle::infer; -use middle::infer::{InferCtxt, TypeFreshener, TypeOrigin}; +use middle::infer::{InferCtxt, TypeFreshener, TypeOrigin, InferOk}; use middle::subst::{Subst, Substs, TypeSpace}; use middle::ty::{self, ToPredicate, ToPolyTraitRef, Ty, TypeFoldable}; use middle::ty::fast_reject; @@ -453,7 +453,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn evaluate_predicate_recursively<'o>(&mut self, previous_stack: TraitObligationStackList<'o, 'tcx>, obligation: &PredicateObligation<'tcx>) - -> EvaluationResult + -> EvaluationResult { debug!("evaluate_predicate_recursively({:?})", obligation); @@ -476,7 +476,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::Predicate::Equate(ref p) => { // does this code ever run? match self.infcx.equality_predicate(obligation.cause.span, p) { - Ok(()) => EvaluatedToOk, + Ok(InferOk { obligations, .. }) => + self.evaluate_predicates_recursively(previous_stack, obligations.iter()), Err(_) => EvaluatedToErr } } @@ -1164,7 +1165,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { origin, trait_bound.clone(), ty::Binder(skol_trait_ref.clone())) { - Ok(()) => { } + Ok(InferOk { obligations, .. }) => { + // FIXME Once obligations start getting generated, they ought to be propagated. + assert!(obligations.is_empty()); + } Err(_) => { return false; } } @@ -2453,7 +2457,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { origin, expected_trait_ref.clone(), obligation_trait_ref.clone()) { - Ok(()) => Ok(()), + Ok(InferOk { obligations, .. }) => { + // FIXME Once obligations start getting generated, they ought tobe propagated. + assert!(obligations.is_empty()); + Ok(()) + }, Err(e) => Err(OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e)) } } @@ -2770,7 +2778,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { origin, poly_trait_ref, obligation.predicate.to_poly_trait_ref()) { - Ok(()) => Ok(()), + Ok(InferOk { obligations, .. }) => { + // FIXME Once obligations start getting generated, they ought to be propagated. + assert!(obligations.is_empty()); + Ok(()) + }, Err(_) => Err(()), } } @@ -2783,7 +2795,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { current: &ty::PolyTraitRef<'tcx>) -> bool { - let mut matcher = ty::_match::Match::new(self.tcx()); + let mut obligations = Vec::new(); + let mut matcher = ty::_match::Match::new(self.tcx(), &mut obligations); matcher.relate(previous, current).is_ok() } diff --git a/src/librustc/middle/ty/_match.rs b/src/librustc/middle/ty/_match.rs index 5a3ad9095ad2c..2156a03ebc76c 100644 --- a/src/librustc/middle/ty/_match.rs +++ b/src/librustc/middle/ty/_match.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use middle::traits::PredicateObligation; + use middle::ty::{self, Ty}; use middle::ty::error::TypeError; use middle::ty::relate::{self, Relate, TypeRelation, RelateResult}; @@ -29,18 +31,22 @@ use middle::ty::relate::{self, Relate, TypeRelation, RelateResult}; /// 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> + tcx: &'a ty::ctxt<'tcx>, + obligations: &'a mut Vec>, } impl<'a, 'tcx> Match<'a, 'tcx> { - pub fn new(tcx: &'a ty::ctxt<'tcx>) -> Match<'a, 'tcx> { - Match { tcx: tcx } + pub fn new(tcx: &'a ty::ctxt<'tcx>, obligations: &'a mut Vec>) + -> Match<'a, 'tcx> + { + Match { tcx: tcx, obligations: obligations } } } 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 obligations(&self) -> &Vec> { self.obligations } fn a_is_expected(&self) -> bool { true } // irrelevant fn relate_with_variance>(&mut self, diff --git a/src/librustc/middle/ty/relate.rs b/src/librustc/middle/ty/relate.rs index 974b5c4bc6c2a..5a237b6be28bd 100644 --- a/src/librustc/middle/ty/relate.rs +++ b/src/librustc/middle/ty/relate.rs @@ -15,6 +15,7 @@ use middle::def_id::DefId; use middle::subst::{ErasedRegions, NonerasedRegions, ParamSpace, Substs}; +use middle::traits::PredicateObligation; use middle::ty::{self, Ty, TypeFoldable}; use middle::ty::error::{ExpectedFound, TypeError}; use std::rc::Rc; @@ -31,6 +32,9 @@ pub enum Cause { pub trait TypeRelation<'a,'tcx> : Sized { fn tcx(&self) -> &'a ty::ctxt<'tcx>; + /// Obligations that have been collected over the course of using this relation. + fn obligations(&self) -> &Vec>; + /// Returns a static string we can use for printouts. fn tag(&self) -> &'static str; diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 3220295d9b88a..75473a19b14c8 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -30,6 +30,7 @@ use rustc_typeck::middle::infer::glb::Glb; use rustc_typeck::middle::infer::sub::Sub; use rustc_metadata::cstore::CStore; use rustc::front::map as hir_map; +use rustc::middle::traits::PredicateObligation; use rustc::session::{self, config}; use std::rc::Rc; use syntax::ast; @@ -351,27 +352,36 @@ impl<'a, 'tcx> Env<'a, 'tcx> { infer::TypeTrace::dummy(self.tcx()) } - pub fn sub(&self) -> Sub<'a, 'tcx> { + pub fn with_sub FnMut(Sub<'a, 'b, 'tcx>) -> T>(&self, mut f: F) + -> (T, Vec>) + { let trace = self.dummy_type_trace(); - self.infcx.sub(true, trace) + let mut obligations = Vec::new(); + (f(self.infcx.sub(true, trace, &mut obligations)), obligations) } - pub fn lub(&self) -> Lub<'a, 'tcx> { + pub fn with_lub FnMut(Lub<'a, 'b, 'tcx>) -> T>(&self, mut f: F) + -> (T, Vec>) + { let trace = self.dummy_type_trace(); - self.infcx.lub(true, trace) + let mut obligations = Vec::new(); + (f(self.infcx.lub(true, trace, &mut obligations)), obligations) } - pub fn glb(&self) -> Glb<'a, 'tcx> { + pub fn with_glb FnMut(Glb<'a, 'b, 'tcx>) -> T>(&self, mut f: F) + -> (T, Vec>) + { let trace = self.dummy_type_trace(); - self.infcx.glb(true, trace) + let mut obligations = Vec::new(); + (f(self.infcx.glb(true, trace, &mut obligations)), obligations) } /// 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().relate(&t1, &t2) { - Ok(_) => {} - Err(ref e) => { + match self.with_sub(|mut sub| sub.relate(&t1, &t2)) { + (Ok(_), obligations) => assert!(obligations.is_empty()), + (Err(ref e), _) => { panic!("unexpected error computing sub({:?},{:?}): {}", t1, t2, e); } } @@ -380,9 +390,9 @@ 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().relate(&t1, &t2) { - Err(_) => {} - Ok(_) => { + match self.with_sub(|mut sub| sub.relate(&t1, &t2)) { + (Err(_), obligations) => assert!(obligations.is_empty()), + (Ok(_), _) => { panic!("unexpected success computing sub({:?},{:?})", t1, t2); } } @@ -390,11 +400,12 @@ 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().relate(&t1, &t2) { - Ok(t) => { + match self.with_lub(|mut lub| lub.relate(&t1, &t2)) { + (Ok(t), obligations) => { self.assert_eq(t, t_lub); + assert!(obligations.is_empty()); } - Err(ref e) => { + (Err(ref e), _) => { panic!("unexpected error in LUB: {}", e) } } @@ -403,16 +414,18 @@ impl<'a, 'tcx> Env<'a, 'tcx> { /// Checks that `GLB(t1,t2) == t_glb` pub fn check_glb(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_glb: Ty<'tcx>) { debug!("check_glb(t1={}, t2={}, t_glb={})", t1, t2, t_glb); - match self.glb().relate(&t1, &t2) { - Err(e) => { + match self.with_glb(|mut glb| glb.relate(&t1, &t2)) { + (Err(e), _) => { panic!("unexpected error computing LUB: {:?}", e) } - Ok(t) => { + (Ok(t), obligations) => { self.assert_eq(t, t_glb); // sanity check for good measure: self.assert_subtype(t, t1); self.assert_subtype(t, t2); + + assert!(obligations.is_empty()); } } } diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 0e97e3629064b..1e4b68720e00e 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -332,18 +332,28 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - fn mk_subty(&self, span: Span, sup: Ty<'tcx>, sub: Ty<'tcx>) + fn mk_subty(&mut self, span: Span, sup: Ty<'tcx>, sub: Ty<'tcx>) -> infer::UnitResult<'tcx> { - infer::mk_subty(self.infcx, false, infer::TypeOrigin::Misc(span), - sup, sub) + infer::mk_subty(self.infcx, false, infer::TypeOrigin::Misc(span), sup, sub) + .map(|infer::InferOk { obligations, .. }| { + for obligation in obligations { + self.fulfillment_cx.register_predicate_obligation(self.infcx, obligation); + } + () + }) } - fn mk_eqty(&self, span: Span, a: Ty<'tcx>, b: Ty<'tcx>) + fn mk_eqty(&mut self, span: Span, a: Ty<'tcx>, b: Ty<'tcx>) -> infer::UnitResult<'tcx> { - infer::mk_eqty(self.infcx, false, infer::TypeOrigin::Misc(span), - a, b) + infer::mk_eqty(self.infcx, false, infer::TypeOrigin::Misc(span), a, b) + .map(|infer::InferOk { obligations, .. }| { + for obligation in obligations { + self.fulfillment_cx.register_predicate_obligation(self.infcx, obligation); + } + () + }) } fn tcx(&self) -> &'a ty::ctxt<'tcx> { @@ -358,7 +368,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let lv_ty = mir.lvalue_ty(tcx, lv).to_ty(tcx); let rv_ty = mir.rvalue_ty(tcx, rv); if let Some(rv_ty) = rv_ty { - if let Err(terr) = self.mk_subty(self.last_span, rv_ty, lv_ty) { + let last_span = self.last_span; + if let Err(terr) = self.mk_subty(last_span, rv_ty, lv_ty) { span_mirbug!(self, stmt, "bad assignment ({:?} = {:?}): {:?}", lv_ty, rv_ty, terr); } @@ -370,7 +381,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - fn check_terminator(&self, + fn check_terminator(&mut self, mir: &Mir<'tcx>, term: &Terminator<'tcx>) { debug!("check_terminator: {:?}", term); @@ -394,7 +405,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } Terminator::SwitchInt { ref discr, switch_ty, .. } => { let discr_ty = mir.lvalue_ty(tcx, discr).to_ty(tcx); - if let Err(terr) = self.mk_subty(self.last_span, discr_ty, switch_ty) { + let last_span = self.last_span; + if let Err(terr) = self.mk_subty(last_span, discr_ty, switch_ty) { span_mirbug!(self, term, "bad SwitchInt ({:?} on {:?}): {:?}", switch_ty, discr_ty, terr); } @@ -439,7 +451,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - fn check_call_dest(&self, + fn check_call_dest(&mut self, mir: &Mir<'tcx>, term: &Terminator<'tcx>, sig: &ty::FnSig<'tcx>, @@ -451,7 +463,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } (&Some((ref dest, _)), ty::FnConverging(ty)) => { let dest_ty = mir.lvalue_ty(tcx, dest).to_ty(tcx); - if let Err(terr) = self.mk_subty(self.last_span, ty, dest_ty) { + let last_span = self.last_span; + if let Err(terr) = self.mk_subty(last_span, ty, dest_ty) { span_mirbug!(self, term, "call dest mismatch ({:?} <- {:?}): {:?}", dest_ty, ty, terr); @@ -464,7 +477,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - fn check_call_inputs(&self, + fn check_call_inputs(&mut self, mir: &Mir<'tcx>, term: &Terminator<'tcx>, sig: &ty::FnSig<'tcx>, @@ -477,7 +490,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } for (n, (fn_arg, op_arg)) in sig.inputs.iter().zip(args).enumerate() { let op_arg_ty = mir.operand_ty(self.tcx(), op_arg); - if let Err(terr) = self.mk_subty(self.last_span, op_arg_ty, fn_arg) { + let last_span = self.last_span; + if let Err(terr) = self.mk_subty(last_span, op_arg_ty, fn_arg) { span_mirbug!(self, term, "bad arg #{:?} ({:?} <- {:?}): {:?}", n, fn_arg, op_arg_ty, terr); } @@ -495,7 +509,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - fn check_box_free_inputs(&self, + fn check_box_free_inputs(&mut self, mir: &Mir<'tcx>, term: &Terminator<'tcx>, sig: &ty::FnSig<'tcx>, @@ -532,7 +546,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } }; - if let Err(terr) = self.mk_subty(self.last_span, arg_ty, pointee_ty) { + let last_span = self.last_span; + if let Err(terr) = self.mk_subty(last_span, arg_ty, pointee_ty) { span_mirbug!(self, term, "bad box_free arg ({:?} <- {:?}): {:?}", pointee_ty, arg_ty, terr); } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index bd2c7b3915363..355c2830fe158 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -533,13 +533,7 @@ pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, ), }; - infer::common_supertype( - fcx.infcx(), - origin, - true, - expected, - found, - ) + fcx.common_supertype(origin, true, expected, found) } }); diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index f07464592faac..6f72629ed9722 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -62,7 +62,7 @@ use check::{autoderef, FnCtxt, UnresolvedTypeAction}; -use middle::infer::{self, Coercion, TypeOrigin}; +use middle::infer::{self, Coercion, TypeOrigin, InferOk}; use middle::traits::{self, ObligationCause}; use middle::traits::{predicate_for_trait_def, report_selection_error}; use middle::ty::adjustment::{AutoAdjustment, AutoDerefRef, AdjustDerefRef}; @@ -71,7 +71,6 @@ use middle::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer}; use middle::ty::{self, LvaluePreference, TypeAndMut, Ty}; use middle::ty::fold::TypeFoldable; use middle::ty::error::TypeError; -use middle::ty::relate::RelateResult; use util::common::indent; use std::cell::RefCell; @@ -84,7 +83,7 @@ struct Coerce<'a, 'tcx: 'a> { unsizing_obligations: RefCell>>, } -type CoerceResult<'tcx> = RelateResult<'tcx, Option>>; +type CoerceResult<'tcx> = Result>, TypeError<'tcx>>; impl<'f, 'tcx> Coerce<'f, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { @@ -92,8 +91,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } fn subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { - try!(self.fcx.infcx().sub_types(false, self.origin.clone(), a, b)); - Ok(None) // No coercion required. + self.fcx.infcx().sub_types(false, self.origin.clone(), a, b) + .map(|InferOk { obligations, .. }| { + for obligation in obligations { + self.fcx.register_predicate(obligation); + } + None + }) } fn unpack_actual_value(&self, a: Ty<'tcx>, f: F) -> T where @@ -206,13 +210,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } let ty = self.tcx().mk_ref(r_borrow, TypeAndMut {ty: inner_ty, mutbl: mutbl_b}); - if let Err(err) = self.subtype(ty, b) { - if first_error.is_none() { - first_error = Some(err); + match self.subtype(ty, b) { + Err(err) => { + if first_error.is_none() { + first_error = Some(err); + } + None + }, + Ok(_) => { + Some(()) } - None - } else { - Some(()) } }); @@ -439,7 +446,7 @@ pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, expr: &hir::Expr, a: Ty<'tcx>, b: Ty<'tcx>) - -> RelateResult<'tcx, ()> { + -> Result<(), TypeError<'tcx>> { debug!("mk_assignty({:?} -> {:?})", a, b); let mut unsizing_obligations = vec![]; let adjustment = try!(indent(|| { diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index d674fa145dc9a..9279861d76145 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -9,7 +9,7 @@ // except according to those terms. use middle::free_region::FreeRegionMap; -use middle::infer::{self, TypeOrigin}; +use middle::infer::{self, TypeOrigin, InferOk}; use middle::traits; use middle::ty::{self}; use middle::subst::{self, Subst, Substs, VecPerParamSpace}; @@ -323,8 +323,12 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, debug!("compare_impl_method: trait_fty={:?}", trait_fty); - try!(infer::mk_subty(&infcx, false, origin, impl_fty, trait_fty)); + let InferOk { obligations, .. } = + try!(infer::mk_subty(&infcx, false, origin, impl_fty, trait_fty)); + for obligation in obligations { + fulfillment_cx.register_predicate_obligation(&infcx, obligation); + } infcx.leak_check(&skol_map, snapshot) }); @@ -475,7 +479,10 @@ pub fn compare_const_impl<'tcx>(tcx: &ty::ctxt<'tcx>, }); match err { - Ok(()) => { } + Ok(InferOk { obligations, .. }) => + for obligation in obligations { + fulfillment_cx.register_predicate_obligation(&infcx, obligation); + }, Err(terr) => { debug!("checking associated const for compatibility: impl ty {:?}, trait ty {:?}", impl_ty, diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 63dac49b384a7..922801f32466a 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -11,7 +11,7 @@ use check::{coercion, FnCtxt}; use middle::ty::{self, Ty}; -use middle::infer::{self, TypeOrigin}; +use middle::infer::{TypeOrigin}; use std::result::Result::{Err, Ok}; use syntax::codemap::Span; @@ -35,8 +35,8 @@ pub fn suptype_with_fn<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, F: FnOnce(Span, Ty<'tcx>, Ty<'tcx>, &ty::error::TypeError<'tcx>), { // n.b.: order of actual, expected is reversed - match infer::mk_subty(fcx.infcx(), b_is_expected, TypeOrigin::Misc(sp), - ty_b, ty_a) { + match fcx.mk_subty(b_is_expected, TypeOrigin::Misc(sp), + ty_b, ty_a) { Ok(()) => { /* ok */ } Err(ref err) => { handle_err(sp, ty_a, ty_b, err); @@ -46,7 +46,7 @@ pub fn suptype_with_fn<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, pub fn eqtype<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { - match infer::mk_eqty(fcx.infcx(), false, TypeOrigin::Misc(sp), actual, expected) { + match fcx.mk_eqty(false, TypeOrigin::Misc(sp), actual, expected) { Ok(()) => { /* ok */ } Err(ref err) => { fcx.report_mismatched_types(sp, expected, actual, err); } } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 3cf182a0d8ff6..1b0812c885282 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -20,8 +20,8 @@ use middle::subst; use middle::subst::Subst; use middle::traits; use middle::ty::{self, NoPreference, Ty, ToPolyTraitRef, TraitRef, TypeFoldable}; -use middle::infer; -use middle::infer::{InferCtxt, TypeOrigin}; +use middle::ty::error::{TypeError}; +use middle::infer::{InferCtxt, TypeOrigin, InferOk}; use syntax::ast; use syntax::codemap::{Span, DUMMY_SP}; use rustc_front::hir; @@ -1133,8 +1133,14 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { /////////////////////////////////////////////////////////////////////////// // MISCELLANY - fn make_sub_ty(&self, sub: Ty<'tcx>, sup: Ty<'tcx>) -> infer::UnitResult<'tcx> { + fn make_sub_ty(&self, sub: Ty<'tcx>, sup: Ty<'tcx>) -> Result<(), TypeError<'tcx>> { self.infcx().sub_types(false, TypeOrigin::Misc(DUMMY_SP), sub, sup) + .map(|InferOk { value, obligations }| { + for obligation in obligations { + self.fcx.register_predicate(obligation); + } + value + }) } fn has_applicable_self(&self, item: &ty::ImplOrTraitItem) -> bool { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7ab4975c8b8ae..af01d6b9da7eb 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -88,8 +88,7 @@ use middle::astconv_util::prohibit_type_params; use middle::cstore::LOCAL_CRATE; use middle::def::{self, Def}; use middle::def_id::DefId; -use middle::infer; -use middle::infer::{TypeOrigin, type_variable}; +use middle::infer::{self, TypeOrigin, type_variable, InferOk}; use middle::pat_util::{self, pat_id_map}; use middle::privacy::{AllPublic, LastMod}; use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace}; @@ -1206,6 +1205,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self.inh.infcx } + pub fn fulfillment_cx(&self) -> &RefCell> { + &self.inh.fulfillment_cx + } + pub fn param_env(&self) -> &ty::ParameterEnvironment<'a,'tcx> { &self.inh.infcx.parameter_environment } @@ -1248,6 +1251,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } + pub fn common_supertype(&self, + origin: TypeOrigin, + a_is_expected: bool, + a: Ty<'tcx>, + b: Ty<'tcx>) + -> Ty<'tcx> + { + let InferOk { value, obligations } = infer::common_supertype( + self.infcx(), origin, a_is_expected, a, b); + for obligation in obligations { + self.register_predicate(obligation); + } + value + } + fn record_deferred_call_resolution(&self, closure_def_id: DefId, r: DeferredCallResolutionHandler<'tcx>) { @@ -1593,6 +1611,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sup: Ty<'tcx>) -> Result<(), TypeError<'tcx>> { infer::mk_subty(self.infcx(), a_is_expected, origin, sub, sup) + .map(|InferOk { value, obligations }| { + for obligation in obligations { + self.register_predicate(obligation); + } + value + }) } pub fn mk_eqty(&self, @@ -1602,6 +1626,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sup: Ty<'tcx>) -> Result<(), TypeError<'tcx>> { infer::mk_eqty(self.infcx(), a_is_expected, origin, sub, sup) + .map(|InferOk { value, obligations }| { + for obligation in obligations { + self.register_predicate(obligation); + } + value + }) } pub fn mk_subr(&self, @@ -1885,9 +1915,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Neither => { if let Some(default) = default_map.get(ty) { let default = default.clone(); - match infer::mk_eqty(self.infcx(), false, - TypeOrigin::Misc(default.origin_span), - ty, default.ty) { + match self.mk_eqty(false, + TypeOrigin::Misc(default.origin_span), + ty, default.ty) { Ok(()) => {} Err(_) => { conflicts.push((*ty, default)); @@ -1978,9 +2008,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Neither => { if let Some(default) = default_map.get(ty) { let default = default.clone(); - match infer::mk_eqty(self.infcx(), false, - TypeOrigin::Misc(default.origin_span), - ty, default.ty) { + match self.mk_eqty(false, + TypeOrigin::Misc(default.origin_span), + ty, default.ty) { Ok(()) => {} Err(_) => { result = Some(default); @@ -2880,18 +2910,16 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, Some(ref else_expr) => { check_expr_with_expectation(fcx, &else_expr, expected); let else_ty = fcx.expr_ty(&else_expr); - infer::common_supertype(fcx.infcx(), - TypeOrigin::IfExpression(sp), - true, - then_ty, - else_ty) + fcx.common_supertype(TypeOrigin::IfExpression(sp), + true, + then_ty, + else_ty) } None => { - infer::common_supertype(fcx.infcx(), - TypeOrigin::IfExpressionWithNoElse(sp), - false, - then_ty, - fcx.tcx().mk_nil()) + fcx.common_supertype(TypeOrigin::IfExpressionWithNoElse(sp), + false, + then_ty, + fcx.tcx().mk_nil()) } }; @@ -3696,11 +3724,10 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, Some(fcx.tcx().types.err) } (Some(t_start), Some(t_end)) => { - Some(infer::common_supertype(fcx.infcx(), - TypeOrigin::RangeExpression(expr.span), - true, - t_start, - t_end)) + Some(fcx.common_supertype(TypeOrigin::RangeExpression(expr.span), + true, + t_start, + t_end)) } _ => None }; diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index e399818779ecf..5ce1132ade06f 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -92,7 +92,8 @@ use middle::region::{self, CodeExtent}; use middle::subst::Substs; use middle::traits; use middle::ty::{self, Ty, MethodCall, TypeFoldable}; -use middle::infer::{self, GenericKind, InferCtxt, SubregionOrigin, TypeOrigin, VerifyBound}; +use middle::infer::{self, GenericKind, InferCtxt, SubregionOrigin, TypeOrigin, VerifyBound, + InferOk}; use middle::pat_util; use middle::ty::adjustment; use middle::ty::wf::ImpliedBound; @@ -1846,7 +1847,12 @@ fn declared_projection_bounds_from_trait<'a,'tcx>(rcx: &Rcx<'a, 'tcx>, // check whether this predicate applies to our current projection match infer::mk_eqty(infcx, false, TypeOrigin::Misc(span), ty, outlives.0) { - Ok(()) => { Ok(outlives.1) } + Ok(InferOk { obligations, .. }) => { + for obligation in obligations { + fcx.register_predicate(obligation); + } + Ok(outlives.1) + } Err(_) => { Err(()) } } });