about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2014-12-06 01:30:41 -0500
committerNiko Matsakis <niko@alum.mit.edu>2014-12-12 20:24:34 -0500
commit2be6c4f1ca6726068ceb70e7fb5369f2c1a42bb0 (patch)
treea7e0eb2c4abc6dcd09a584d988bf1e8a7ca29afb
parent9409bd9ff87941fcdddb5af7cb3b22c0e7a29c30 (diff)
downloadrust-2be6c4f1ca6726068ceb70e7fb5369f2c1a42bb0.tar.gz
rust-2be6c4f1ca6726068ceb70e7fb5369f2c1a42bb0.zip
Write code for registering region obligations (but don't use it yet).
-rw-r--r--src/librustc/middle/infer/error_reporting.rs4
-rw-r--r--src/librustc/middle/infer/mod.rs11
-rw-r--r--src/librustc/middle/traits/fulfill.rs47
-rw-r--r--src/librustc/middle/traits/mod.rs19
-rw-r--r--src/librustc/middle/traits/util.rs26
-rw-r--r--src/librustc_typeck/check/mod.rs24
-rw-r--r--src/librustc_typeck/check/regionck.rs4
-rw-r--r--src/librustc_typeck/collect.rs33
8 files changed, 122 insertions, 46 deletions
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<ty::TraitRef<'tcx>>> {
 
 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<Rc<ty::TraitRef<'tcx>>>
+    -> Result<Rc<ty::TraitRef<'tcx>>, 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<TraitObligation<'tcx>, 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 &region_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,