diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index d24eddf9ab0..e2a57629d7e 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -366,6 +366,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { infer::MatchExpressionArm(_, _) => "match arms have incompatible types", infer::IfExpression(_) => "if and else have incompatible types", infer::IfExpressionWithNoElse(_) => "if may be missing an else clause", + infer::EquatePredicate(_) => "equality predicate not satisfied", }; self.tcx.sess.span_err( @@ -1523,6 +1524,9 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { infer::IfExpressionWithNoElse(_) => { format!("if may be missing an else clause") } + infer::EquatePredicate(_) => { + format!("equality where clause is satisfied") + } }; match self.values_str(&trace.values) { diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 81cd8dd20d2..3b62b96a3e9 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -129,7 +129,10 @@ pub enum TypeOrigin { IfExpression(Span), // Computing common supertype of an if expression with no else counter-part - IfExpressionWithNoElse(Span) + IfExpressionWithNoElse(Span), + + // `where a == b` + EquatePredicate(Span), } impl Copy for TypeOrigin {} @@ -1017,7 +1020,8 @@ impl TypeOrigin { RelateOutputImplTypes(span) => span, MatchExpressionArm(match_span, _) => match_span, IfExpression(span) => span, - IfExpressionWithNoElse(span) => span + IfExpressionWithNoElse(span) => span, + EquatePredicate(span) => span, } } } @@ -1050,6 +1054,9 @@ impl<'tcx> Repr<'tcx> for TypeOrigin { IfExpressionWithNoElse(a) => { format!("IfExpressionWithNoElse({})", a.repr(tcx)) } + EquatePredicate(a) => { + format!("EquatePredicate({})", a.repr(tcx)) + } } } } diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index d0e401d3551..28f92089ce9 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -10,7 +10,7 @@ use middle::mem_categorization::Typer; use middle::ty::{mod, Ty}; -use middle::infer::{mod, InferCtxt}; +use middle::infer::{mod, InferCtxt, ures}; use std::collections::HashSet; use std::collections::hash_map::{Occupied, Vacant}; use std::default::Default; @@ -20,6 +20,8 @@ use util::ppaux::Repr; use util::nodemap::NodeMap; use super::CodeAmbiguity; +use super::Obligation; +use super::ObligationCause; use super::TraitObligation; use super::FulfillmentError; use super::CodeSelectionError; @@ -82,7 +84,7 @@ pub struct FulfillmentContext<'tcx> { pub struct RegionObligation<'tcx> { pub sub_region: ty::Region, pub sup_type: Ty<'tcx>, - pub origin: infer::SubregionOrigin<'tcx>, + pub cause: ObligationCause<'tcx>, } impl<'tcx> FulfillmentContext<'tcx> { @@ -95,6 +97,32 @@ impl<'tcx> FulfillmentContext<'tcx> { } } + pub fn register_predicate<'a>(&mut self, + infcx: &InferCtxt<'a,'tcx>, + predicate: &Obligation<'tcx, ty::Predicate<'tcx>>) + -> ures<'tcx> + { + match predicate.trait_ref { + ty::Predicate::Trait(ref trait_ref) => { + let trait_obligation = Obligation { cause: predicate.cause, + recursion_depth: predicate.recursion_depth, + trait_ref: (*trait_ref).clone() }; + Ok(self.register_obligation(infcx.tcx, trait_obligation)) + } + ty::Predicate::Equate(a, b) => { + let origin = infer::EquatePredicate(predicate.cause.span); + infer::mk_eqty(infcx, false, origin, a, b) // `a == b` ==> `` + } + ty::Predicate::RegionOutlives(r_a, r_b) => { + let origin = infer::RelateRegionParamBound(predicate.cause.span); + Ok(infer::mk_subr(infcx, origin, r_b, r_a)) // `b : a` ==> `a <= b` + } + ty::Predicate::TypeOutlives(t_a, r_b) => { + Ok(self.register_region_obligation(t_a, r_b, predicate.cause)) + } + } + } + pub fn register_obligation(&mut self, tcx: &ty::ctxt<'tcx>, obligation: TraitObligation<'tcx>) @@ -109,10 +137,14 @@ impl<'tcx> FulfillmentContext<'tcx> { } pub fn register_region_obligation(&mut self, - body_id: ast::NodeId, - region_obligation: RegionObligation<'tcx>) + sup_type: Ty<'tcx>, + sub_region: ty::Region, + cause: ObligationCause<'tcx>) { - match self.region_obligations.entry(body_id) { + let region_obligation = RegionObligation { sup_type: sup_type, + sub_region: sub_region, + cause: cause }; + match self.region_obligations.entry(cause.body_id) { Vacant(entry) => { entry.set(vec![region_obligation]); }, Occupied(mut entry) => { entry.get_mut().push(region_obligation); }, } @@ -268,9 +300,8 @@ impl<'tcx> FulfillmentContext<'tcx> { impl<'tcx> Repr<'tcx> for RegionObligation<'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { - format!("RegionObligation(sub_region={}, sup_type={}, origin={})", + format!("RegionObligation(sub_region={}, sup_type={})", self.sub_region.repr(tcx), - self.sup_type.repr(tcx), - self.origin.repr(tcx)) + self.sup_type.repr(tcx)) } } diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index aab1fbcdbfd..37da82891de 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -31,9 +31,10 @@ pub use self::select::SelectionCache; pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch}; pub use self::select::{MethodMatchedData}; // intentionally don't export variants pub use self::util::supertraits; -pub use self::util::transitive_bounds; pub use self::util::Supertraits; pub use self::util::search_trait_and_supertraits_from_bound; +pub use self::util::transitive_bounds; +pub use self::util::trait_ref_for_builtin_bound; mod coherence; mod fulfill; @@ -61,7 +62,7 @@ pub struct ObligationCause<'tcx> { pub span: Span, // the id of XXX - pub scope_id: ast::NodeId, + pub body_id: ast::NodeId, pub code: ObligationCauseCode<'tcx> } @@ -307,8 +308,8 @@ impl<'tcx,O> Obligation<'tcx,O> { trait_ref: trait_ref } } - pub fn misc(span: Span, scope_id: ast::NodeId, trait_ref: O) -> Obligation<'tcx, O> { - Obligation::new(ObligationCause::misc(span, scope_id), trait_ref) + pub fn misc(span: Span, body_id: ast::NodeId, trait_ref: O) -> Obligation<'tcx, O> { + Obligation::new(ObligationCause::misc(span, body_id), trait_ref) } } @@ -320,18 +321,18 @@ impl<'tcx> Obligation<'tcx,Rc>> { impl<'tcx> ObligationCause<'tcx> { pub fn new(span: Span, - scope_id: ast::NodeId, + body_id: ast::NodeId, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> { - ObligationCause { span: span, scope_id: scope_id, code: code } + ObligationCause { span: span, body_id: body_id, code: code } } - pub fn misc(span: Span, scope_id: ast::NodeId) -> ObligationCause<'tcx> { - ObligationCause { span: span, scope_id: scope_id, code: MiscObligation } + pub fn misc(span: Span, body_id: ast::NodeId) -> ObligationCause<'tcx> { + ObligationCause { span: span, body_id: body_id, code: MiscObligation } } pub fn dummy() -> ObligationCause<'tcx> { - ObligationCause { span: DUMMY_SP, scope_id: 0, code: MiscObligation } + ObligationCause { span: DUMMY_SP, body_id: 0, code: MiscObligation } } } diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 9ffa5b76a99..360298feab7 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -81,7 +81,10 @@ impl<'cx, 'tcx> Supertraits<'cx, 'tcx> { let bound_trait_ref = trait_ref_for_builtin_bound(self.tcx, builtin_bound, trait_ref.self_ty()); - bound_trait_ref.map(|trait_ref| trait_bounds.push(trait_ref)); + match bound_trait_ref { + Ok(trait_ref) => { trait_bounds.push(trait_ref); } + Err(ErrorReported) => { } + } } // Only keep those bounds that we haven't already seen. This @@ -240,18 +243,18 @@ pub fn trait_ref_for_builtin_bound<'tcx>( tcx: &ty::ctxt<'tcx>, builtin_bound: ty::BuiltinBound, param_ty: Ty<'tcx>) - -> Option>> + -> Result>, ErrorReported> { match tcx.lang_items.from_builtin_kind(builtin_bound) { Ok(def_id) => { - Some(Rc::new(ty::TraitRef { + Ok(Rc::new(ty::TraitRef { def_id: def_id, substs: Substs::empty().with_self_ty(param_ty) })) } Err(e) => { tcx.sess.err(e.as_slice()); - None + Err(ErrorReported) } } } @@ -264,15 +267,12 @@ pub fn obligation_for_builtin_bound<'tcx>( param_ty: Ty<'tcx>) -> Result, ErrorReported> { - let trait_ref = trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty); - match trait_ref { - Some(trait_ref) => Ok(Obligation { - cause: cause, - recursion_depth: recursion_depth, - trait_ref: trait_ref - }), - None => Err(ErrorReported) - } + let trait_ref = try!(trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty)); + Ok(Obligation { + cause: cause, + recursion_depth: recursion_depth, + trait_ref: trait_ref + }) } /// Starting from a caller obligation `caller_bound` (which has coordinates `space`/`i` in the list diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c7be362f187..cd5cade78db 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1729,8 +1729,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the type is `Foo+'a`, ensures that the type // being cast to `Foo+'a` outlives `'a`: - let origin = infer::RelateObjectBound(span); - self.register_region_obligation(origin, self_ty, ty_trait.bounds.region_bound); + let cause = traits::ObligationCause { span: span, + body_id: self.body_id, + code: traits::ObjectCastObligation(self_ty) }; + self.register_region_obligation(self_ty, ty_trait.bounds.region_bound, cause); } } } @@ -1951,15 +1953,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Registers an obligation for checking later, during regionck, that the type `ty` must /// outlive the region `r`. pub fn register_region_obligation(&self, - origin: infer::SubregionOrigin<'tcx>, ty: Ty<'tcx>, - r: ty::Region) + region: ty::Region, + cause: traits::ObligationCause<'tcx>) { let mut fulfillment_cx = self.inh.fulfillment_cx.borrow_mut(); - let region_obligation = traits::RegionObligation { sub_region: r, - sup_type: ty, - origin: origin }; - fulfillment_cx.register_region_obligation(self.body_id, region_obligation); + fulfillment_cx.register_region_obligation(ty, region, cause); } pub fn add_default_region_param_bounds(&self, @@ -1968,8 +1967,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { for &ty in substs.types.iter() { let default_bound = ty::ReScope(CodeExtent::from_node_id(expr.id)); - let origin = infer::RelateDefaultParamBound(expr.span, ty); - self.register_region_obligation(origin, ty, default_bound); + let cause = traits::ObligationCause::new(expr.span, self.body_id, + traits::MiscObligation); + self.register_region_obligation(ty, default_bound, cause); } } @@ -2061,8 +2061,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { param_bound.builtin_bounds, param_bound.trait_bounds.as_slice()); for &r in region_bounds.iter() { - let origin = infer::RelateParamBound(span, ty); - self.register_region_obligation(origin, ty, r); + let cause = traits::ObligationCause::new(span, self.body_id, traits::MiscObligation); + self.register_region_obligation(ty, r, cause); } } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 1564287f15f..328c1eafae5 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -358,8 +358,8 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { debug!("visit_region_obligations: r_o={}", r_o.repr(self.tcx())); let sup_type = self.resolve_type(r_o.sup_type); - type_must_outlive(self, r_o.origin.clone(), - sup_type, r_o.sub_region); + let origin = infer::RelateRegionParamBound(r_o.cause.span); + type_must_outlive(self, origin, sup_type, r_o.sub_region); } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 6b7f08e8104..9cfb56fbf8c 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -42,6 +42,7 @@ use middle::region; use middle::resolve_lifetime; use middle::subst; use middle::subst::{Substs}; +use middle::traits; use middle::ty::{ImplContainer, ImplOrTraitItemContainer, TraitContainer}; use middle::ty::{Polytype}; use middle::ty::{mod, Ty}; @@ -49,6 +50,7 @@ use middle::ty_fold::TypeFolder; use middle::infer; use rscope::*; use {CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx}; +use util::common::ErrorReported; use util::nodemap::{FnvHashMap, FnvHashSet}; use util::ppaux; use util::ppaux::{Repr,UserString}; @@ -1806,6 +1808,10 @@ fn ty_generics<'tcx,AC>(this: &AC, result.types.push(space, (*associated_type_param).clone()); } + // Just for fun, also push the bounds from the type parameters + // into the predicates list. This is currently kind of non-DRY. + create_predicates(this.tcx(), &mut result, space); + return result; fn create_type_parameters_for_associated_types<'tcx, AC>( @@ -1892,6 +1898,33 @@ fn ty_generics<'tcx,AC>(this: &AC, } } } + + fn create_predicates<'tcx>( + tcx: &ty::ctxt<'tcx>, + result: &mut ty::Generics<'tcx>, + space: subst::ParamSpace) + { + for (index, type_param_def) in result.types.get_slice(space).iter().enumerate() { + let param_ty = ty::mk_param(tcx, space, index, type_param_def.def_id); + + for builtin_bound in type_param_def.bounds.builtin_bounds.iter() { + match traits::trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty) { + Ok(trait_ref) => { + result.predicates.push(space, ty::Predicate::Trait(trait_ref)); + } + Err(ErrorReported) => { } + } + } + + for ®ion_bound in type_param_def.bounds.region_bounds.iter() { + result.predicates.push(space, ty::Predicate::TypeOutlives(param_ty, region_bound)); + } + + for bound_trait_ref in type_param_def.bounds.trait_bounds.iter() { + result.predicates.push(space, ty::Predicate::Trait((*bound_trait_ref).clone())); + } + } + } } fn get_or_create_type_parameter_def<'tcx,AC>(this: &AC,