From 4efaddf7c96743c087861ba15bd9b48a2200ddfd Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 5 Dec 2014 00:03:03 -0500 Subject: [PATCH 01/10] Start restructuring to support generalized where clauses etc. --- src/librustc/metadata/csearch.rs | 6 +- src/librustc/middle/astencode.rs | 2 +- src/librustc/middle/traits/fulfill.rs | 8 +- src/librustc/middle/traits/mod.rs | 41 ++++++----- src/librustc/middle/traits/select.rs | 102 +++++++++++++------------- src/librustc/middle/traits/util.rs | 10 +-- src/librustc/middle/ty.rs | 8 +- src/librustc/middle/ty_fold.rs | 28 +++---- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/check/vtable.rs | 12 +-- src/librustc_typeck/lib.rs | 6 +- 11 files changed, 112 insertions(+), 113 deletions(-) diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index b864dc396036..7ce9893afc8b 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -21,7 +21,6 @@ use middle::def; use middle::lang_items; use middle::resolve; use middle::ty; -use middle::subst::VecPerParamSpace; use rbml; use rbml::reader; @@ -250,9 +249,8 @@ pub fn get_field_type<'tcx>(tcx: &ty::ctxt<'tcx>, class_id: ast::DefId, }); let ty = decoder::item_type(def, the_field, tcx, &*cdata); ty::Polytype { - generics: ty::Generics {types: VecPerParamSpace::empty(), - regions: VecPerParamSpace::empty()}, - ty: ty + generics: ty::Generics::empty(), + ty: ty, } } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 113d127503f0..8c2fbc078e2e 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -1553,7 +1553,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { this.read_struct_field("regions", 1, |this| { Ok(this.read_vec_per_param_space( |this| Decodable::decode(this).unwrap())) - }).unwrap() + }).unwrap(), }) }) }).unwrap(), diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 653c686ab197..f6428efc4e4e 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -16,7 +16,7 @@ use std::rc::Rc; use util::ppaux::Repr; use super::CodeAmbiguity; -use super::Obligation; +use super::TraitObligation; use super::FulfillmentError; use super::CodeSelectionError; use super::select::SelectionContext; @@ -41,7 +41,7 @@ pub struct FulfillmentContext<'tcx> { // A list of all obligations that have been registered with this // fulfillment context. - trait_obligations: Vec>, + trait_obligations: Vec>, // Remembers the count of trait obligations that we have already // attempted to select. This is used to avoid repeating work @@ -60,7 +60,7 @@ impl<'tcx> FulfillmentContext<'tcx> { pub fn register_obligation(&mut self, tcx: &ty::ctxt<'tcx>, - obligation: Obligation<'tcx>) + obligation: TraitObligation<'tcx>) { if self.duplicate_set.insert(obligation.trait_ref.clone()) { debug!("register_obligation({})", obligation.repr(tcx)); @@ -117,7 +117,7 @@ impl<'tcx> FulfillmentContext<'tcx> { self.select(&mut selcx, false) } - pub fn pending_trait_obligations(&self) -> &[Obligation<'tcx>] { + pub fn pending_trait_obligations(&self) -> &[TraitObligation<'tcx>] { self.trait_obligations[] } diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index d410a456dc91..1505fe7561b6 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -47,22 +47,22 @@ mod util; /// provides the required vtable, or else finding a bound that is in /// scope. The eventual result is usually a `Selection` (defined below). #[deriving(Clone)] -pub struct Obligation<'tcx> { +pub struct Obligation<'tcx, T> { pub cause: ObligationCause<'tcx>, pub recursion_depth: uint, - pub trait_ref: Rc>, + pub trait_ref: T, } +pub type TraitObligation<'tcx> = Obligation<'tcx, Rc>>; + /// Why did we incur this obligation? Used for error reporting. -#[deriving(Clone)] +#[deriving(Copy, Clone)] pub struct ObligationCause<'tcx> { pub span: Span, pub code: ObligationCauseCode<'tcx> } -impl<'tcx> Copy for ObligationCause<'tcx> {} - -#[deriving(Clone)] +#[deriving(Copy, Clone)] pub enum ObligationCauseCode<'tcx> { /// Not well classified or should be obvious from span. MiscObligation, @@ -95,11 +95,11 @@ pub enum ObligationCauseCode<'tcx> { ObjectSized, } -pub type Obligations<'tcx> = subst::VecPerParamSpace>; +pub type Obligations<'tcx, O> = subst::VecPerParamSpace>; -impl<'tcx> Copy for ObligationCauseCode<'tcx> {} +pub type TraitObligations<'tcx> = subst::VecPerParamSpace>; -pub type Selection<'tcx> = Vtable<'tcx, Obligation<'tcx>>; +pub type Selection<'tcx> = Vtable<'tcx, TraitObligation<'tcx>>; #[deriving(Clone,Show)] pub enum SelectionError<'tcx> { @@ -109,7 +109,7 @@ pub enum SelectionError<'tcx> { } pub struct FulfillmentError<'tcx> { - pub obligation: Obligation<'tcx>, + pub obligation: TraitObligation<'tcx>, pub code: FulfillmentErrorCode<'tcx> } @@ -230,7 +230,7 @@ pub fn select_inherent_impl<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, impl_def_id: ast::DefId, self_ty: Ty<'tcx>) -> SelectionResult<'tcx, - VtableImplData<'tcx, Obligation<'tcx>>> + VtableImplData<'tcx, TraitObligation<'tcx>>> { // This routine is only suitable for inherent impls. This is // because it does not attempt to unify the output type parameters @@ -279,7 +279,7 @@ pub fn obligations_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>, cause: ObligationCause<'tcx>, generic_bounds: &ty::GenericBounds<'tcx>, type_substs: &subst::VecPerParamSpace>) - -> subst::VecPerParamSpace> + -> subst::VecPerParamSpace> { util::obligations_for_generics(tcx, cause, 0, generic_bounds, type_substs) } @@ -288,23 +288,27 @@ pub fn obligation_for_builtin_bound<'tcx>(tcx: &ty::ctxt<'tcx>, cause: ObligationCause<'tcx>, source_ty: Ty<'tcx>, builtin_bound: ty::BuiltinBound) - -> Result, ErrorReported> + -> Result, ErrorReported> { util::obligation_for_builtin_bound(tcx, cause, builtin_bound, 0, source_ty) } -impl<'tcx> Obligation<'tcx> { - pub fn new(cause: ObligationCause<'tcx>, trait_ref: Rc>) - -> Obligation<'tcx> { +impl<'tcx,O> Obligation<'tcx,O> { + pub fn new(cause: ObligationCause<'tcx>, + trait_ref: O) + -> Obligation<'tcx, O> + { Obligation { cause: cause, recursion_depth: 0, trait_ref: trait_ref } } - pub fn misc(span: Span, trait_ref: Rc>) -> Obligation<'tcx> { + pub fn misc(span: Span, trait_ref: O) -> Obligation<'tcx, O> { Obligation::new(ObligationCause::misc(span), trait_ref) } +} +impl<'tcx> Obligation<'tcx,Rc>> { pub fn self_ty(&self) -> Ty<'tcx> { self.trait_ref.self_ty() } @@ -406,7 +410,8 @@ impl VtableBuiltinData { } impl<'tcx> FulfillmentError<'tcx> { - fn new(obligation: Obligation<'tcx>, code: FulfillmentErrorCode<'tcx>) + fn new(obligation: TraitObligation<'tcx>, + code: FulfillmentErrorCode<'tcx>) -> FulfillmentError<'tcx> { FulfillmentError { obligation: obligation, code: code } diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 06f8cbf1a6a6..90fc663e8296 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -17,7 +17,7 @@ use self::Candidate::*; use self::BuiltinBoundConditions::*; use self::EvaluationResult::*; -use super::{Obligation, ObligationCause}; +use super::{TraitObligation, ObligationCause}; use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch}; use super::{Selection}; @@ -70,14 +70,14 @@ pub struct SelectionContext<'cx, 'tcx:'cx> { } // A stack that walks back up the stack frame. -struct ObligationStack<'prev, 'tcx: 'prev> { - obligation: &'prev Obligation<'tcx>, +struct TraitObligationStack<'prev, 'tcx: 'prev> { + obligation: &'prev TraitObligation<'tcx>, /// Trait ref from `obligation` but skolemized with the /// selection-context's skolemizer. Used to check for recursion. skol_trait_ref: Rc>, - previous: Option<&'prev ObligationStack<'prev, 'tcx>> + previous: Option<&'prev TraitObligationStack<'prev, 'tcx>> } #[deriving(Clone)] @@ -213,7 +213,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Evaluates whether the obligation can be satisfied. Returns an indication of whether the /// obligation can be satisfied and, if so, by what means. Never affects surrounding typing /// environment. - pub fn select(&mut self, obligation: &Obligation<'tcx>) + pub fn select(&mut self, obligation: &TraitObligation<'tcx>) -> SelectionResult<'tcx, Selection<'tcx>> { debug!("select({})", obligation.repr(self.tcx())); assert!(!obligation.trait_ref.has_escaping_regions()); @@ -229,7 +229,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { impl_def_id: ast::DefId, obligation_cause: ObligationCause<'tcx>, obligation_self_ty: Ty<'tcx>) - -> SelectionResult<'tcx, VtableImplData<'tcx, Obligation<'tcx>>> + -> SelectionResult<'tcx, VtableImplData<'tcx, TraitObligation<'tcx>>> { debug!("select_inherent_impl(impl_def_id={}, obligation_self_ty={})", impl_def_id.repr(self.tcx()), @@ -260,7 +260,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Evaluates whether the obligation `obligation` can be satisfied (by any means). pub fn evaluate_obligation(&mut self, - obligation: &Obligation<'tcx>) + obligation: &TraitObligation<'tcx>) -> bool { debug!("evaluate_obligation({})", @@ -273,7 +273,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn evaluate_builtin_bound_recursively<'o>(&mut self, bound: ty::BuiltinBound, - previous_stack: &ObligationStack<'o, 'tcx>, + previous_stack: &TraitObligationStack<'o, 'tcx>, ty: Ty<'tcx>) -> EvaluationResult<'tcx> { @@ -296,8 +296,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn evaluate_obligation_recursively<'o>(&mut self, - previous_stack: Option<&ObligationStack<'o, 'tcx>>, - obligation: &Obligation<'tcx>) + previous_stack: Option<&TraitObligationStack<'o, 'tcx>>, + obligation: &TraitObligation<'tcx>) -> EvaluationResult<'tcx> { debug!("evaluate_obligation_recursively({})", @@ -312,7 +312,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn evaluate_stack<'o>(&mut self, - stack: &ObligationStack<'o, 'tcx>) + stack: &TraitObligationStack<'o, 'tcx>) -> EvaluationResult<'tcx> { // In intercrate mode, whenever any of the types are unbound, @@ -392,7 +392,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// `obligation_self_ty`. This can be used either for trait or inherent impls. pub fn evaluate_impl(&mut self, impl_def_id: ast::DefId, - obligation: &Obligation<'tcx>) + obligation: &TraitObligation<'tcx>) -> bool { debug!("evaluate_impl(impl_def_id={}, obligation={})", @@ -423,7 +423,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // candidates. See `doc.rs` and the `Candidate` type for more details. fn candidate_from_obligation<'o>(&mut self, - stack: &ObligationStack<'o, 'tcx>) + stack: &TraitObligationStack<'o, 'tcx>) -> SelectionResult<'tcx, Candidate<'tcx>> { // Watch out for overflow. This intentionally bypasses (and does @@ -466,7 +466,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn candidate_from_obligation_no_cache<'o>(&mut self, - stack: &ObligationStack<'o, 'tcx>) + stack: &TraitObligationStack<'o, 'tcx>) -> SelectionResult<'tcx, Candidate<'tcx>> { if ty::type_is_error(stack.obligation.self_ty()) { @@ -626,12 +626,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn assemble_candidates<'o>(&mut self, - stack: &ObligationStack<'o, 'tcx>) + stack: &TraitObligationStack<'o, 'tcx>) -> Result, SelectionError<'tcx>> { // Check for overflow. - let ObligationStack { obligation, .. } = *stack; + let TraitObligationStack { obligation, .. } = *stack; let mut candidates = CandidateSet { vec: Vec::new(), @@ -682,7 +682,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// /// Never affects inference environment. fn assemble_candidates_from_caller_bounds(&mut self, - obligation: &Obligation<'tcx>, + obligation: &TraitObligation<'tcx>, candidates: &mut CandidateSet<'tcx>) -> Result<(),SelectionError<'tcx>> { @@ -720,7 +720,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// parameters and hence do not affect whether this trait is a match or not. They will be /// unified during the confirmation step. fn assemble_unboxed_closure_candidates(&mut self, - obligation: &Obligation<'tcx>, + obligation: &TraitObligation<'tcx>, candidates: &mut CandidateSet<'tcx>) -> Result<(),SelectionError<'tcx>> { @@ -762,7 +762,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Implement one of the `Fn()` family for a fn pointer. fn assemble_fn_pointer_candidates(&mut self, - obligation: &Obligation<'tcx>, + obligation: &TraitObligation<'tcx>, candidates: &mut CandidateSet<'tcx>) -> Result<(),SelectionError<'tcx>> { @@ -800,7 +800,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Search for impls that might apply to `obligation`. fn assemble_candidates_from_impls(&mut self, - obligation: &Obligation<'tcx>, + obligation: &TraitObligation<'tcx>, candidates: &mut CandidateSet<'tcx>) -> Result<(), SelectionError<'tcx>> { @@ -831,7 +831,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// obligations are met. Returns true if `candidate` remains viable after this further /// scrutiny. fn winnow_candidate<'o>(&mut self, - stack: &ObligationStack<'o, 'tcx>, + stack: &TraitObligationStack<'o, 'tcx>, candidate: &Candidate<'tcx>) -> EvaluationResult<'tcx> { @@ -846,7 +846,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn winnow_selection<'o>(&mut self, - stack: Option<&ObligationStack<'o, 'tcx>>, + stack: Option<&TraitObligationStack<'o, 'tcx>>, selection: Selection<'tcx>) -> EvaluationResult<'tcx> { @@ -885,7 +885,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// essentially harmless. See issue #18453 for more details of /// a case where doing the opposite caused us harm. fn candidate_should_be_dropped_in_favor_of<'o>(&mut self, - stack: &ObligationStack<'o, 'tcx>, + stack: &TraitObligationStack<'o, 'tcx>, candidate_i: &Candidate<'tcx>, candidate_j: &Candidate<'tcx>) -> bool @@ -928,7 +928,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn assemble_builtin_bound_candidates<'o>(&mut self, bound: ty::BuiltinBound, - stack: &ObligationStack<'o, 'tcx>, + stack: &TraitObligationStack<'o, 'tcx>, candidates: &mut CandidateSet<'tcx>) -> Result<(),SelectionError<'tcx>> { @@ -1300,7 +1300,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // type error. See `doc.rs` for more details. fn confirm_candidate(&mut self, - obligation: &Obligation<'tcx>, + obligation: &TraitObligation<'tcx>, candidate: Candidate<'tcx>) -> Result,SelectionError<'tcx>> { @@ -1343,7 +1343,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn confirm_param_candidate(&mut self, - obligation: &Obligation<'tcx>, + obligation: &TraitObligation<'tcx>, param: VtableParamData<'tcx>) -> Result, SelectionError<'tcx>> @@ -1359,9 +1359,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn confirm_builtin_candidate(&mut self, - obligation: &Obligation<'tcx>, + obligation: &TraitObligation<'tcx>, bound: ty::BuiltinBound) - -> Result>, + -> Result>, SelectionError<'tcx>> { debug!("confirm_builtin_candidate({})", @@ -1379,10 +1379,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn vtable_builtin_data(&mut self, - obligation: &Obligation<'tcx>, + obligation: &TraitObligation<'tcx>, bound: ty::BuiltinBound, nested: Vec>) - -> VtableBuiltinData> + -> VtableBuiltinData> { let obligations = nested.iter().map(|&t| { util::obligation_for_builtin_bound( @@ -1402,9 +1402,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn confirm_impl_candidate(&mut self, - obligation: &Obligation<'tcx>, + obligation: &TraitObligation<'tcx>, impl_def_id: ast::DefId) - -> Result>, + -> Result>, SelectionError<'tcx>> { debug!("confirm_impl_candidate({},{})", @@ -1422,7 +1422,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { substs: Substs<'tcx>, cause: ObligationCause<'tcx>, recursion_depth: uint) - -> VtableImplData<'tcx, Obligation<'tcx>> + -> VtableImplData<'tcx, TraitObligation<'tcx>> { let impl_obligations = self.impl_obligations(cause, @@ -1435,7 +1435,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn confirm_fn_pointer_candidate(&mut self, - obligation: &Obligation<'tcx>) + obligation: &TraitObligation<'tcx>) -> Result,SelectionError<'tcx>> { debug!("confirm_fn_pointer_candidate({})", @@ -1480,7 +1480,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn confirm_unboxed_closure_candidate(&mut self, - obligation: &Obligation<'tcx>, + obligation: &TraitObligation<'tcx>, closure_def_id: ast::DefId, substs: &Substs<'tcx>) -> Result<(),SelectionError<'tcx>> @@ -1531,7 +1531,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn rematch_impl(&mut self, impl_def_id: ast::DefId, - obligation: &Obligation<'tcx>) + obligation: &TraitObligation<'tcx>) -> Substs<'tcx> { match self.match_impl(impl_def_id, obligation) { @@ -1550,7 +1550,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn match_impl(&mut self, impl_def_id: ast::DefId, - obligation: &Obligation<'tcx>) + obligation: &TraitObligation<'tcx>) -> Result, ()> { let impl_trait_ref = ty::impl_trait_ref(self.tcx(), @@ -1577,7 +1577,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn fast_reject_trait_refs(&mut self, - obligation: &Obligation, + obligation: &TraitObligation, impl_trait_ref: &ty::TraitRef) -> bool { @@ -1600,7 +1600,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn match_trait_refs(&mut self, - obligation: &Obligation<'tcx>, + obligation: &TraitObligation<'tcx>, trait_ref: Rc>) -> Result<(),()> { @@ -1762,13 +1762,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Miscellany fn push_stack<'o,'s:'o>(&mut self, - previous_stack: Option<&'s ObligationStack<'s, 'tcx>>, - obligation: &'o Obligation<'tcx>) - -> ObligationStack<'o, 'tcx> + previous_stack: Option<&'s TraitObligationStack<'s, 'tcx>>, + obligation: &'o TraitObligation<'tcx>) + -> TraitObligationStack<'o, 'tcx> { let skol_trait_ref = obligation.trait_ref.fold_with(&mut self.skolemizer); - ObligationStack { + TraitObligationStack { obligation: obligation, skol_trait_ref: skol_trait_ref, previous: previous_stack.map(|p| p), // FIXME variance @@ -1790,7 +1790,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { recursion_depth: uint, impl_def_id: ast::DefId, impl_substs: &Substs<'tcx>) - -> VecPerParamSpace> + -> VecPerParamSpace> { let impl_generics = ty::lookup_item_type(self.tcx(), impl_def_id).generics; let bounds = impl_generics.to_bounds(self.tcx(), impl_substs); @@ -1840,14 +1840,16 @@ impl<'tcx> SelectionCache<'tcx> { } } -impl<'o, 'tcx> ObligationStack<'o, 'tcx> { - fn iter(&self) -> Option<&ObligationStack<'o, 'tcx>> { +impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> { + fn iter(&self) -> Option<&TraitObligationStack<'o, 'tcx>> { Some(self) } } -impl<'o, 'tcx> Iterator<&'o ObligationStack<'o, 'tcx>> for Option<&'o ObligationStack<'o, 'tcx>> { - fn next(&mut self) -> Option<&'o ObligationStack<'o, 'tcx>> { +impl<'o, 'tcx> Iterator<&'o TraitObligationStack<'o,'tcx>> + for Option<&'o TraitObligationStack<'o, 'tcx>> +{ + fn next(&mut self) -> Option<&'o TraitObligationStack<'o, 'tcx>> { match *self { Some(o) => { *self = o.previous; @@ -1860,9 +1862,9 @@ impl<'o, 'tcx> Iterator<&'o ObligationStack<'o, 'tcx>> for Option<&'o Obligation } } -impl<'o, 'tcx> Repr<'tcx> for ObligationStack<'o, 'tcx> { +impl<'o, 'tcx> Repr<'tcx> for TraitObligationStack<'o, 'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { - format!("ObligationStack({})", + format!("TraitObligationStack({})", self.obligation.repr(tcx)) } } diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 159b6961782c..9ffa5b76a993 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -21,7 +21,7 @@ use syntax::codemap::Span; use util::common::ErrorReported; use util::ppaux::Repr; -use super::{Obligation, ObligationCause, VtableImpl, +use super::{Obligation, ObligationCause, TraitObligation, VtableImpl, VtableParam, VtableParamData, VtableImplData}; /////////////////////////////////////////////////////////////////////////// @@ -181,7 +181,7 @@ pub fn obligations_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>, recursion_depth: uint, generic_bounds: &ty::GenericBounds<'tcx>, type_substs: &VecPerParamSpace>) - -> VecPerParamSpace> + -> VecPerParamSpace> { debug!("obligations_for_generics(generic_bounds={}, type_substs={})", @@ -213,7 +213,7 @@ fn push_obligations_for_param_bounds<'tcx>( index: uint, param_bounds: &ty::ParamBounds<'tcx>, param_type_substs: &VecPerParamSpace>, - obligations: &mut VecPerParamSpace>) + obligations: &mut VecPerParamSpace>) { let param_ty = *param_type_substs.get(space, index); for builtin_bound in param_bounds.builtin_bounds.iter() { @@ -262,7 +262,7 @@ pub fn obligation_for_builtin_bound<'tcx>( builtin_bound: ty::BuiltinBound, recursion_depth: uint, param_ty: Ty<'tcx>) - -> Result, ErrorReported> + -> Result, ErrorReported> { let trait_ref = trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty); match trait_ref { @@ -294,7 +294,7 @@ pub fn search_trait_and_supertraits_from_bound<'tcx>(tcx: &ty::ctxt<'tcx>, return None; } -impl<'tcx> Repr<'tcx> for super::Obligation<'tcx> { +impl<'tcx,O:Repr<'tcx>> Repr<'tcx> for super::Obligation<'tcx, O> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { format!("Obligation(trait_ref={},depth={})", self.trait_ref.repr(tcx), diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 3f555ec5c4cb..5f5709f87f77 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1623,8 +1623,10 @@ pub struct Generics<'tcx> { impl<'tcx> Generics<'tcx> { pub fn empty() -> Generics<'tcx> { - Generics { types: VecPerParamSpace::empty(), - regions: VecPerParamSpace::empty() } + Generics { + types: VecPerParamSpace::empty(), + regions: VecPerParamSpace::empty(), + } } pub fn has_type_params(&self, space: subst::ParamSpace) -> bool { @@ -1743,7 +1745,7 @@ pub struct ParameterEnvironment<'tcx> { /// /// Note: This effectively *duplicates* the `bounds` array for /// now. - pub caller_obligations: VecPerParamSpace>, + pub caller_obligations: VecPerParamSpace>, /// Caches the results of trait selection. This cache is used /// for things that have to do with the parameters in scope. diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 77092025349e..543d2bdd9574 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -137,11 +137,6 @@ pub trait TypeFolder<'tcx> { fn fold_item_substs(&mut self, i: ty::ItemSubsts<'tcx>) -> ty::ItemSubsts<'tcx> { super_fold_item_substs(self, i) } - - fn fold_obligation(&mut self, o: &traits::Obligation<'tcx>) - -> traits::Obligation<'tcx> { - super_fold_obligation(self, o) - } } /////////////////////////////////////////////////////////////////////////// @@ -434,9 +429,15 @@ impl<'tcx> TypeFoldable<'tcx> for ty::UnsizeKind<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for traits::Obligation<'tcx> { - fn fold_with>(&self, folder: &mut F) -> traits::Obligation<'tcx> { - folder.fold_obligation(self) +impl<'tcx,O> TypeFoldable<'tcx> for traits::Obligation<'tcx,O> + where O : TypeFoldable<'tcx> +{ + fn fold_with>(&self, folder: &mut F) -> traits::Obligation<'tcx, O> { + traits::Obligation { + cause: self.cause, + recursion_depth: self.recursion_depth, + trait_ref: self.trait_ref.fold_with(folder), + } } } @@ -687,17 +688,6 @@ pub fn super_fold_item_substs<'tcx, T: TypeFolder<'tcx>>(this: &mut T, } } -pub fn super_fold_obligation<'tcx, T:TypeFolder<'tcx>>(this: &mut T, - obligation: &traits::Obligation<'tcx>) - -> traits::Obligation<'tcx> -{ - traits::Obligation { - cause: obligation.cause, - recursion_depth: obligation.recursion_depth, - trait_ref: obligation.trait_ref.fold_with(this), - } -} - /////////////////////////////////////////////////////////////////////////// // Higher-ranked things diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7e29e7078d48..7270e66ab530 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1841,7 +1841,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub fn register_obligation(&self, - obligation: traits::Obligation<'tcx>) + obligation: traits::TraitObligation<'tcx>) { debug!("register_obligation({})", obligation.repr(self.tcx())); diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index 80363055a4bf..1f0a486edd38 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -12,9 +12,9 @@ use check::{FnCtxt, structurally_resolved_type}; use middle::subst::{SelfSpace, FnSpace}; use middle::traits; use middle::traits::{SelectionError, OutputTypeParameterMismatch, Overflow, Unimplemented}; -use middle::traits::{Obligation, obligation_for_builtin_bound}; +use middle::traits::{Obligation, ObligationCause, obligation_for_builtin_bound}; use middle::traits::{FulfillmentError, CodeSelectionError, CodeAmbiguity}; -use middle::traits::{ObligationCause}; +use middle::traits::{TraitObligation}; use middle::ty::{mod, Ty}; use middle::infer; use std::rc::Rc; @@ -323,7 +323,7 @@ pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) { } } -fn resolve_trait_ref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, obligation: &Obligation<'tcx>) +fn resolve_trait_ref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, obligation: &TraitObligation<'tcx>) -> (Rc>, Ty<'tcx>) { let trait_ref = @@ -354,7 +354,7 @@ pub fn report_fulfillment_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - obligation: &Obligation<'tcx>, + obligation: &TraitObligation<'tcx>, error: &SelectionError<'tcx>) { match *error { @@ -411,7 +411,7 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } pub fn maybe_report_ambiguity<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - obligation: &Obligation<'tcx>) { + obligation: &TraitObligation<'tcx>) { // Unable to successfully determine, probably means // insufficient type information, but could mean // ambiguous impls. The latter *ought* to be a @@ -500,7 +500,7 @@ pub fn select_new_fcx_obligations(fcx: &FnCtxt) { } fn note_obligation_cause<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - obligation: &Obligation<'tcx>) { + obligation: &TraitObligation<'tcx>) { let tcx = fcx.tcx(); let trait_name = ty::item_path_str(tcx, obligation.trait_ref.def_id); match obligation.cause.code { diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index b83bbd6b4c08..d29e5a9f4309 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -160,8 +160,10 @@ fn lookup_def_ccx(ccx: &CrateCtxt, sp: Span, id: ast::NodeId) fn no_params<'tcx>(t: Ty<'tcx>) -> ty::Polytype<'tcx> { ty::Polytype { - generics: ty::Generics {types: VecPerParamSpace::empty(), - regions: VecPerParamSpace::empty()}, + generics: ty::Generics { + types: VecPerParamSpace::empty(), + regions: VecPerParamSpace::empty(), + }, ty: t } } From 9bdd7f00401c0002011ab20b70b405a15fa9128c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 5 Dec 2014 01:59:17 -0500 Subject: [PATCH 02/10] Thread a id to `Obligation` --- src/librustc/middle/check_static.rs | 4 ++-- src/librustc/middle/traits/coherence.rs | 4 ++-- src/librustc/middle/traits/mod.rs | 20 +++++++++++++------- src/librustc/middle/ty.rs | 14 ++++++++++---- src/librustc_trans/trans/common.rs | 3 ++- src/librustc_typeck/check/method/confirm.rs | 2 +- src/librustc_typeck/check/method/mod.rs | 4 ++-- src/librustc_typeck/check/method/probe.rs | 2 +- src/librustc_typeck/check/mod.rs | 5 +++-- src/librustc_typeck/check/regionck.rs | 2 +- src/librustc_typeck/check/vtable.rs | 4 +++- src/librustc_typeck/check/wf.rs | 10 ++++++++-- 12 files changed, 48 insertions(+), 26 deletions(-) diff --git a/src/librustc/middle/check_static.rs b/src/librustc/middle/check_static.rs index a495d1e049d1..9aa258c16aa1 100644 --- a/src/librustc/middle/check_static.rs +++ b/src/librustc/middle/check_static.rs @@ -36,7 +36,7 @@ use util::nodemap::NodeSet; use syntax::ast; use syntax::print::pprust; use syntax::visit::Visitor; -use syntax::codemap::{DUMMY_SP, Span}; +use syntax::codemap::Span; use syntax::visit; #[deriving(Eq, PartialEq)] @@ -119,7 +119,7 @@ impl<'a, 'tcx> CheckStaticVisitor<'a, 'tcx> { let ty = ty::node_id_to_type(self.tcx, e.id); let infcx = infer::new_infer_ctxt(self.tcx); let mut fulfill_cx = traits::FulfillmentContext::new(); - let cause = traits::ObligationCause::misc(DUMMY_SP); + let cause = traits::ObligationCause::dummy(); let obligation = traits::obligation_for_builtin_bound(self.tcx, cause, ty, ty::BoundSync); fulfill_cx.register_obligation(self.tcx, obligation.unwrap()); diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index 1bce353cb0cf..822979c86017 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -11,7 +11,7 @@ //! See `doc.rs` for high-level documentation use super::SelectionContext; -use super::Obligation; +use super::{Obligation, ObligationCause}; use super::util; use middle::subst; @@ -48,7 +48,7 @@ pub fn impl_can_satisfy(infcx: &InferCtxt, // same types. let param_env = ty::empty_parameter_environment(); let mut selcx = SelectionContext::intercrate(infcx, ¶m_env, infcx.tcx); - let obligation = Obligation::misc(DUMMY_SP, impl1_trait_ref); + let obligation = Obligation::new(ObligationCause::dummy(), impl1_trait_ref); debug!("impl_can_satisfy(obligation={})", obligation.repr(infcx.tcx)); selcx.evaluate_impl(impl2_def_id, &obligation) } diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 1505fe7561b6..2600640a17da 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -59,6 +59,10 @@ pub type TraitObligation<'tcx> = Obligation<'tcx, Rc>>; #[deriving(Copy, Clone)] pub struct ObligationCause<'tcx> { pub span: Span, + + // the id of XXX + pub scope_id: ast::NodeId, + pub code: ObligationCauseCode<'tcx> } @@ -303,8 +307,8 @@ impl<'tcx,O> Obligation<'tcx,O> { trait_ref: trait_ref } } - pub fn misc(span: Span, trait_ref: O) -> Obligation<'tcx, O> { - Obligation::new(ObligationCause::misc(span), 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) } } @@ -315,17 +319,19 @@ impl<'tcx> Obligation<'tcx,Rc>> { } impl<'tcx> ObligationCause<'tcx> { - pub fn new(span: Span, code: ObligationCauseCode<'tcx>) + pub fn new(span: Span, + scope_id: ast::NodeId, + code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> { - ObligationCause { span: span, code: code } + ObligationCause { span: span, scope_id: scope_id, code: code } } - pub fn misc(span: Span) -> ObligationCause<'tcx> { - ObligationCause { span: span, code: MiscObligation } + pub fn misc(span: Span, scope_id: ast::NodeId) -> ObligationCause<'tcx> { + ObligationCause { span: span, scope_id: scope_id, code: MiscObligation } } pub fn dummy() -> ObligationCause<'tcx> { - ObligationCause { span: DUMMY_SP, code: MiscObligation } + ObligationCause { span: DUMMY_SP, scope_id: 0, code: MiscObligation } } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 5f5709f87f77..ee13fc5e3460 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -78,7 +78,7 @@ use std::rc::Rc; use std::collections::hash_map::{HashMap, Occupied, Vacant}; use arena::TypedArena; use syntax::abi; -use syntax::ast::{CrateNum, DefId, FnStyle, Ident, ItemTrait, LOCAL_CRATE}; +use syntax::ast::{CrateNum, DefId, DUMMY_NODE_ID, FnStyle, Ident, ItemTrait, LOCAL_CRATE}; use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId}; use syntax::ast::{Onceness, StmtExpr, StmtSemi, StructField, UnnamedField}; use syntax::ast::{Visibility}; @@ -3158,9 +3158,15 @@ pub fn type_moves_by_default<'tcx>(cx: &ctxt<'tcx>, let infcx = infer::new_infer_ctxt(cx); let mut fulfill_cx = traits::FulfillmentContext::new(); + + // we can use dummy values here because we won't report any errors + // that result nor will we pay any mind to region obligations that arise + // (there shouldn't really be any anyhow) + let cause = ObligationCause::misc(DUMMY_SP, DUMMY_NODE_ID); + let obligation = traits::obligation_for_builtin_bound( cx, - ObligationCause::misc(DUMMY_SP), + cause, ty, ty::BoundCopy).unwrap(); fulfill_cx.register_obligation(cx, obligation); @@ -5846,7 +5852,7 @@ pub fn empty_parameter_environment<'tcx>() -> ParameterEnvironment<'tcx> { /// See `ParameterEnvironment` struct def'n for details pub fn construct_parameter_environment<'tcx>( tcx: &ctxt<'tcx>, - span: Span, + _span: Span, generics: &ty::Generics<'tcx>, free_id: ast::NodeId) -> ParameterEnvironment<'tcx> @@ -5884,7 +5890,7 @@ pub fn construct_parameter_environment<'tcx>( let bounds = generics.to_bounds(tcx, &free_substs); let bounds = liberate_late_bound_regions(tcx, free_id_scope, &bind(bounds)).value; let obligations = traits::obligations_for_generics(tcx, - traits::ObligationCause::misc(span), + traits::ObligationCause::dummy(), &bounds, &free_substs.types); let type_bounds = bounds.types.subst(tcx, &free_substs); diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 77412b00299b..da6aa84cfa11 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -793,7 +793,8 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Do the initial selection for the obligation. This yields the // shallow result we are looking for -- that is, what specific impl. let mut selcx = traits::SelectionContext::new(&infcx, ¶m_env, tcx); - let obligation = traits::Obligation::misc(span, trait_ref.clone()); + let obligation = traits::Obligation::new(traits::ObligationCause::dummy(), + trait_ref.clone()); let selection = match selcx.select(&obligation) { Ok(Some(selection)) => selection, Ok(None) => { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index b6a9e2cbc59e..7b43b97a4bb3 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -462,7 +462,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { method_bounds.repr(self.tcx())); self.fcx.add_obligations_for_parameters( - traits::ObligationCause::misc(self.span), + traits::ObligationCause::misc(self.span, self.fcx.body_id), method_bounds_substs, method_bounds); diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 53bda93b28e0..1ab76740962b 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -169,7 +169,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, substs)); // Construct an obligation - let obligation = traits::Obligation::misc(span, trait_ref.clone()); + let obligation = traits::Obligation::misc(span, fcx.body_id, trait_ref.clone()); // Now we want to know if this can be matched let mut selcx = traits::SelectionContext::new(fcx.infcx(), @@ -219,7 +219,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, let method_bounds = method_ty.generics.to_bounds(fcx.tcx(), &trait_ref.substs); assert!(!method_bounds.has_escaping_regions()); fcx.add_obligations_for_parameters( - traits::ObligationCause::misc(span), + traits::ObligationCause::misc(span, fcx.body_id), &trait_ref.substs, &method_bounds); diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 4d23161f6dee..3d7590db748e 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -804,7 +804,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { let obligations = traits::obligations_for_generics( self.tcx(), - traits::ObligationCause::misc(self.span), + traits::ObligationCause::misc(self.span, self.fcx.body_id), &impl_bounds, &substs.types); debug!("impl_obligations={}", obligations.repr(self.tcx())); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7270e66ab530..265766029b50 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1790,6 +1790,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.add_obligations_for_parameters( traits::ObligationCause::new( span, + self.body_id, traits::ItemObligation(def_id)), &substs, &bounds); @@ -1817,7 +1818,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let obligation = traits::obligation_for_builtin_bound( self.tcx(), - traits::ObligationCause::new(span, code), + traits::ObligationCause::new(span, self.body_id, code), ty, bound); if let Ok(ob) = obligation { @@ -5197,7 +5198,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, debug!("after late-bounds have been replaced: bounds={}", bounds.repr(fcx.tcx())); fcx.add_obligations_for_parameters( - traits::ObligationCause::new(span, traits::ItemObligation(def.def_id())), + traits::ObligationCause::new(span, fcx.body_id, traits::ItemObligation(def.def_id())), &substs, &bounds); diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 80ee2cce4ce7..c53ad34a6d22 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -938,7 +938,7 @@ fn check_expr_fn_block(rcx: &mut Rcx, // Check that the type meets the criteria of the existential bounds: for builtin_bound in bounds.builtin_bounds.iter() { let code = traits::ClosureCapture(var_node_id, expr.span); - let cause = traits::ObligationCause::new(freevar.span, code); + let cause = traits::ObligationCause::new(freevar.span, rcx.fcx.body_id, code); let obligation = traits::obligation_for_builtin_bound(rcx.tcx(), cause, var_ty, builtin_bound); if let Ok(obligation) = obligation { diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index 1f0a486edd38..17651b9bfb61 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -252,7 +252,7 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let sized_obligation = traits::obligation_for_builtin_bound( fcx.tcx(), - traits::ObligationCause::new(span, traits::ObjectSized), + traits::ObligationCause::new(span, fcx.body_id, traits::ObjectSized), referent_ty, ty::BoundSized); match sized_obligation { @@ -287,6 +287,7 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let object_obligation = Obligation::new( ObligationCause::new(span, + fcx.body_id, traits::ObjectCastObligation(object_trait_ty)), object_trait_ref.clone()); fcx.register_obligation(object_obligation); @@ -299,6 +300,7 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let obligation = obligation_for_builtin_bound( fcx.tcx(), ObligationCause::new(span, + fcx.body_id, traits::ObjectCastObligation(object_trait_ty)), referent_ty, builtin_bound); diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index a011982a1fc5..23db98b31758 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -122,7 +122,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { // For DST, all intermediate types must be sized. if variant.fields.len() > 0 { for field in variant.fields.init().iter() { - let cause = traits::ObligationCause::new(field.span, traits::FieldSized); + let cause = traits::ObligationCause::new(field.span, + fcx.body_id, + traits::FieldSized); let obligation = traits::obligation_for_builtin_bound(fcx.tcx(), cause, field.ty, @@ -223,6 +225,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { let cause = traits::ObligationCause::new( item.span, + fcx.body_id, traits::ItemObligation(trait_ref.def_id)); // Find the supertrait bounds. This will add `int:Bar`. @@ -291,6 +294,7 @@ impl<'cx,'tcx> BoundsChecker<'cx,'tcx> { self.fcx.add_obligations_for_parameters( traits::ObligationCause::new( self.span, + self.fcx.body_id, traits::ItemObligation(trait_ref.def_id)), &trait_ref.substs, &bounds); @@ -341,6 +345,7 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { if self.binding_count == 0 { self.fcx.add_obligations_for_parameters( traits::ObligationCause::new(self.span, + self.fcx.body_id, traits::ItemObligation(type_id)), substs, &polytype.generics.to_bounds(self.tcx(), substs)); @@ -369,6 +374,7 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { // that will require an RFC. -nmatsakis) self.fcx.add_trait_obligations_for_generics( traits::ObligationCause::new(self.span, + self.fcx.body_id, traits::ItemObligation(type_id)), substs, &polytype.generics.to_bounds(self.tcx(), substs)); @@ -469,7 +475,7 @@ fn check_struct_safe_for_destructor<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, if !struct_tpt.generics.has_type_params(subst::TypeSpace) && !struct_tpt.generics.has_region_params(subst::TypeSpace) { - let cause = traits::ObligationCause::new(span, traits::DropTrait); + let cause = traits::ObligationCause::new(span, fcx.body_id, traits::DropTrait); let obligation = traits::obligation_for_builtin_bound(fcx.tcx(), cause, self_ty, From 70be49d2c7372313921f8121d5c4fe83821a3b65 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 5 Dec 2014 02:57:17 -0500 Subject: [PATCH 03/10] Move the list of region obligations into the fulfillment context. --- src/librustc/middle/traits/fulfill.rs | 70 ++++++++++++++++++++++++++- src/librustc/middle/traits/mod.rs | 2 +- src/librustc_typeck/check/mod.rs | 59 +++------------------- src/librustc_typeck/check/regionck.rs | 19 +++----- 4 files changed, 83 insertions(+), 67 deletions(-) diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index f6428efc4e4e..d0e401d35518 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -9,11 +9,15 @@ // except according to those terms. use middle::mem_categorization::Typer; -use middle::ty; -use middle::infer::InferCtxt; +use middle::ty::{mod, Ty}; +use middle::infer::{mod, InferCtxt}; use std::collections::HashSet; +use std::collections::hash_map::{Occupied, Vacant}; +use std::default::Default; use std::rc::Rc; +use syntax::ast; use util::ppaux::Repr; +use util::nodemap::NodeMap; use super::CodeAmbiguity; use super::TraitObligation; @@ -47,6 +51,38 @@ pub struct FulfillmentContext<'tcx> { // attempted to select. This is used to avoid repeating work // when `select_new_obligations` is called. attempted_mark: uint, + + // A set of constraints that regionck must validate. Each + // constraint has the form `T:'a`, meaning "some type `T` must + // outlive the lifetime 'a". These constraints derive from + // instantiated type parameters. So if you had a struct defined + // like + // + // struct Foo { ... } + // + // then in some expression `let x = Foo { ... }` it will + // instantiate the type parameter `T` with a fresh type `$0`. At + // the same time, it will record a region obligation of + // `$0:'static`. This will get checked later by regionck. (We + // can't generally check these things right away because we have + // to wait until types are resolved.) + // + // These are stored in a map keyed to the id of the innermost + // enclosing fn body / static initializer expression. This is + // because the location where the obligation was incurred can be + // relevant with respect to which sublifetime assumptions are in + // place. The reason that we store under the fn-id, and not + // something more fine-grained, is so that it is easier for + // regionck to be sure that it has found *all* the region + // obligations (otherwise, it's easy to fail to walk to a + // particular node-id). + region_obligations: NodeMap>>, +} + +pub struct RegionObligation<'tcx> { + pub sub_region: ty::Region, + pub sup_type: Ty<'tcx>, + pub origin: infer::SubregionOrigin<'tcx>, } impl<'tcx> FulfillmentContext<'tcx> { @@ -55,6 +91,7 @@ impl<'tcx> FulfillmentContext<'tcx> { duplicate_set: HashSet::new(), trait_obligations: Vec::new(), attempted_mark: 0, + region_obligations: NodeMap::new(), } } @@ -71,6 +108,26 @@ impl<'tcx> FulfillmentContext<'tcx> { } } + pub fn register_region_obligation(&mut self, + body_id: ast::NodeId, + region_obligation: RegionObligation<'tcx>) + { + match self.region_obligations.entry(body_id) { + Vacant(entry) => { entry.set(vec![region_obligation]); }, + Occupied(mut entry) => { entry.get_mut().push(region_obligation); }, + } + } + + pub fn region_obligations(&self, + body_id: ast::NodeId) + -> &[RegionObligation<'tcx>] + { + match self.region_obligations.get(&body_id) { + None => Default::default(), + Some(vec) => vec.as_slice(), + } + } + pub fn select_all_or_error<'a>(&mut self, infcx: &InferCtxt<'a,'tcx>, param_env: &ty::ParameterEnvironment<'tcx>, @@ -208,3 +265,12 @@ 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={})", + self.sub_region.repr(tcx), + self.sup_type.repr(tcx), + self.origin.repr(tcx)) + } +} diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 2600640a17da..aab1fbcdbfd6 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -25,7 +25,7 @@ use syntax::ast; use syntax::codemap::{Span, DUMMY_SP}; use util::common::ErrorReported; -pub use self::fulfill::FulfillmentContext; +pub use self::fulfill::{FulfillmentContext, RegionObligation}; pub use self::select::SelectionContext; pub use self::select::SelectionCache; pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch}; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 265766029b50..c7be362f1875 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -84,13 +84,14 @@ use self::TupleArgumentsFlag::*; use astconv::{mod, ast_region_to_region, ast_ty_to_ty, AstConv}; use check::_match::pat_ctxt; -use middle::{const_eval, def, traits}; +use middle::{const_eval, def}; use middle::infer; use middle::lang_items::IteratorItem; use middle::mem_categorization::{mod, McResult}; use middle::pat_util::{mod, pat_id_map}; use middle::region::CodeExtent; use middle::subst::{mod, Subst, Substs, VecPerParamSpace, ParamSpace}; +use middle::traits; use middle::ty::{FnSig, VariantInfo, Polytype}; use middle::ty::{Disr, ParamTy, ParameterEnvironment}; use middle::ty::{mod, Ty}; @@ -108,7 +109,6 @@ use util::ppaux::{mod, UserString, Repr}; use util::nodemap::{DefIdMap, FnvHashMap, NodeMap}; use std::cell::{Cell, Ref, RefCell}; -use std::collections::hash_map::{Occupied, Vacant}; use std::mem::replace; use std::rc::Rc; use syntax::{mod, abi, attr}; @@ -161,42 +161,10 @@ pub struct Inherited<'a, 'tcx: 'a> { // one is never copied into the tcx: it is only used by regionck. fn_sig_map: RefCell>>>, - // A set of constraints that regionck must validate. Each - // constraint has the form `T:'a`, meaning "some type `T` must - // outlive the lifetime 'a". These constraints derive from - // instantiated type parameters. So if you had a struct defined - // like - // - // struct Foo { ... } - // - // then in some expression `let x = Foo { ... }` it will - // instantiate the type parameter `T` with a fresh type `$0`. At - // the same time, it will record a region obligation of - // `$0:'static`. This will get checked later by regionck. (We - // can't generally check these things right away because we have - // to wait until types are resolved.) - // - // These are stored in a map keyed to the id of the innermost - // enclosing fn body / static initializer expression. This is - // because the location where the obligation was incurred can be - // relevant with respect to which sublifetime assumptions are in - // place. The reason that we store under the fn-id, and not - // something more fine-grained, is so that it is easier for - // regionck to be sure that it has found *all* the region - // obligations (otherwise, it's easy to fail to walk to a - // particular node-id). - region_obligations: RefCell>>>, - // Tracks trait obligations incurred during this function body. fulfillment_cx: RefCell>, } -struct RegionObligation<'tcx> { - sub_region: ty::Region, - sup_type: Ty<'tcx>, - origin: infer::SubregionOrigin<'tcx>, -} - /// When type-checking an expression, we propagate downward /// whatever type hint we are able in the form of an `Expectation`. enum Expectation<'tcx> { @@ -328,7 +296,6 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> { upvar_borrow_map: RefCell::new(FnvHashMap::new()), unboxed_closures: RefCell::new(DefIdMap::new()), fn_sig_map: RefCell::new(NodeMap::new()), - region_obligations: RefCell::new(NodeMap::new()), fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()), } } @@ -1988,15 +1955,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty: Ty<'tcx>, r: ty::Region) { - let mut region_obligations = self.inh.region_obligations.borrow_mut(); - let region_obligation = RegionObligation { sub_region: r, - sup_type: ty, - origin: origin }; - - match region_obligations.entry(self.body_id) { - Vacant(entry) => { entry.set(vec![region_obligation]); }, - Occupied(mut entry) => { entry.get_mut().push(region_obligation); }, - } + 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); } pub fn add_default_region_param_bounds(&self, @@ -5833,11 +5796,3 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { } } -impl<'tcx> Repr<'tcx> for RegionObligation<'tcx> { - fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { - format!("RegionObligation(sub_region={}, sup_type={}, origin={})", - self.sub_region.repr(tcx), - self.sup_type.repr(tcx), - self.origin.repr(tcx)) - } -} diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index c53ad34a6d22..1564287f15f9 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -353,18 +353,13 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { fn visit_region_obligations(&mut self, node_id: ast::NodeId) { debug!("visit_region_obligations: node_id={}", node_id); - let region_obligations = self.fcx.inh.region_obligations.borrow(); - match region_obligations.get(&node_id) { - None => { } - Some(vec) => { - for r_o in vec.iter() { - 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 fulfillment_cx = self.fcx.inh.fulfillment_cx.borrow(); + for r_o in fulfillment_cx.region_obligations(node_id).iter() { + 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); } } From 9409bd9ff87941fcdddb5af7cb3b22c0e7a29c30 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 5 Dec 2014 11:04:49 -0500 Subject: [PATCH 04/10] Introduce predicates but don't use them. --- src/librustc/metadata/decoder.rs | 4 +++- src/librustc/middle/astencode.rs | 3 +++ src/librustc/middle/ty.rs | 17 +++++++++++++++++ src/librustc/middle/ty_fold.rs | 19 +++++++++++++++++++ src/librustc_typeck/lib.rs | 1 + 5 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 23bd37486bc0..79bfc46dca8d 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -1437,7 +1437,9 @@ fn doc_generics<'tcx>(base_doc: rbml::Doc, true }); - ty::Generics { types: types, regions: regions } + let predicates = subst::VecPerParamSpace::empty(); // TODO fix in later commit + + ty::Generics { types: types, regions: regions, predicates: predicates } } pub fn is_associated_type(cdata: Cmd, id: ast::NodeId) -> bool { diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 8c2fbc078e2e..319337bf48b7 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -1554,6 +1554,9 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { Ok(this.read_vec_per_param_space( |this| Decodable::decode(this).unwrap())) }).unwrap(), + + predicates: + subst::VecPerParamSpace::empty(), // TODO fix in later commit }) }) }).unwrap(), diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index ee13fc5e3460..ef8e3f3b2d7f 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1619,6 +1619,22 @@ pub struct RegionParameterDef { pub struct Generics<'tcx> { pub types: VecPerParamSpace>, pub regions: VecPerParamSpace, + pub predicates: VecPerParamSpace>, +} + +#[deriving(Clone, Show)] +pub enum Predicate<'tcx> { + /// where Foo : Bar + Trait(Rc>), + + /// where Foo == Bar + Equate(Ty<'tcx>, Ty<'tcx>), + + /// where 'a : 'b + RegionOutlives(Region, Region), + + /// where T : 'a + TypeOutlives(Ty<'tcx>, Region), } impl<'tcx> Generics<'tcx> { @@ -1626,6 +1642,7 @@ impl<'tcx> Generics<'tcx> { Generics { types: VecPerParamSpace::empty(), regions: VecPerParamSpace::empty(), + predicates: VecPerParamSpace::empty(), } } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 543d2bdd9574..87467ba064a2 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -399,6 +399,25 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Generics<'tcx> { ty::Generics { types: self.types.fold_with(folder), regions: self.regions.fold_with(folder), + predicates: self.predicates.fold_with(folder), + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { + fn fold_with>(&self, folder: &mut F) -> ty::Predicate<'tcx> { + match *self { + ty::Predicate::Trait(ref a) => + ty::Predicate::Trait(a.fold_with(folder)), + ty::Predicate::Equate(ref a, ref b) => + ty::Predicate::Equate(a.fold_with(folder), + b.fold_with(folder)), + ty::Predicate::RegionOutlives(ref a, ref b) => + ty::Predicate::RegionOutlives(a.fold_with(folder), + b.fold_with(folder)), + ty::Predicate::TypeOutlives(ref a, ref b) => + ty::Predicate::TypeOutlives(a.fold_with(folder), + b.fold_with(folder)), } } } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index d29e5a9f4309..41ed5b8ec365 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -163,6 +163,7 @@ fn no_params<'tcx>(t: Ty<'tcx>) -> ty::Polytype<'tcx> { generics: ty::Generics { types: VecPerParamSpace::empty(), regions: VecPerParamSpace::empty(), + predicates: VecPerParamSpace::empty(), }, ty: t } From 2be6c4f1ca6726068ceb70e7fb5369f2c1a42bb0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 6 Dec 2014 01:30:41 -0500 Subject: [PATCH 05/10] Write code for registering region obligations (but don't use it yet). --- src/librustc/middle/infer/error_reporting.rs | 4 ++ src/librustc/middle/infer/mod.rs | 11 ++++- src/librustc/middle/traits/fulfill.rs | 47 ++++++++++++++++---- src/librustc/middle/traits/mod.rs | 19 ++++---- src/librustc/middle/traits/util.rs | 26 +++++------ src/librustc_typeck/check/mod.rs | 24 +++++----- src/librustc_typeck/check/regionck.rs | 4 +- src/librustc_typeck/collect.rs | 33 ++++++++++++++ 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 d24eddf9ab05..e2a57629d7eb 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 81cd8dd20d20..3b62b96a3e9b 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 d0e401d35518..28f92089ce9e 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 aab1fbcdbfd6..37da82891deb 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 9ffa5b76a993..360298feab79 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 c7be362f1875..cd5cade78db7 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 1564287f15f9..328c1eafae5c 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 6b7f08e81045..9cfb56fbf8cb 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, From 9f492fefef8d9a75f6dc27c834561fe977ca70c5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 7 Dec 2014 11:10:48 -0500 Subject: [PATCH 06/10] Switch to using predicates to drive checking. Correct various tests -- in most cases, just the error message changed, but in some cases we are reporting new errors that OUGHT to have been reported before but we're overlooked (mostly involving the `'static` bound on `Send`). --- src/libcore/kinds.rs | 2 +- src/librustc/metadata/common.rs | 4 + src/librustc/metadata/decoder.rs | 16 +- src/librustc/metadata/encoder.rs | 12 + src/librustc/metadata/tydecode.rs | 29 +- src/librustc/metadata/tyencode.rs | 27 ++ src/librustc/middle/check_static.rs | 21 +- src/librustc/middle/traits/fulfill.rs | 242 ++++++++----- src/librustc/middle/traits/mod.rs | 80 ++--- src/librustc/middle/traits/select.rs | 186 ++++++---- src/librustc/middle/traits/util.rs | 291 ++++++++-------- src/librustc/middle/ty.rs | 327 ++++++++++-------- src/librustc/middle/ty_fold.rs | 3 +- src/librustc/util/ppaux.rs | 10 +- src/librustc_trans/trans/common.rs | 4 +- src/librustc_typeck/astconv.rs | 86 ++--- src/librustc_typeck/check/closure.rs | 26 +- src/librustc_typeck/check/method/confirm.rs | 1 - src/librustc_typeck/check/method/mod.rs | 14 +- src/librustc_typeck/check/method/probe.rs | 33 +- src/librustc_typeck/check/mod.rs | 117 ++----- src/librustc_typeck/check/regionck.rs | 25 +- src/librustc_typeck/check/regionmanip.rs | 18 +- src/librustc_typeck/check/vtable.rs | 185 ++++++---- src/librustc_typeck/check/wf.rs | 75 ++-- src/librustc_typeck/collect.rs | 44 ++- .../builtin-superkinds-self-type.rs | 1 - .../compile-fail/builtin-superkinds-simple.rs | 2 +- .../compile-fail/kindck-impl-type-params.rs | 1 + src/test/compile-fail/kindck-send-object1.rs | 2 +- src/test/compile-fail/kindck-send-owned.rs | 2 +- .../kindck-send-region-pointers.rs | 6 +- src/test/compile-fail/kindck-send-unsafe.rs | 2 +- src/test/compile-fail/recursion_limit.rs | 4 +- .../region-object-lifetime-in-coercion.rs | 6 +- .../compile-fail/regions-bounded-by-send.rs | 14 +- ...gions-bounded-by-trait-requiring-static.rs | 12 +- .../regions-bounded-method-type-parameters.rs | 2 +- src/test/compile-fail/regions-proc-bounds.rs | 2 +- 39 files changed, 1064 insertions(+), 870 deletions(-) diff --git a/src/libcore/kinds.rs b/src/libcore/kinds.rs index f932acffd3c2..2b92ae8af0ab 100644 --- a/src/libcore/kinds.rs +++ b/src/libcore/kinds.rs @@ -19,7 +19,7 @@ /// Types able to be transferred across task boundaries. #[lang="send"] -pub trait Send for Sized? { +pub trait Send for Sized? : 'static { // empty. } diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 315e0eea9b76..99e7966b66f6 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -251,3 +251,7 @@ pub const tag_type_param_def: uint = 0xa5; pub const tag_item_generics: uint = 0xa6; pub const tag_method_ty_generics: uint = 0xa7; + +pub const tag_predicate: uint = 0xa8; +pub const tag_predicate_space: uint = 0xa9; +pub const tag_predicate_data: uint = 0xb0; diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 79bfc46dca8d..898f5d2ef93c 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -23,7 +23,8 @@ use metadata::csearch; use metadata::cstore; use metadata::tydecode::{parse_ty_data, parse_region_data, parse_def_id, parse_type_param_def_data, parse_bounds_data, - parse_bare_fn_ty_data, parse_trait_ref_data}; + parse_bare_fn_ty_data, parse_trait_ref_data, + parse_predicate_data}; use middle::def; use middle::lang_items; use middle::resolve::{TraitItemKind, TypeTraitItemKind}; @@ -1437,7 +1438,18 @@ fn doc_generics<'tcx>(base_doc: rbml::Doc, true }); - let predicates = subst::VecPerParamSpace::empty(); // TODO fix in later commit + let mut predicates = subst::VecPerParamSpace::empty(); + reader::tagged_docs(doc, tag_predicate, |predicate_doc| { + let space_doc = reader::get_doc(predicate_doc, tag_predicate_space); + let space = subst::ParamSpace::from_uint(reader::doc_as_u8(space_doc) as uint); + + let data_doc = reader::get_doc(predicate_doc, tag_predicate_data); + let data = parse_predicate_data(data_doc.data, data_doc.start, cdata.cnum, tcx, + |_, did| translate_def_id(cdata, did)); + + predicates.push(space, data); + true + }); ty::Generics { types: types, regions: regions, predicates: predicates } } diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index a3f56f7f655f..48d1284f5078 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -803,6 +803,18 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder, rbml_w.end_tag(); } + for (space, _, predicate) in generics.predicates.iter_enumerated() { + rbml_w.start_tag(tag_predicate); + + rbml_w.wr_tagged_u8(tag_predicate_space, space as u8); + + rbml_w.start_tag(tag_predicate_data); + tyencode::enc_predicate(rbml_w.writer, ty_str_ctxt, predicate); + rbml_w.end_tag(); + + rbml_w.end_tag(); + } + rbml_w.end_tag(); } diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index e29741fb4a12..37d790df37f4 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -470,7 +470,7 @@ fn parse_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> Ty<'tcx> { st.tcx.rcache.borrow_mut().insert(key, tt); return tt; } - '"' => { + '\"' => { let _ = parse_def(st, TypeWithId, |x,y| conv(x,y)); let inner = parse_ty(st, |x,y| conv(x,y)); inner @@ -646,6 +646,33 @@ pub fn parse_def_id(buf: &[u8]) -> ast::DefId { ast::DefId { krate: crate_num, node: def_num } } +pub fn parse_predicate_data<'tcx>(data: &[u8], + start: uint, + crate_num: ast::CrateNum, + tcx: &ty::ctxt<'tcx>, + conv: conv_did) + -> ty::Predicate<'tcx> +{ + let mut st = parse_state_from_data(data, crate_num, start, tcx); + parse_predicate(&mut st, conv) +} + +pub fn parse_predicate<'a,'tcx>(st: &mut PState<'a, 'tcx>, + conv: conv_did) + -> ty::Predicate<'tcx> +{ + match next(st) { + 't' => ty::Predicate::Trait(Rc::new(parse_trait_ref(st, conv))), + 'e' => ty::Predicate::Equate(parse_ty(st, |x,y| conv(x,y)), + parse_ty(st, |x,y| conv(x,y))), + 'r' => ty::Predicate::RegionOutlives(parse_region(st, |x,y| conv(x,y)), + parse_region(st, |x,y| conv(x,y))), + 'o' => ty::Predicate::TypeOutlives(parse_ty(st, |x,y| conv(x,y)), + parse_region(st, |x,y| conv(x,y))), + c => panic!("Encountered invalid character in metadata: {}", c) + } +} + pub fn parse_type_param_def_data<'tcx>(data: &[u8], start: uint, crate_num: ast::CrateNum, tcx: &ty::ctxt<'tcx>, conv: conv_did) -> ty::TypeParameterDef<'tcx> diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index bbb2faaae069..5c7d15e16018 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -413,3 +413,30 @@ pub fn enc_type_param_def<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tc enc_bounds(w, cx, &v.bounds); enc_opt(w, v.default, |w, t| enc_ty(w, cx, t)); } + +pub fn enc_predicate<'a, 'tcx>(w: &mut SeekableMemWriter, + cx: &ctxt<'a, 'tcx>, + p: &ty::Predicate<'tcx>) +{ + match *p { + ty::Predicate::Trait(ref trait_ref) => { + mywrite!(w, "t"); + enc_trait_ref(w, cx, &**trait_ref); + } + ty::Predicate::Equate(a, b) => { + mywrite!(w, "e"); + enc_ty(w, cx, a); + enc_ty(w, cx, b); + } + ty::Predicate::RegionOutlives(a, b) => { + mywrite!(w, "r"); + enc_region(w, cx, a); + enc_region(w, cx, b); + } + ty::Predicate::TypeOutlives(a, b) => { + mywrite!(w, "o"); + enc_ty(w, cx, a); + enc_region(w, cx, b); + } + } +} diff --git a/src/librustc/middle/check_static.rs b/src/librustc/middle/check_static.rs index 9aa258c16aa1..5a53979d7193 100644 --- a/src/librustc/middle/check_static.rs +++ b/src/librustc/middle/check_static.rs @@ -31,6 +31,7 @@ use middle::infer; use middle::traits; use middle::mem_categorization as mc; use middle::expr_use_visitor as euv; +use util::common::ErrorReported; use util::nodemap::NodeSet; use syntax::ast; @@ -119,15 +120,17 @@ impl<'a, 'tcx> CheckStaticVisitor<'a, 'tcx> { let ty = ty::node_id_to_type(self.tcx, e.id); let infcx = infer::new_infer_ctxt(self.tcx); let mut fulfill_cx = traits::FulfillmentContext::new(); - let cause = traits::ObligationCause::dummy(); - let obligation = traits::obligation_for_builtin_bound(self.tcx, cause, ty, - ty::BoundSync); - fulfill_cx.register_obligation(self.tcx, obligation.unwrap()); - let env = ty::empty_parameter_environment(); - let result = fulfill_cx.select_all_or_error(&infcx, &env, self.tcx).is_ok(); - if !result { - self.tcx.sess.span_err(e.span, "shared static items must have a \ - type which implements Sync"); + match traits::trait_ref_for_builtin_bound(self.tcx, ty::BoundSync, ty) { + Ok(trait_ref) => { + fulfill_cx.register_trait_ref(self.tcx, trait_ref, + traits::ObligationCause::dummy()); + let env = ty::empty_parameter_environment(); + if !fulfill_cx.select_all_or_error(&infcx, &env, self.tcx).is_ok() { + self.tcx.sess.span_err(e.span, "shared static items must have a \ + type which implements Sync"); + } + } + Err(ErrorReported) => { } } } } diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 28f92089ce9e..9d9c3e238d40 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -10,22 +10,26 @@ use middle::mem_categorization::Typer; use middle::ty::{mod, Ty}; -use middle::infer::{mod, InferCtxt, ures}; +use middle::infer::{mod, InferCtxt}; use std::collections::HashSet; use std::collections::hash_map::{Occupied, Vacant}; use std::default::Default; use std::rc::Rc; use syntax::ast; +use util::common::ErrorReported; use util::ppaux::Repr; use util::nodemap::NodeMap; use super::CodeAmbiguity; +use super::CodeSelectionError; +use super::FulfillmentError; use super::Obligation; use super::ObligationCause; -use super::TraitObligation; -use super::FulfillmentError; -use super::CodeSelectionError; +use super::PredicateObligation; +use super::Selection; use super::select::SelectionContext; +use super::trait_ref_for_builtin_bound; +use super::Unimplemented; /// The fulfillment context is used to drive trait resolution. It /// consists of a list of obligations that must be (eventually) @@ -43,11 +47,11 @@ pub struct FulfillmentContext<'tcx> { // than the `SelectionCache`: it avoids duplicate errors and // permits recursive obligations, which are often generated from // traits like `Send` et al. - duplicate_set: HashSet>>, + duplicate_set: HashSet>, // A list of all obligations that have been registered with this // fulfillment context. - trait_obligations: Vec>, + predicates: Vec>, // Remembers the count of trait obligations that we have already // attempted to select. This is used to avoid repeating work @@ -91,63 +95,61 @@ impl<'tcx> FulfillmentContext<'tcx> { pub fn new() -> FulfillmentContext<'tcx> { FulfillmentContext { duplicate_set: HashSet::new(), - trait_obligations: Vec::new(), + predicates: Vec::new(), attempted_mark: 0, region_obligations: NodeMap::new(), } } - pub fn register_predicate<'a>(&mut self, - infcx: &InferCtxt<'a,'tcx>, - predicate: &Obligation<'tcx, ty::Predicate<'tcx>>) - -> ures<'tcx> + pub fn register_builtin_bound(&mut self, + tcx: &ty::ctxt<'tcx>, + ty: Ty<'tcx>, + builtin_bound: ty::BuiltinBound, + cause: ObligationCause<'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)) + match trait_ref_for_builtin_bound(tcx, builtin_bound, ty) { + Ok(trait_ref) => { + self.register_trait_ref(tcx, trait_ref, cause); } + Err(ErrorReported) => { } } } - pub fn register_obligation(&mut self, - tcx: &ty::ctxt<'tcx>, - obligation: TraitObligation<'tcx>) + pub fn register_trait_ref<'a>(&mut self, + tcx: &ty::ctxt<'tcx>, + trait_ref: Rc>, + cause: ObligationCause<'tcx>) { - if self.duplicate_set.insert(obligation.trait_ref.clone()) { - debug!("register_obligation({})", obligation.repr(tcx)); - assert!(!obligation.trait_ref.has_escaping_regions()); - self.trait_obligations.push(obligation); - } else { - debug!("register_obligation({}) -- already seen, skip", obligation.repr(tcx)); - } + /*! + * A convenience function for registering trait obligations. + */ + + let trait_obligation = Obligation { cause: cause, + recursion_depth: 0, + trait_ref: ty::Predicate::Trait(trait_ref) }; + self.register_predicate(tcx, trait_obligation) } pub fn register_region_obligation(&mut self, - sup_type: Ty<'tcx>, - sub_region: ty::Region, + tcx: &ty::ctxt<'tcx>, + t_a: Ty<'tcx>, + r_b: ty::Region, cause: ObligationCause<'tcx>) { - 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); }, + register_region_obligation(tcx, t_a, r_b, cause, &mut self.region_obligations); + } + + pub fn register_predicate<'a>(&mut self, + tcx: &ty::ctxt<'tcx>, + predicate: PredicateObligation<'tcx>) + { + if !self.duplicate_set.insert(predicate.trait_ref.clone()) { + debug!("register_predicate({}) -- already seen, skip", predicate.repr(tcx)); + return; } + + debug!("register_predicate({})", predicate.repr(tcx)); + self.predicates.push(predicate); } pub fn region_obligations(&self, @@ -170,7 +172,7 @@ impl<'tcx> FulfillmentContext<'tcx> { // Anything left is ambiguous. let errors: Vec = - self.trait_obligations + self.predicates .iter() .map(|o| FulfillmentError::new((*o).clone(), CodeAmbiguity)) .collect(); @@ -206,8 +208,8 @@ impl<'tcx> FulfillmentContext<'tcx> { self.select(&mut selcx, false) } - pub fn pending_trait_obligations(&self) -> &[TraitObligation<'tcx>] { - self.trait_obligations[] + pub fn pending_obligations(&self) -> &[PredicateObligation<'tcx>] { + self.predicates[] } /// Attempts to select obligations using `selcx`. If `only_new_obligations` is true, then it @@ -218,14 +220,14 @@ impl<'tcx> FulfillmentContext<'tcx> { -> Result<(),Vec>> { debug!("select({} obligations, only_new_obligations={}) start", - self.trait_obligations.len(), + self.predicates.len(), only_new_obligations); let tcx = selcx.tcx(); let mut errors = Vec::new(); loop { - let count = self.trait_obligations.len(); + let count = self.predicates.len(); debug!("select_where_possible({} obligations) iteration", count); @@ -243,37 +245,24 @@ impl<'tcx> FulfillmentContext<'tcx> { // First pass: walk each obligation, retaining // only those that we cannot yet process. - self.trait_obligations.retain(|obligation| { - // Hack: Retain does not pass in the index, but we want - // to avoid processing the first `start_count` entries. - if skip > 0 { - skip -= 1; - true - } else { - match selcx.select(obligation) { - Ok(None) => { - true - } - Ok(Some(s)) => { - selections.push(s); - false - } - Err(selection_err) => { - debug!("obligation: {} error: {}", - obligation.repr(tcx), - selection_err.repr(tcx)); - errors.push(FulfillmentError::new( - (*obligation).clone(), - CodeSelectionError(selection_err))); - false - } + { + let region_obligations = &mut self.region_obligations; + self.predicates.retain(|predicate| { + // Hack: Retain does not pass in the index, but we want + // to avoid processing the first `start_count` entries. + if skip == 0 { + retain_predicate(selcx, predicate, + &mut selections, &mut errors, region_obligations) + } else { + skip -= 1; + true } - } - }); + }); + } - self.attempted_mark = self.trait_obligations.len(); + self.attempted_mark = self.predicates.len(); - if self.trait_obligations.len() == count { + if self.predicates.len() == count { // Nothing changed. break; } @@ -281,13 +270,12 @@ impl<'tcx> FulfillmentContext<'tcx> { // Now go through all the successful ones, // registering any nested obligations for the future. for selection in selections.into_iter() { - selection.map_move_nested( - |o| self.register_obligation(tcx, o)); + selection.map_move_nested(|p| self.register_predicate(tcx, p)); } } debug!("select({} obligations, {} errors) done", - self.trait_obligations.len(), + self.predicates.len(), errors.len()); if errors.len() == 0 { @@ -298,6 +286,76 @@ impl<'tcx> FulfillmentContext<'tcx> { } } +fn retain_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, + predicate: &PredicateObligation<'tcx>, + selections: &mut Vec>, + errors: &mut Vec>, + region_obligations: &mut NodeMap>>) + -> bool +{ + /*! + * Evaluates a predicate obligation and modifies the appropriate + * output array. Returns `true` if the predicate must be retained + * because it could not be fully evaluated yet due to insufficient + * type inference. + */ + + let tcx = selcx.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() }; + match selcx.select(&trait_obligation) { + Ok(None) => { + true + } + Ok(Some(s)) => { + selections.push(s); + false + } + Err(selection_err) => { + debug!("predicate: {} error: {}", + predicate.repr(tcx), + selection_err.repr(tcx)); + errors.push( + FulfillmentError::new( + predicate.clone(), + CodeSelectionError(selection_err))); + false + } + } + } + + ty::Predicate::Equate(a, b) => { + let origin = infer::EquatePredicate(predicate.cause.span); + match infer::mk_eqty(selcx.infcx(), false, origin, a, b) { + Ok(()) => { + false + } + Err(_) => { + errors.push( + FulfillmentError::new( + predicate.clone(), + CodeSelectionError(Unimplemented))); + false + } + } + } + + ty::Predicate::RegionOutlives(r_a, r_b) => { + let origin = infer::RelateRegionParamBound(predicate.cause.span); + let () = infer::mk_subr(selcx.infcx(), origin, r_b, r_a); // `b : a` ==> `a <= b` + false + } + + ty::Predicate::TypeOutlives(t_a, r_b) => { + register_region_obligation(tcx, t_a, r_b, predicate.cause, region_obligations); + false + } + } +} + impl<'tcx> Repr<'tcx> for RegionObligation<'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { format!("RegionObligation(sub_region={}, sup_type={})", @@ -305,3 +363,23 @@ impl<'tcx> Repr<'tcx> for RegionObligation<'tcx> { self.sup_type.repr(tcx)) } } + +fn register_region_obligation<'tcx>(tcx: &ty::ctxt<'tcx>, + t_a: Ty<'tcx>, + r_b: ty::Region, + cause: ObligationCause<'tcx>, + region_obligations: &mut NodeMap>>) +{ + let region_obligation = RegionObligation { sup_type: t_a, + sub_region: r_b, + cause: cause }; + + debug!("register_region_obligation({})", + region_obligation.repr(tcx)); + + match region_obligations.entry(region_obligation.cause.body_id) { + Vacant(entry) => { entry.set(vec![region_obligation]); }, + Occupied(mut entry) => { entry.get_mut().push(region_obligation); }, + } + +} diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 37da82891deb..f438b61e27c2 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -15,7 +15,6 @@ pub use self::FulfillmentErrorCode::*; pub use self::Vtable::*; pub use self::ObligationCauseCode::*; -use middle::mem_categorization::Typer; use middle::subst; use middle::ty::{mod, Ty}; use middle::infer::InferCtxt; @@ -23,13 +22,13 @@ use std::rc::Rc; use std::slice::Items; use syntax::ast; use syntax::codemap::{Span, DUMMY_SP}; -use util::common::ErrorReported; pub use self::fulfill::{FulfillmentContext, RegionObligation}; pub use self::select::SelectionContext; 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::elaborate_predicates; pub use self::util::supertraits; pub use self::util::Supertraits; pub use self::util::search_trait_and_supertraits_from_bound; @@ -54,6 +53,7 @@ pub struct Obligation<'tcx, T> { pub trait_ref: T, } +pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>; pub type TraitObligation<'tcx> = Obligation<'tcx, Rc>>; /// Why did we incur this obligation? Used for error reporting. @@ -91,7 +91,7 @@ pub enum ObligationCauseCode<'tcx> { // Captures of variable the given id by a closure (span is the // span of the closure) - ClosureCapture(ast::NodeId, Span), + ClosureCapture(ast::NodeId, Span, ty::BuiltinBound), // Types of fields (other than the last) in a struct must be sized. FieldSized, @@ -101,20 +101,20 @@ pub enum ObligationCauseCode<'tcx> { } pub type Obligations<'tcx, O> = subst::VecPerParamSpace>; - +pub type PredicateObligations<'tcx> = subst::VecPerParamSpace>; pub type TraitObligations<'tcx> = subst::VecPerParamSpace>; -pub type Selection<'tcx> = Vtable<'tcx, TraitObligation<'tcx>>; +pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>; #[deriving(Clone,Show)] pub enum SelectionError<'tcx> { Unimplemented, Overflow, - OutputTypeParameterMismatch(Rc>, ty::type_err<'tcx>) + OutputTypeParameterMismatch(Rc>, Rc>, ty::type_err<'tcx>), } pub struct FulfillmentError<'tcx> { - pub obligation: TraitObligation<'tcx>, + pub obligation: PredicateObligation<'tcx>, pub code: FulfillmentErrorCode<'tcx> } @@ -224,33 +224,6 @@ pub struct VtableParamData<'tcx> { pub bound: Rc>, } -/// Matches the self type of the inherent impl `impl_def_id` -/// against `self_ty` and returns the resulting resolution. This -/// routine may modify the surrounding type context (for example, -/// it may unify variables). -pub fn select_inherent_impl<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, - param_env: &ty::ParameterEnvironment<'tcx>, - typer: &Typer<'tcx>, - cause: ObligationCause<'tcx>, - impl_def_id: ast::DefId, - self_ty: Ty<'tcx>) - -> SelectionResult<'tcx, - VtableImplData<'tcx, TraitObligation<'tcx>>> -{ - // This routine is only suitable for inherent impls. This is - // because it does not attempt to unify the output type parameters - // from the trait ref against the values from the obligation. - // (These things do not apply to inherent impls, for which there - // is no trait ref nor obligation.) - // - // Matching against non-inherent impls should be done with - // `try_resolve_obligation()`. - assert!(ty::impl_trait_ref(infcx.tcx, impl_def_id).is_none()); - - let mut selcx = select::SelectionContext::new(infcx, param_env, typer); - selcx.select_inherent_impl(impl_def_id, cause, self_ty) -} - /// True if neither the trait nor self type is local. Note that `impl_def_id` must refer to an impl /// of a trait, not an inherent impl. pub fn is_orphan_impl(tcx: &ty::ctxt, @@ -270,32 +243,13 @@ pub fn overlapping_impls(infcx: &InferCtxt, coherence::impl_can_satisfy(infcx, impl2_def_id, impl1_def_id) } -/// Given generic bounds from an impl like: -/// -/// impl ... -/// -/// along with the bindings for the types `A` and `B` (e.g., ``), yields a result like -/// -/// [[Foo for A0, Bar for B0, Qux for B0], [], []] -/// -/// Expects that `generic_bounds` have already been fully substituted, late-bound regions liberated -/// and so forth, so that they are in the same namespace as `type_substs`. -pub fn obligations_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>, - cause: ObligationCause<'tcx>, - generic_bounds: &ty::GenericBounds<'tcx>, - type_substs: &subst::VecPerParamSpace>) - -> subst::VecPerParamSpace> +/// Creates predicate obligations from the generic bounds. +pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>, + cause: ObligationCause<'tcx>, + generic_bounds: &ty::GenericBounds<'tcx>) + -> PredicateObligations<'tcx> { - util::obligations_for_generics(tcx, cause, 0, generic_bounds, type_substs) -} - -pub fn obligation_for_builtin_bound<'tcx>(tcx: &ty::ctxt<'tcx>, - cause: ObligationCause<'tcx>, - source_ty: Ty<'tcx>, - builtin_bound: ty::BuiltinBound) - -> Result, ErrorReported> -{ - util::obligation_for_builtin_bound(tcx, cause, builtin_bound, 0, source_ty) + util::predicates_for_generics(tcx, cause, 0, generic_bounds) } impl<'tcx,O> Obligation<'tcx,O> { @@ -311,6 +265,12 @@ impl<'tcx,O> Obligation<'tcx,O> { pub fn misc(span: Span, body_id: ast::NodeId, trait_ref: O) -> Obligation<'tcx, O> { Obligation::new(ObligationCause::misc(span, body_id), trait_ref) } + + pub fn with

(&self, value: P) -> Obligation<'tcx,P> { + Obligation { cause: self.cause.clone(), + recursion_depth: self.recursion_depth, + trait_ref: value } + } } impl<'tcx> Obligation<'tcx,Rc>> { @@ -417,7 +377,7 @@ impl VtableBuiltinData { } impl<'tcx> FulfillmentError<'tcx> { - fn new(obligation: TraitObligation<'tcx>, + fn new(obligation: PredicateObligation<'tcx>, code: FulfillmentErrorCode<'tcx>) -> FulfillmentError<'tcx> { diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 90fc663e8296..c55335ea190e 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -17,9 +17,8 @@ use self::Candidate::*; use self::BuiltinBoundConditions::*; use self::EvaluationResult::*; -use super::{TraitObligation, ObligationCause}; -use super::{SelectionError, Unimplemented, Overflow, - OutputTypeParameterMismatch}; +use super::{PredicateObligation, Obligation, TraitObligation, ObligationCause}; +use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch}; use super::{Selection}; use super::{SelectionResult}; use super::{VtableBuiltin, VtableImpl, VtableParam, VtableUnboxedClosure, VtableFnPointer}; @@ -191,6 +190,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + pub fn infcx(&self) -> &'cx InferCtxt<'cx, 'tcx> { + self.infcx + } + pub fn tcx(&self) -> &'cx ty::ctxt<'tcx> { self.infcx.tcx } @@ -225,29 +228,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - pub fn select_inherent_impl(&mut self, - impl_def_id: ast::DefId, - obligation_cause: ObligationCause<'tcx>, - obligation_self_ty: Ty<'tcx>) - -> SelectionResult<'tcx, VtableImplData<'tcx, TraitObligation<'tcx>>> - { - debug!("select_inherent_impl(impl_def_id={}, obligation_self_ty={})", - impl_def_id.repr(self.tcx()), - obligation_self_ty.repr(self.tcx())); - - match self.match_inherent_impl(impl_def_id, - obligation_cause, - obligation_self_ty) { - Ok(substs) => { - let vtable_impl = self.vtable_impl(impl_def_id, substs, obligation_cause, 0); - Ok(Some(vtable_impl)) - } - Err(()) => { - Err(Unimplemented) - } - } - } - /////////////////////////////////////////////////////////////////////////// // EVALUATION // @@ -260,15 +240,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Evaluates whether the obligation `obligation` can be satisfied (by any means). pub fn evaluate_obligation(&mut self, - obligation: &TraitObligation<'tcx>) + obligation: &PredicateObligation<'tcx>) -> bool { debug!("evaluate_obligation({})", obligation.repr(self.tcx())); - assert!(!obligation.trait_ref.has_escaping_regions()); - let stack = self.push_stack(None, obligation); - self.evaluate_stack(&stack).may_apply() + self.evaluate_predicate_recursively(None, obligation).may_apply() } fn evaluate_builtin_bound_recursively<'o>(&mut self, @@ -278,7 +256,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { -> EvaluationResult<'tcx> { let obligation = - util::obligation_for_builtin_bound( + util::predicate_for_builtin_bound( self.tcx(), previous_stack.obligation.cause, bound, @@ -287,7 +265,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match obligation { Ok(obligation) => { - self.evaluate_obligation_recursively(Some(previous_stack), &obligation) + self.evaluate_predicate_recursively(Some(previous_stack), &obligation) } Err(ErrorReported) => { EvaluatedToOk @@ -295,6 +273,36 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + fn evaluate_predicate_recursively<'o>(&mut self, + previous_stack: Option<&TraitObligationStack<'o, 'tcx>>, + obligation: &PredicateObligation<'tcx>) + -> EvaluationResult<'tcx> + { + debug!("evaluate_predicate_recursively({})", + obligation.repr(self.tcx())); + + match obligation.trait_ref { + ty::Predicate::Trait(ref t) => { + assert!(!t.has_escaping_regions()); + let obligation = obligation.with(t.clone()); + self.evaluate_obligation_recursively(previous_stack, &obligation) + } + + ty::Predicate::Equate(a, b) => { + match infer::can_mk_eqty(self.infcx, a, b) { + Ok(()) => EvaluatedToOk, + Err(_) => EvaluatedToErr(Unimplemented), + } + } + + ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => { + // we do not consider region relationships when + // evaluating trait matches + EvaluatedToOk + } + } + } + fn evaluate_obligation_recursively<'o>(&mut self, previous_stack: Option<&TraitObligationStack<'o, 'tcx>>, obligation: &TraitObligation<'tcx>) @@ -347,7 +355,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { stack.iter().skip(1).any( |prev| stack.skol_trait_ref.def_id == prev.skol_trait_ref.def_id)) { - debug!("evaluate_stack_intracrate({}) --> unbound argument, recursion --> ambiguous", + debug!("evaluate_stack({}) --> unbound argument, recursion --> ambiguous", stack.skol_trait_ref.repr(self.tcx())); return EvaluatedToAmbig; } @@ -376,7 +384,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .skip(1) // skip top-most frame .any(|prev| stack.skol_trait_ref == prev.skol_trait_ref) { - debug!("evaluate_stack_intracrate({}) --> recursive", + debug!("evaluate_stack({}) --> recursive", stack.skol_trait_ref.repr(self.tcx())); return EvaluatedToOk; } @@ -595,8 +603,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // common case, then we can use the global environment. // See the discussion in doc.rs for more details. if - !self.param_env.caller_obligations.is_empty() - && + !self.param_env.caller_bounds.is_empty() && cache_skol_trait_ref.input_types().iter().any( |&t| ty::type_has_ty_infer(t)) { @@ -690,8 +697,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.repr(self.tcx())); let caller_trait_refs: Vec> = - self.param_env.caller_obligations.iter() - .map(|o| o.trait_ref.clone()) + self.param_env.caller_bounds.predicates.iter() + .filter_map(|o| o.to_trait()) .collect(); let all_bounds = @@ -852,7 +859,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { { let mut result = EvaluatedToOk; for obligation in selection.iter_nested() { - match self.evaluate_obligation_recursively(stack, obligation) { + match self.evaluate_predicate_recursively(stack, obligation) { EvaluatedToErr(e) => { return EvaluatedToErr(e); } EvaluatedToAmbig => { result = EvaluatedToAmbig; } EvaluatedToOk => { } @@ -932,8 +939,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates: &mut CandidateSet<'tcx>) -> Result<(),SelectionError<'tcx>> { - match self.builtin_bound(bound, stack.obligation.self_ty()) { - Ok(If(_)) => { + match self.builtin_bound(bound, stack.obligation) { + Ok(If(..)) => { debug!("builtin_bound: bound={}", bound.repr(self.tcx())); candidates.vec.push(BuiltinCandidate(bound)); @@ -947,10 +954,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn builtin_bound(&mut self, bound: ty::BuiltinBound, - self_ty: Ty<'tcx>) + obligation: &TraitObligation<'tcx>) -> Result,SelectionError<'tcx>> { - let self_ty = self.infcx.shallow_resolve(self_ty); + let self_ty = self.infcx.shallow_resolve(obligation.trait_ref.self_ty()); return match self_ty.sty { ty::ty_infer(ty::IntVar(_)) | ty::ty_infer(ty::FloatVar(_)) | @@ -1023,8 +1030,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match bound { ty::BoundCopy => { match mutbl { - ast::MutMutable => Err(Unimplemented), // &mut T is affine - ast::MutImmutable => Ok(If(Vec::new())), // &T is copyable + ast::MutMutable => { + // &mut T is affine + Err(Unimplemented) + } + ast::MutImmutable => { + // &T is copyable, no matter what T is + Ok(If(Vec::new())) + } } } @@ -1083,10 +1096,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::BoundCopy => { match mutbl { // &mut T is affine and hence never `Copy` - ast::MutMutable => Err(Unimplemented), + ast::MutMutable => { + Err(Unimplemented) + } // &T is always copyable - ast::MutImmutable => Ok(If(Vec::new())), + ast::MutImmutable => { + Ok(If(Vec::new())) + } } } @@ -1122,8 +1139,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match bound { ty::BoundCopy => { match *len { - Some(_) => Ok(If(vec![element_ty])), // [T, ..n] is copy iff T is copy - None => Err(Unimplemented), // [T] is unsized and hence affine + Some(_) => { + // [T, ..n] is copy iff T is copy + Ok(If(vec![element_ty])) + } + None => { + // [T] is unsized and hence affine + Err(Unimplemented) + } } } @@ -1256,7 +1279,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Some(def_id) == tcx.lang_items.no_send_bound() || Some(def_id) == tcx.lang_items.managed_bound() { - return Err(Unimplemented); + return Err(Unimplemented) } } @@ -1274,7 +1297,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Some(def_id) == tcx.lang_items.no_sync_bound() || Some(def_id) == tcx.lang_items.managed_bound() { - return Err(Unimplemented); + return Err(Unimplemented) } else if Some(def_id) == tcx.lang_items.unsafe_type() { @@ -1361,13 +1384,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn confirm_builtin_candidate(&mut self, obligation: &TraitObligation<'tcx>, bound: ty::BuiltinBound) - -> Result>, + -> Result>, SelectionError<'tcx>> { debug!("confirm_builtin_candidate({})", obligation.repr(self.tcx())); - match try!(self.builtin_bound(bound, obligation.self_ty())) { + match try!(self.builtin_bound(bound, obligation)) { If(nested) => Ok(self.vtable_builtin_data(obligation, bound, nested)), AmbiguousBuiltin | ParameterBuiltin => { self.tcx().sess.span_bug( @@ -1382,29 +1405,44 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, bound: ty::BuiltinBound, nested: Vec>) - -> VtableBuiltinData> + -> VtableBuiltinData> { let obligations = nested.iter().map(|&t| { - util::obligation_for_builtin_bound( + util::predicate_for_builtin_bound( self.tcx(), obligation.cause, bound, obligation.recursion_depth + 1, t) }).collect::>(); - let obligations = match obligations { + let mut obligations = match obligations { Ok(o) => o, Err(ErrorReported) => Vec::new() }; + + // as a special case, `Send` requires `'static` + if bound == ty::BoundSend { + obligations.push(Obligation { + cause: obligation.cause, + recursion_depth: obligation.recursion_depth+1, + trait_ref: ty::Predicate::TypeOutlives(obligation.self_ty(), + ty::ReStatic) + }); + } + let obligations = VecPerParamSpace::new(obligations, Vec::new(), Vec::new(), Vec::new()); + + debug!("vtable_builtin_data: obligations={}", + obligations.repr(self.tcx())); + VtableBuiltinData { nested: obligations } } fn confirm_impl_candidate(&mut self, obligation: &TraitObligation<'tcx>, impl_def_id: ast::DefId) - -> Result>, + -> Result>, SelectionError<'tcx>> { debug!("confirm_impl_candidate({},{})", @@ -1414,6 +1452,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // First, create the substitutions by matching the impl again, // this time not in a probe. let substs = self.rematch_impl(impl_def_id, obligation); + debug!("confirm_impl_candidate substs={}", substs); Ok(self.vtable_impl(impl_def_id, substs, obligation.cause, obligation.recursion_depth + 1)) } @@ -1422,16 +1461,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { substs: Substs<'tcx>, cause: ObligationCause<'tcx>, recursion_depth: uint) - -> VtableImplData<'tcx, TraitObligation<'tcx>> + -> VtableImplData<'tcx, PredicateObligation<'tcx>> { - let impl_obligations = - self.impl_obligations(cause, - recursion_depth, - impl_def_id, - &substs); + let impl_predicates = + self.impl_predicates(cause, + recursion_depth, + impl_def_id, + &substs); VtableImplData { impl_def_id: impl_def_id, substs: substs, - nested: impl_obligations } + nested: impl_predicates } } fn confirm_fn_pointer_candidate(&mut self, @@ -1752,9 +1791,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match self.infcx.sub_trait_refs(false, origin, expected_trait_ref.clone(), - obligation_trait_ref) { + obligation_trait_ref.clone()) { Ok(()) => Ok(()), - Err(e) => Err(OutputTypeParameterMismatch(expected_trait_ref, e)) + Err(e) => Err(OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e)) } } @@ -1785,17 +1824,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - fn impl_obligations(&self, - cause: ObligationCause<'tcx>, - recursion_depth: uint, - impl_def_id: ast::DefId, - impl_substs: &Substs<'tcx>) - -> VecPerParamSpace> + fn impl_predicates(&self, + cause: ObligationCause<'tcx>, + recursion_depth: uint, + impl_def_id: ast::DefId, + impl_substs: &Substs<'tcx>) + -> VecPerParamSpace> { let impl_generics = ty::lookup_item_type(self.tcx(), impl_def_id).generics; let bounds = impl_generics.to_bounds(self.tcx(), impl_substs); - util::obligations_for_generics(self.tcx(), cause, recursion_depth, - &bounds, &impl_substs.types) + util::predicates_for_generics(self.tcx(), cause, recursion_depth, &bounds) } fn fn_family_trait_kind(&self, diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 360298feab79..a9532aceebb1 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -9,8 +9,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::subst; -use middle::subst::{ParamSpace, Substs, VecPerParamSpace, Subst}; +use middle::subst::{Subst, Substs, VecPerParamSpace}; use middle::infer::InferCtxt; use middle::ty::{mod, Ty}; use std::collections::HashSet; @@ -21,115 +20,130 @@ use syntax::codemap::Span; use util::common::ErrorReported; use util::ppaux::Repr; -use super::{Obligation, ObligationCause, TraitObligation, VtableImpl, - VtableParam, VtableParamData, VtableImplData}; +use super::{Obligation, ObligationCause, PredicateObligation, + VtableImpl, VtableParam, VtableParamData, VtableImplData}; /////////////////////////////////////////////////////////////////////////// -// Supertrait iterator +// Elaboration iterator -pub struct Supertraits<'cx, 'tcx:'cx> { +pub struct Elaborator<'cx, 'tcx:'cx> { tcx: &'cx ty::ctxt<'tcx>, - stack: Vec>, - visited: HashSet>>, + stack: Vec>, + visited: HashSet>, } -struct SupertraitEntry<'tcx> { +struct StackEntry<'tcx> { position: uint, - supertraits: Vec>>, + predicates: Vec>, } -pub fn supertraits<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, - trait_ref: Rc>) - -> Supertraits<'cx, 'tcx> +pub fn elaborate_trait_ref<'cx, 'tcx>( + tcx: &'cx ty::ctxt<'tcx>, + trait_ref: Rc>) + -> Elaborator<'cx, 'tcx> { - //! Returns an iterator over the trait reference `T` and all of its supertrait references. May - //! contain duplicates. In general the ordering is not defined. - //! - //! Example: - //! - //! ``` - //! trait Foo { ... } - //! trait Bar : Foo { ... } - //! trait Baz : Bar+Foo { ... } - //! ``` - //! - //! `supertraits(Baz)` yields `[Baz, Bar, Foo, Foo]` in some order. - - transitive_bounds(tcx, &[trait_ref]) + elaborate_predicates(tcx, vec![ty::Predicate::Trait(trait_ref)]) } -pub fn transitive_bounds<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, - bounds: &[Rc>]) - -> Supertraits<'cx, 'tcx> +pub fn elaborate_trait_refs<'cx, 'tcx>( + tcx: &'cx ty::ctxt<'tcx>, + trait_refs: &[Rc>]) + -> Elaborator<'cx, 'tcx> { - let bounds = Vec::from_fn(bounds.len(), |i| bounds[i].clone()); - - let visited: HashSet> = - bounds.iter() - .map(|b| (*b).clone()) - .collect(); - - let entry = SupertraitEntry { position: 0, supertraits: bounds }; - Supertraits { tcx: tcx, stack: vec![entry], visited: visited } + let predicates = trait_refs.iter() + .map(|trait_ref| ty::Predicate::Trait((*trait_ref).clone())) + .collect(); + elaborate_predicates(tcx, predicates) } -impl<'cx, 'tcx> Supertraits<'cx, 'tcx> { - fn push(&mut self, trait_ref: &ty::TraitRef<'tcx>) { - let ty::ParamBounds { builtin_bounds, mut trait_bounds, .. } = - ty::bounds_for_trait_ref(self.tcx, trait_ref); - for builtin_bound in builtin_bounds.iter() { - let bound_trait_ref = trait_ref_for_builtin_bound(self.tcx, - builtin_bound, - trait_ref.self_ty()); - match bound_trait_ref { - Ok(trait_ref) => { trait_bounds.push(trait_ref); } - Err(ErrorReported) => { } +pub fn elaborate_predicates<'cx, 'tcx>( + tcx: &'cx ty::ctxt<'tcx>, + predicates: Vec>) + -> Elaborator<'cx, 'tcx> +{ + let visited: HashSet> = + predicates.iter() + .map(|b| (*b).clone()) + .collect(); + + let entry = StackEntry { position: 0, predicates: predicates }; + Elaborator { tcx: tcx, stack: vec![entry], visited: visited } +} + +impl<'cx, 'tcx> Elaborator<'cx, 'tcx> { + fn push(&mut self, predicate: &ty::Predicate<'tcx>) { + match *predicate { + ty::Predicate::Trait(ref trait_ref) => { + let mut predicates = + ty::predicates_for_trait_ref(self.tcx, &**trait_ref); + + // Only keep those bounds that we haven't already + // seen. This is necessary to prevent infinite + // recursion in some cases. One common case is when + // people define `trait Sized { }` rather than `trait + // Sized for Sized? { }`. + predicates.retain(|r| self.visited.insert((*r).clone())); + + self.stack.push(StackEntry { position: 0, + predicates: predicates }); + } + ty::Predicate::Equate(..) => { + } + ty::Predicate::RegionOutlives(..) | + ty::Predicate::TypeOutlives(..) => { + // Currently, we do not "elaborate" predicates like + // `'a : 'b` or `T : 'a`. We could conceivably do + // more here. For example, + // + // &'a int : 'b + // + // implies that + // + // 'a : 'b + // + // and we could get even more if we took WF + // constraints into account. For example, + // + // &'a &'b int : 'c + // + // implies that + // + // 'b : 'a + // 'a : 'c } } - - // Only keep those bounds that we haven't already seen. This - // is necessary to prevent infinite recursion in some cases. - // One common case is when people define `trait Sized { }` - // rather than `trait Sized for Sized? { }`. - trait_bounds.retain(|r| self.visited.insert((*r).clone())); - - let entry = SupertraitEntry { position: 0, supertraits: trait_bounds }; - self.stack.push(entry); - } - - /// Returns the path taken through the trait supertraits to reach the current point. - pub fn indices(&self) -> Vec { - self.stack.iter().map(|e| e.position).collect() } } -impl<'cx, 'tcx> Iterator>> for Supertraits<'cx, 'tcx> { - fn next(&mut self) -> Option>> { +impl<'cx, 'tcx> Iterator> for Elaborator<'cx, 'tcx> { + fn next(&mut self) -> Option> { loop { // Extract next item from top-most stack frame, if any. - let next_trait = match self.stack.last_mut() { + let next_predicate = match self.stack.last_mut() { None => { // No more stack frames. Done. return None; } Some(entry) => { let p = entry.position; - if p < entry.supertraits.len() { - // Still more supertraits left in the top stack frame. + if p < entry.predicates.len() { + // Still more predicates left in the top stack frame. entry.position += 1; - let next_trait = entry.supertraits[p].clone(); - Some(next_trait) + let next_predicate = + entry.predicates[p].clone(); + + Some(next_predicate) } else { None } } }; - match next_trait { - Some(next_trait) => { - self.push(&*next_trait); - return Some(next_trait); + match next_predicate { + Some(next_predicate) => { + self.push(&next_predicate); + return Some(next_predicate); } None => { @@ -141,6 +155,50 @@ impl<'cx, 'tcx> Iterator>> for Supertraits<'cx, 'tcx> { } } +/////////////////////////////////////////////////////////////////////////// +// Supertrait iterator + +pub struct Supertraits<'cx, 'tcx:'cx> { + elaborator: Elaborator<'cx, 'tcx>, +} + +pub fn supertraits<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, + trait_ref: Rc>) + -> Supertraits<'cx, 'tcx> +{ + let elaborator = elaborate_trait_ref(tcx, trait_ref); + Supertraits { elaborator: elaborator } +} + +pub fn transitive_bounds<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, + bounds: &[Rc>]) + -> Supertraits<'cx, 'tcx> +{ + let elaborator = elaborate_trait_refs(tcx, bounds); + Supertraits { elaborator: elaborator } +} + +impl<'cx, 'tcx> Iterator>> for Supertraits<'cx, 'tcx> { + fn next(&mut self) -> Option>> { + loop { + match self.elaborator.next() { + None => { + return None; + } + Some(ty::Predicate::Trait(trait_ref)) => { + return Some(trait_ref); + } + Some(ty::Predicate::Equate(..)) | + Some(ty::Predicate::RegionOutlives(..)) | + Some(ty::Predicate::TypeOutlives(..)) => { + } + } + } + } +} + +/////////////////////////////////////////////////////////////////////////// + // determine the `self` type, using fresh variables for all variables // declared on the impl declaration e.g., `impl for Box<[(A,B)]>` // would return ($0, $1) where $0 and $1 are freshly instantiated type @@ -179,64 +237,20 @@ impl<'tcx> fmt::Show for VtableParamData<'tcx> { } /// See `super::obligations_for_generics` -pub fn obligations_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>, - cause: ObligationCause<'tcx>, - recursion_depth: uint, - generic_bounds: &ty::GenericBounds<'tcx>, - type_substs: &VecPerParamSpace>) - -> VecPerParamSpace> +pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>, + cause: ObligationCause<'tcx>, + recursion_depth: uint, + generic_bounds: &ty::GenericBounds<'tcx>) + -> VecPerParamSpace> { + debug!("predicates_for_generics(generic_bounds={})", + generic_bounds.repr(tcx)); - debug!("obligations_for_generics(generic_bounds={}, type_substs={})", - generic_bounds.repr(tcx), type_substs.repr(tcx)); - - let mut obligations = VecPerParamSpace::empty(); - - for (space, index, bounds) in generic_bounds.types.iter_enumerated() { - push_obligations_for_param_bounds(tcx, - cause, - recursion_depth, - space, - index, - bounds, - type_substs, - &mut obligations); - } - - debug!("obligations() ==> {}", obligations.repr(tcx)); - - return obligations; -} - -fn push_obligations_for_param_bounds<'tcx>( - tcx: &ty::ctxt<'tcx>, - cause: ObligationCause<'tcx>, - recursion_depth: uint, - space: subst::ParamSpace, - index: uint, - param_bounds: &ty::ParamBounds<'tcx>, - param_type_substs: &VecPerParamSpace>, - obligations: &mut VecPerParamSpace>) -{ - let param_ty = *param_type_substs.get(space, index); - for builtin_bound in param_bounds.builtin_bounds.iter() { - let obligation = obligation_for_builtin_bound(tcx, - cause, - builtin_bound, - recursion_depth, - param_ty); - if let Ok(ob) = obligation { - obligations.push(space, ob); - } - } - - for bound_trait_ref in param_bounds.trait_bounds.iter() { - obligations.push( - space, - Obligation { cause: cause, - recursion_depth: recursion_depth, - trait_ref: (*bound_trait_ref).clone() }); - } + generic_bounds.predicates.map(|predicate| { + Obligation { cause: cause, + recursion_depth: recursion_depth, + trait_ref: predicate.clone() } + }) } pub fn trait_ref_for_builtin_bound<'tcx>( @@ -259,19 +273,19 @@ pub fn trait_ref_for_builtin_bound<'tcx>( } } -pub fn obligation_for_builtin_bound<'tcx>( +pub fn predicate_for_builtin_bound<'tcx>( tcx: &ty::ctxt<'tcx>, cause: ObligationCause<'tcx>, builtin_bound: ty::BuiltinBound, recursion_depth: uint, param_ty: Ty<'tcx>) - -> Result, ErrorReported> + -> Result, 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 + trait_ref: ty::Predicate::Trait(trait_ref), }) } @@ -358,10 +372,11 @@ impl<'tcx> Repr<'tcx> for super::SelectionError<'tcx> { super::Unimplemented => format!("Unimplemented"), - super::OutputTypeParameterMismatch(ref t, ref e) => - format!("OutputTypeParameterMismatch({}, {})", - t.repr(tcx), - e.repr(tcx)), + super::OutputTypeParameterMismatch(ref a, ref b, ref c) => + format!("OutputTypeParameterMismatch({},{},{})", + a.repr(tcx), + b.repr(tcx), + c.repr(tcx)), } } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index ef8e3f3b2d7f..ca226e2ca3fa 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -44,6 +44,7 @@ use back::svh::Svh; use session::Session; use lint; use metadata::csearch; +use middle; use middle::const_eval; use middle::def; use middle::dependency_format; @@ -60,13 +61,14 @@ use middle::traits::ObligationCause; use middle::traits; use middle::ty; use middle::ty_fold::{mod, TypeFoldable, TypeFolder, HigherRankedFoldable}; -use middle; use util::ppaux::{note_and_explain_region, bound_region_ptr_to_string}; use util::ppaux::{trait_store_to_string, ty_to_string}; use util::ppaux::{Repr, UserString}; -use util::common::{indenter, memoized}; +use util::common::{indenter, memoized, ErrorReported}; use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet}; use util::nodemap::{FnvHashMap, FnvHashSet}; + +use arena::TypedArena; use std::borrow::BorrowFrom; use std::cell::{Cell, RefCell}; use std::cmp; @@ -75,8 +77,8 @@ use std::hash::{Hash, sip, Writer}; use std::mem; use std::ops; use std::rc::Rc; +use std::collections::enum_set::{EnumSet, CLike}; use std::collections::hash_map::{HashMap, Occupied, Vacant}; -use arena::TypedArena; use syntax::abi; use syntax::ast::{CrateNum, DefId, DUMMY_NODE_ID, FnStyle, Ident, ItemTrait, LOCAL_CRATE}; use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId}; @@ -87,7 +89,6 @@ use syntax::attr::{mod, AttrMetaMethods}; use syntax::codemap::{DUMMY_SP, Span}; use syntax::parse::token::{mod, InternedString}; use syntax::{ast, ast_map}; -use std::collections::enum_set::{EnumSet, CLike}; pub type Disr = u64; @@ -1613,8 +1614,14 @@ pub struct RegionParameterDef { pub bounds: Vec, } -/// Information about the formal type/lifetime parameters associated with an -/// item or method. Analogous to ast::Generics. +impl RegionParameterDef { + pub fn to_early_bound_region(&self) -> ty::Region { + ty::ReEarlyBound(self.def_id.node, self.space, self.index, self.name) + } +} + +/// Information about the formal type/lifetime parameters associated +/// with an item or method. Analogous to ast::Generics. #[deriving(Clone, Show)] pub struct Generics<'tcx> { pub types: VecPerParamSpace>, @@ -1622,21 +1629,6 @@ pub struct Generics<'tcx> { pub predicates: VecPerParamSpace>, } -#[deriving(Clone, Show)] -pub enum Predicate<'tcx> { - /// where Foo : Bar - Trait(Rc>), - - /// where Foo == Bar - Equate(Ty<'tcx>, Ty<'tcx>), - - /// where 'a : 'b - RegionOutlives(Region, Region), - - /// where T : 'a - TypeOutlives(Ty<'tcx>, Region), -} - impl<'tcx> Generics<'tcx> { pub fn empty() -> Generics<'tcx> { Generics { @@ -1657,8 +1649,47 @@ impl<'tcx> Generics<'tcx> { pub fn to_bounds(&self, tcx: &ty::ctxt<'tcx>, substs: &Substs<'tcx>) -> GenericBounds<'tcx> { GenericBounds { - types: self.types.map(|d| d.bounds.subst(tcx, substs)), - regions: self.regions.map(|d| d.bounds.subst(tcx, substs)), + predicates: self.predicates.subst(tcx, substs), + } + } +} + +#[deriving(Clone, PartialEq, Eq, Hash, Show)] +pub enum Predicate<'tcx> { + /// where Foo : Bar + Trait(Rc>), + + /// where Foo == Bar + Equate(Ty<'tcx>, Ty<'tcx>), + + /// where 'a : 'b + RegionOutlives(Region, Region), + + /// where T : 'a + TypeOutlives(Ty<'tcx>, Region), +} + +impl<'tcx> Predicate<'tcx> { + pub fn has_escaping_regions(&self) -> bool { + match *self { + Predicate::Trait(ref trait_ref) => trait_ref.has_escaping_regions(), + Predicate::Equate(a, b) => (ty::type_has_escaping_regions(a) || + ty::type_has_escaping_regions(b)), + Predicate::RegionOutlives(a, b) => a.escapes_depth(0) || b.escapes_depth(0), + Predicate::TypeOutlives(a, b) => ty::type_has_escaping_regions(a) || b.escapes_depth(0), + } + } + + pub fn to_trait(&self) -> Option>> { + match *self { + Predicate::Trait(ref t) => { + Some(t.clone()) + } + Predicate::Equate(..) | + Predicate::RegionOutlives(..) | + Predicate::TypeOutlives(..) => { + None + } } } } @@ -1684,19 +1715,20 @@ impl<'tcx> Generics<'tcx> { /// [uint:Bar]]`. #[deriving(Clone, Show)] pub struct GenericBounds<'tcx> { - pub types: VecPerParamSpace>, - pub regions: VecPerParamSpace>, + pub predicates: VecPerParamSpace>, } impl<'tcx> GenericBounds<'tcx> { pub fn empty() -> GenericBounds<'tcx> { - GenericBounds { types: VecPerParamSpace::empty(), - regions: VecPerParamSpace::empty() } + GenericBounds { predicates: VecPerParamSpace::empty() } } pub fn has_escaping_regions(&self) -> bool { - self.types.any(|pb| pb.trait_bounds.iter().any(|tr| tr.has_escaping_regions())) || - self.regions.any(|rs| rs.iter().any(|r| r.escapes_depth(0))) + self.predicates.any(|p| p.has_escaping_regions()) + } + + pub fn is_empty(&self) -> bool { + self.predicates.is_empty() } } @@ -1747,9 +1779,6 @@ pub struct ParameterEnvironment<'tcx> { /// parameters in the same way, this only has an effect on regions. pub free_substs: Substs<'tcx>, - /// Bounds on the various type parameters - pub bounds: VecPerParamSpace>, - /// Each type parameter has an implicit region bound that /// indicates it must outlive at least the function body (the user /// may specify stronger requirements). This field indicates the @@ -1759,10 +1788,7 @@ pub struct ParameterEnvironment<'tcx> { /// Obligations that the caller must satisfy. This is basically /// the set of bounds on the in-scope type parameters, translated /// into Obligations. - /// - /// Note: This effectively *duplicates* the `bounds` array for - /// now. - pub caller_obligations: VecPerParamSpace>, + pub caller_bounds: ty::GenericBounds<'tcx>, /// Caches the results of trait selection. This cache is used /// for things that have to do with the parameters in scope. @@ -3160,7 +3186,8 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { pub fn type_moves_by_default<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>, param_env: &ParameterEnvironment<'tcx>) - -> bool { + -> bool +{ if !type_has_params(ty) && !type_has_self(ty) { match cx.type_moves_by_default_cache.borrow().get(&ty) { None => {} @@ -3181,20 +3208,20 @@ pub fn type_moves_by_default<'tcx>(cx: &ctxt<'tcx>, // (there shouldn't really be any anyhow) let cause = ObligationCause::misc(DUMMY_SP, DUMMY_NODE_ID); - let obligation = traits::obligation_for_builtin_bound( - cx, - cause, - ty, - ty::BoundCopy).unwrap(); - fulfill_cx.register_obligation(cx, obligation); - let result = !fulfill_cx.select_all_or_error(&infcx, - param_env, - cx).is_ok(); - cx.type_moves_by_default_cache.borrow_mut().insert(ty, result); + fulfill_cx.register_builtin_bound(cx, ty, ty::BoundCopy, cause); + + // Note: we only assuming something is `Copy` if we can + // *definitively* show that it implements `Copy`. Otherwise, + // assume it is move; linear is always ok. + let is_copy = fulfill_cx.select_all_or_error(&infcx, param_env, cx).is_ok(); + let is_move = !is_copy; + debug!("determined whether {} moves by default: {}", ty_to_string(cx, ty), - result); - result + is_move); + + cx.type_moves_by_default_cache.borrow_mut().insert(ty, is_move); + is_move } pub fn is_ffi_safe<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> bool { @@ -5006,9 +5033,9 @@ pub fn lookup_trait_def<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId) /// Given a reference to a trait, returns the bounds declared on the /// trait, with appropriate substitutions applied. -pub fn bounds_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>, - trait_ref: &TraitRef<'tcx>) - -> ty::ParamBounds<'tcx> +pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>, + trait_ref: &TraitRef<'tcx>) + -> Vec> { let trait_def = lookup_trait_def(tcx, trait_ref.def_id); @@ -5099,11 +5126,39 @@ pub fn bounds_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>, let builtin_bounds = trait_def.bounds.builtin_bounds.subst(tcx, &trait_ref.substs); - ty::ParamBounds { + let bounds = ty::ParamBounds { trait_bounds: trait_bounds, region_bounds: region_bounds, builtin_bounds: builtin_bounds, + }; + + predicates(tcx, trait_ref.self_ty(), &bounds) +} + +pub fn predicates<'tcx>( + tcx: &ctxt<'tcx>, + param_ty: Ty<'tcx>, + bounds: &ParamBounds<'tcx>) + -> Vec> +{ + let mut vec = Vec::new(); + + for builtin_bound in bounds.builtin_bounds.iter() { + match traits::trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty) { + Ok(trait_ref) => { vec.push(Predicate::Trait(trait_ref)); } + Err(ErrorReported) => { } + } } + + for ®ion_bound in bounds.region_bounds.iter() { + vec.push(Predicate::TypeOutlives(param_ty, region_bound)); + } + + for bound_trait_ref in bounds.trait_bounds.iter() { + vec.push(Predicate::Trait((*bound_trait_ref).clone())); + } + + vec } /// Iterate over attributes of a definition. @@ -5461,56 +5516,62 @@ pub fn each_bound_trait_and_supertraits<'tcx>(tcx: &ctxt<'tcx>, return true; } +pub fn object_region_bounds<'tcx>(tcx: &ctxt<'tcx>, + opt_principal: Option<&TraitRef<'tcx>>, // None for boxed closures + others: BuiltinBounds) + -> Vec +{ + // Since we don't actually *know* the self type for an object, + // this "open(err)" serves as a kind of dummy standin -- basically + // a skolemized type. + let open_ty = ty::mk_infer(tcx, SkolemizedTy(0)); + + let opt_trait_ref = opt_principal.map_or(Vec::new(), |principal| { + let substs = principal.substs.with_self_ty(open_ty); + vec!(Rc::new(ty::TraitRef::new(principal.def_id, substs))) + }); + + let param_bounds = ty::ParamBounds { + region_bounds: Vec::new(), + builtin_bounds: others, + trait_bounds: opt_trait_ref, + }; + + let predicates = ty::predicates(tcx, open_ty, ¶m_bounds); + ty::required_region_bounds(tcx, open_ty, predicates) +} + /// Given a type which must meet the builtin bounds and trait bounds, returns a set of lifetimes /// which the type must outlive. /// /// Requires that trait definitions have been processed. pub fn required_region_bounds<'tcx>(tcx: &ctxt<'tcx>, - region_bounds: &[ty::Region], - builtin_bounds: BuiltinBounds, - trait_bounds: &[Rc>]) + param_ty: Ty<'tcx>, + predicates: Vec>) -> Vec { - let mut all_bounds = Vec::new(); + debug!("required_region_bounds(param_ty={}, predicates={})", + param_ty.repr(tcx), + predicates.repr(tcx)); - debug!("required_region_bounds(builtin_bounds={}, trait_bounds={})", - builtin_bounds.repr(tcx), - trait_bounds.repr(tcx)); - - all_bounds.push_all(region_bounds); - - push_region_bounds(&[], - builtin_bounds, - &mut all_bounds); - - debug!("from builtin bounds: all_bounds={}", all_bounds.repr(tcx)); - - each_bound_trait_and_supertraits( - tcx, - trait_bounds, - |trait_ref| { - let bounds = ty::bounds_for_trait_ref(tcx, &*trait_ref); - push_region_bounds(bounds.region_bounds.as_slice(), - bounds.builtin_bounds, - &mut all_bounds); - debug!("from {}: bounds={} all_bounds={}", - trait_ref.repr(tcx), - bounds.repr(tcx), - all_bounds.repr(tcx)); - true - }); - - return all_bounds; - - fn push_region_bounds(region_bounds: &[ty::Region], - builtin_bounds: ty::BuiltinBounds, - all_bounds: &mut Vec) { - all_bounds.push_all(region_bounds.as_slice()); - - if builtin_bounds.contains(&ty::BoundSend) { - all_bounds.push(ty::ReStatic); - } - } + traits::elaborate_predicates(tcx, predicates) + .filter_map(|predicate| { + match predicate { + ty::Predicate::Trait(..) | + ty::Predicate::Equate(..) | + ty::Predicate::RegionOutlives(..) => { + None + } + ty::Predicate::TypeOutlives(t, r) => { + if t == param_ty { + Some(r) + } else { + None + } + } + } + }) + .collect() } pub fn get_tydesc_ty<'tcx>(tcx: &ctxt<'tcx>) -> Result, String> { @@ -5860,8 +5921,7 @@ impl Variance { /// are no free type/lifetime parameters in scope. pub fn empty_parameter_environment<'tcx>() -> ParameterEnvironment<'tcx> { ty::ParameterEnvironment { free_substs: Substs::empty(), - bounds: VecPerParamSpace::empty(), - caller_obligations: VecPerParamSpace::empty(), + caller_bounds: GenericBounds::empty(), implicit_region_bound: ty::ReEmpty, selection_cache: traits::SelectionCache::new(), } } @@ -5906,11 +5966,6 @@ pub fn construct_parameter_environment<'tcx>( let bounds = generics.to_bounds(tcx, &free_substs); let bounds = liberate_late_bound_regions(tcx, free_id_scope, &bind(bounds)).value; - let obligations = traits::obligations_for_generics(tcx, - traits::ObligationCause::dummy(), - &bounds, - &free_substs.types); - let type_bounds = bounds.types.subst(tcx, &free_substs); // // Compute region bounds. For now, these relations are stored in a @@ -5918,23 +5973,17 @@ pub fn construct_parameter_environment<'tcx>( // crazy about this scheme, but it's convenient, at least. // - for &space in subst::ParamSpace::all().iter() { - record_region_bounds(tcx, space, &free_substs, bounds.regions.get_slice(space)); - } + record_region_bounds(tcx, &bounds); - - debug!("construct_parameter_environment: free_id={} free_subst={} \ - obligations={} type_bounds={}", + debug!("construct_parameter_environment: free_id={} free_subst={} bounds={}", free_id, free_substs.repr(tcx), - obligations.repr(tcx), - type_bounds.repr(tcx)); + bounds.repr(tcx)); return ty::ParameterEnvironment { free_substs: free_substs, - bounds: bounds.types, implicit_region_bound: ty::ReScope(free_id_scope), - caller_obligations: obligations, + caller_bounds: bounds, selection_cache: traits::SelectionCache::new(), }; @@ -5963,31 +6012,24 @@ pub fn construct_parameter_environment<'tcx>( } } - fn record_region_bounds<'tcx>(tcx: &ty::ctxt<'tcx>, - space: subst::ParamSpace, - free_substs: &Substs<'tcx>, - bound_sets: &[Vec]) { - for (subst_region, bound_set) in - free_substs.regions().get_slice(space).iter().zip( - bound_sets.iter()) - { - // For each region parameter 'subst... - for bound_region in bound_set.iter() { - // Which is declared with a bound like 'subst:'bound... - match (subst_region, bound_region) { - (&ty::ReFree(subst_fr), &ty::ReFree(bound_fr)) => { - // Record that 'subst outlives 'bound. Or, put - // another way, 'bound <= 'subst. - tcx.region_maps.relate_free_regions(bound_fr, subst_fr); - }, - _ => { - // All named regions are instantiated with free regions. - tcx.sess.bug( - format!("record_region_bounds: \ - non free region: {} / {}", - subst_region.repr(tcx), - bound_region.repr(tcx)).as_slice()); - } + fn record_region_bounds<'tcx>(tcx: &ty::ctxt<'tcx>, bounds: &GenericBounds<'tcx>) { + debug!("record_region_bounds(bounds={})", bounds.repr(tcx)); + + for predicate in bounds.predicates.iter() { + match *predicate { + Predicate::Trait(..) | Predicate::Equate(..) | Predicate::TypeOutlives(..) => { + // No region bounds here + } + Predicate::RegionOutlives(ty::ReFree(fr_a), ty::ReFree(fr_b)) => { + // Record that `'a:'b`. Or, put another way, `'b <= 'a`. + tcx.region_maps.relate_free_regions(fr_b, fr_a); + } + Predicate::RegionOutlives(r_a, r_b) => { + // All named regions are instantiated with free regions. + tcx.sess.bug( + format!("record_region_bounds: non free region: {} / {}", + r_a.repr(tcx), + r_b.repr(tcx)).as_slice()); } } } @@ -6306,6 +6348,17 @@ impl<'tcx> Repr<'tcx> for TyTrait<'tcx> { } } +impl<'tcx> Repr<'tcx> for ty::Predicate<'tcx> { + fn repr(&self, tcx: &ctxt<'tcx>) -> String { + match *self { + Predicate::Trait(ref a) => a.repr(tcx), + Predicate::Equate(a, b) => format!("Equate({},{})", a.repr(tcx), b.repr(tcx)), + Predicate::RegionOutlives(a, b) => format!("Outlives({}:{})", a.repr(tcx), b.repr(tcx)), + Predicate::TypeOutlives(a, b) => format!("Outlives({}:{})", a.repr(tcx), b.repr(tcx)), + } + } +} + impl<'tcx> Repr<'tcx> for vtable_origin<'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { match *self { diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 87467ba064a2..8b54a46bfb93 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -425,8 +425,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { impl<'tcx> TypeFoldable<'tcx> for ty::GenericBounds<'tcx> { fn fold_with>(&self, folder: &mut F) -> ty::GenericBounds<'tcx> { ty::GenericBounds { - types: self.types.fold_with(folder), - regions: self.regions.fold_with(folder), + predicates: self.predicates.fold_with(folder), } } } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 3895a1137267..7a14ed9cca8c 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -914,17 +914,17 @@ impl<'tcx> Repr<'tcx> for ty::Polytype<'tcx> { impl<'tcx> Repr<'tcx> for ty::Generics<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { - format!("Generics(types: {}, regions: {})", + format!("Generics(types: {}, regions: {}, predicates: {})", self.types.repr(tcx), - self.regions.repr(tcx)) + self.regions.repr(tcx), + self.predicates.repr(tcx)) } } impl<'tcx> Repr<'tcx> for ty::GenericBounds<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { - format!("GenericBounds(types: {}, regions: {})", - self.types.repr(tcx), - self.regions.repr(tcx)) + format!("GenericBounds({})", + self.predicates.repr(tcx)) } } diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index da6aa84cfa11..83938fa33570 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -827,8 +827,8 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // fully bound. It could be a slight optimization to stop // iterating early. let mut fulfill_cx = traits::FulfillmentContext::new(); - let vtable = selection.map_move_nested(|obligation| { - fulfill_cx.register_obligation(tcx, obligation); + let vtable = selection.map_move_nested(|predicate| { + fulfill_cx.register_predicate(infcx.tcx, predicate); }); match fulfill_cx.select_all_or_error(&infcx, ¶m_env, tcx) { Ok(()) => { } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index e4edfadb3aaa..4ad0d2b8293e 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -800,7 +800,7 @@ fn trait_ref_to_object_type<'tcx,AC,RS>(this: &AC, let existential_bounds = conv_existential_bounds(this, rscope, span, - &[Rc::new(trait_ref.clone())], + Some(&trait_ref), bounds); let result = ty::mk_trait(this.tcx(), trait_ref, existential_bounds); @@ -918,7 +918,7 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( let bounds = conv_existential_bounds(this, rscope, ast_ty.span, - [].as_slice(), + None, f.bounds.as_slice()); let fn_decl = ty_of_closure(this, f.fn_style, @@ -935,9 +935,10 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( ast::TyProc(ref f) => { // Use corresponding trait store to figure out default bounds // if none were specified. - let bounds = conv_existential_bounds(this, rscope, + let bounds = conv_existential_bounds(this, + rscope, ast_ty.span, - [].as_slice(), + None, f.bounds.as_slice()); let fn_decl = ty_of_closure(this, @@ -1370,7 +1371,7 @@ pub fn conv_existential_bounds<'tcx, AC: AstConv<'tcx>, RS:RegionScope>( this: &AC, rscope: &RS, span: Span, - main_trait_refs: &[Rc>], + principal_trait_ref: Option<&ty::TraitRef<'tcx>>, // None for boxed closures ast_bounds: &[ast::TyParamBound]) -> ty::ExistentialBounds { @@ -1381,7 +1382,7 @@ pub fn conv_existential_bounds<'tcx, AC: AstConv<'tcx>, RS:RegionScope>( partition_bounds(this.tcx(), span, ast_bound_refs.as_slice()); conv_existential_bounds_from_partitioned_bounds( - this, rscope, span, main_trait_refs, partitioned_bounds) + this, rscope, span, principal_trait_ref, partitioned_bounds) } fn conv_ty_poly_trait_ref<'tcx, AC, RS>( @@ -1411,11 +1412,12 @@ fn conv_ty_poly_trait_ref<'tcx, AC, RS>( } }; - let bounds = conv_existential_bounds_from_partitioned_bounds(this, - rscope, - span, - main_trait_bound.as_slice(), - partitioned_bounds); + let bounds = + conv_existential_bounds_from_partitioned_bounds(this, + rscope, + span, + main_trait_bound.as_ref().map(|tr| &**tr), + partitioned_bounds); match main_trait_bound { None => ty::mk_err(), @@ -1427,7 +1429,7 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx, AC, RS>( this: &AC, rscope: &RS, span: Span, - main_trait_refs: &[Rc>], + principal_trait_ref: Option<&ty::TraitRef<'tcx>>, // None for boxed closures partitioned_bounds: PartitionedBounds) -> ty::ExistentialBounds where AC: AstConv<'tcx>, RS:RegionScope @@ -1445,28 +1447,12 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx, AC, RS>( as closure or object bounds").as_slice()); } - // The "main trait refs", rather annoyingly, have no type - // specified for the `Self` parameter of the trait. The reason for - // this is that they are, after all, *existential* types, and - // hence that type is unknown. However, leaving this type missing - // causes the substitution code to go all awry when walking the - // bounds, so here we clone those trait refs and insert ty::err as - // the self type. Perhaps we should do this more generally, it'd - // be convenient (or perhaps something else, i.e., ty::erased). - let main_trait_refs: Vec> = - main_trait_refs.iter() - .map(|t| - Rc::new(ty::TraitRef { - def_id: t.def_id, - substs: t.substs.with_self_ty(ty::mk_err()) })) - .collect(); - let region_bound = compute_region_bound(this, rscope, span, - builtin_bounds, region_bounds.as_slice(), - main_trait_refs.as_slice()); + principal_trait_ref, + builtin_bounds); ty::ExistentialBounds { region_bound: region_bound, @@ -1478,33 +1464,35 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx, AC, RS>( /// (if any) we can use to summarize this type. The basic idea is that we will use the bound the /// user provided, if they provided one, and otherwise search the supertypes of trait bounds for /// region bounds. It may be that we can derive no bound at all, in which case we return `None`. -pub fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>, - span: Span, - builtin_bounds: ty::BuiltinBounds, - region_bounds: &[&ast::Lifetime], - trait_bounds: &[Rc>]) - -> Option +fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>, + span: Span, + explicit_region_bounds: &[&ast::Lifetime], + principal_trait_ref: Option<&ty::TraitRef<'tcx>>, + builtin_bounds: ty::BuiltinBounds) + -> Option { - if region_bounds.len() > 1 { + debug!("compute_opt_region_bound(explicit_region_bounds={}, \ + principal_trait_ref={}, builtin_bounds={})", + explicit_region_bounds, + principal_trait_ref.repr(tcx), + builtin_bounds.repr(tcx)); + + if explicit_region_bounds.len() > 1 { tcx.sess.span_err( - region_bounds[1].span, + explicit_region_bounds[1].span, format!("only a single explicit lifetime bound is permitted").as_slice()); } - if region_bounds.len() != 0 { + if explicit_region_bounds.len() != 0 { // Explicitly specified region bound. Use that. - let r = region_bounds[0]; + let r = explicit_region_bounds[0]; return Some(ast_region_to_region(tcx, r)); } // No explicit region bound specified. Therefore, examine trait // bounds and see if we can derive region bounds from those. let derived_region_bounds = - ty::required_region_bounds( - tcx, - &[], - builtin_bounds, - trait_bounds); + ty::object_region_bounds(tcx, principal_trait_ref, builtin_bounds); // If there are no derived region bounds, then report back that we // can find no region bound. @@ -1538,13 +1526,13 @@ fn compute_region_bound<'tcx, AC: AstConv<'tcx>, RS:RegionScope>( this: &AC, rscope: &RS, span: Span, - builtin_bounds: ty::BuiltinBounds, region_bounds: &[&ast::Lifetime], - trait_bounds: &[Rc>]) + principal_trait_ref: Option<&ty::TraitRef<'tcx>>, // None for closures + builtin_bounds: ty::BuiltinBounds) -> ty::Region { - match compute_opt_region_bound(this.tcx(), span, builtin_bounds, - region_bounds, trait_bounds) { + match compute_opt_region_bound(this.tcx(), span, region_bounds, + principal_trait_ref, builtin_bounds) { Some(r) => r, None => { match rscope.default_region_bound(span) { diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 34030ae4493a..2b34b4a55b7c 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -232,16 +232,24 @@ fn deduce_unboxed_closure_expectations_from_obligations<'a,'tcx>( -> Option<(ty::FnSig<'tcx>, ty::UnboxedClosureKind)> { // Here `expected_ty` is known to be a type inference variable. - for obligation in fcx.inh.fulfillment_cx.borrow().pending_trait_obligations().iter() { - let obligation_self_ty = fcx.infcx().shallow_resolve(obligation.self_ty()); - match obligation_self_ty.sty { - ty::ty_infer(ty::TyVar(v)) if expected_vid == v => { } - _ => { continue; } - } + for obligation in fcx.inh.fulfillment_cx.borrow().pending_obligations().iter() { + match obligation.trait_ref { + ty::Predicate::Trait(ref trait_ref) => { + let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty()); + match self_ty.sty { + ty::ty_infer(ty::TyVar(v)) if expected_vid == v => { } + _ => { continue; } + } - match deduce_unboxed_closure_expectations_from_trait_ref(fcx, &*obligation.trait_ref) { - Some(e) => { return Some(e); } - None => { } + match deduce_unboxed_closure_expectations_from_trait_ref(fcx, &**trait_ref) { + Some(e) => { return Some(e); } + None => { } + } + } + ty::Predicate::Equate(..) | + ty::Predicate::RegionOutlives(..) | + ty::Predicate::TypeOutlives(..) => { + } } } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 7b43b97a4bb3..bf1f2c0ce809 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -463,7 +463,6 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { self.fcx.add_obligations_for_parameters( traits::ObligationCause::misc(self.span, self.fcx.body_id), - method_bounds_substs, method_bounds); self.fcx.add_default_region_param_bounds( diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 1ab76740962b..d081b97b71ad 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -169,7 +169,9 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, substs)); // Construct an obligation - let obligation = traits::Obligation::misc(span, fcx.body_id, trait_ref.clone()); + let obligation = traits::Obligation::misc(span, + fcx.body_id, + ty::Predicate::Trait(trait_ref.clone())); // Now we want to know if this can be matched let mut selcx = traits::SelectionContext::new(fcx.infcx(), @@ -187,6 +189,9 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, assert_eq!(method_ty.generics.types.len(subst::FnSpace), 0); assert_eq!(method_ty.generics.regions.len(subst::FnSpace), 0); + debug!("lookup_in_trait_adjusted: method_num={} method_ty={}", + method_num, method_ty.repr(fcx.tcx())); + // Substitute the trait parameters into the method type and // instantiate late-bound regions to get the actual method type. // @@ -204,7 +209,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, abi: bare_fn_ty.abi.clone(), }); - debug!("matched method fty={} obligation={}", + debug!("lookup_in_trait_adjusted: matched method fty={} obligation={}", fty.repr(fcx.tcx()), obligation.repr(fcx.tcx())); @@ -220,7 +225,6 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, assert!(!method_bounds.has_escaping_regions()); fcx.add_obligations_for_parameters( traits::ObligationCause::misc(span, fcx.body_id), - &trait_ref.substs, &method_bounds); // FIXME(#18653) -- Try to resolve obligations, giving us more @@ -233,8 +237,8 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, None => { } Some(self_expr) => { - debug!("inserting adjustment if needed (self-id = {}, \ - base adjustment = {}, explicit self = {})", + debug!("lookup_in_trait_adjusted: inserting adjustment if needed \ + (self-id={}, base adjustment={}, explicit_self={})", self_expr.id, autoderefref, method_ty.explicit_self); match method_ty.explicit_self { diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 3d7590db748e..f0f527f66735 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -353,11 +353,27 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { param_ty: ty::ParamTy) { // FIXME -- Do we want to commit to this behavior for param bounds? - let ty::ParamTy { space, idx: index, .. } = param_ty; - let bounds = - self.fcx.inh.param_env.bounds.get(space, index).trait_bounds - .as_slice(); - self.elaborate_bounds(bounds, true, |this, trait_ref, m, method_num| { + let bounds: Vec<_> = + self.fcx.inh.param_env.caller_bounds.predicates + .iter() + .filter_map(|predicate| { + match *predicate { + ty::Predicate::Trait(ref trait_ref) => { + match trait_ref.self_ty().sty { + ty::ty_param(ref p) if *p == param_ty => Some(trait_ref.clone()), + _ => None + } + } + ty::Predicate::Equate(..) | + ty::Predicate::RegionOutlives(..) | + ty::Predicate::TypeOutlives(..) => { + None + } + } + }) + .collect(); + + self.elaborate_bounds(bounds.as_slice(), true, |this, trait_ref, m, method_num| { let xform_self_ty = this.xform_self_ty(&m, &trait_ref.substs); @@ -400,6 +416,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { m: Rc>, method_num: uint|) { + debug!("elaborate_bounds(bounds={})", bounds.repr(self.tcx())); + let tcx = self.tcx(); let mut cache = HashSet::new(); for bound_trait_ref in traits::transitive_bounds(tcx, bounds) { @@ -802,11 +820,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // Convert the bounds into obligations. let obligations = - traits::obligations_for_generics( + traits::predicates_for_generics( self.tcx(), traits::ObligationCause::misc(self.span, self.fcx.body_id), - &impl_bounds, - &substs.types); + &impl_bounds); debug!("impl_obligations={}", obligations.repr(self.tcx())); // Evaluate those obligations to see if they might possibly hold. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index cd5cade78db7..73fae9760971 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -104,6 +104,7 @@ use {CrateCtxt, lookup_def_ccx, no_params, require_same_types}; use TypeAndSubsts; use middle::lang_items::TypeIdLangItem; use lint; +use util::common::ErrorReported; use util::common::{block_query, indenter, loop_query}; use util::ppaux::{mod, UserString, Repr}; use util::nodemap::{DefIdMap, FnvHashMap, NodeMap}; @@ -1761,7 +1762,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, self.body_id, traits::ItemObligation(def_id)), - &substs, &bounds); let monotype = polytype.ty.subst(self.tcx(), &substs); @@ -1785,14 +1785,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { code: traits::ObligationCauseCode<'tcx>, bound: ty::BuiltinBound) { - let obligation = traits::obligation_for_builtin_bound( - self.tcx(), - traits::ObligationCause::new(span, self.body_id, code), + self.register_builtin_bound( ty, - bound); - if let Ok(ob) = obligation { - self.register_obligation(ob); - } + bound, + traits::ObligationCause::new(span, self.body_id, code)); } pub fn require_type_is_sized(&self, @@ -1810,15 +1806,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.require_type_is_sized(self.expr_ty(expr), expr.span, code); } - pub fn register_obligation(&self, - obligation: traits::TraitObligation<'tcx>) + pub fn register_builtin_bound(&self, + ty: Ty<'tcx>, + builtin_bound: ty::BuiltinBound, + cause: traits::ObligationCause<'tcx>) { - debug!("register_obligation({})", + self.inh.fulfillment_cx.borrow_mut() + .register_builtin_bound(self.tcx(), ty, builtin_bound, cause); + } + + pub fn register_predicate(&self, + obligation: traits::PredicateObligation<'tcx>) + { + debug!("register_predicate({})", obligation.repr(self.tcx())); self.inh.fulfillment_cx .borrow_mut() - .register_obligation(self.tcx(), obligation); + .register_predicate(self.tcx(), obligation); } pub fn to_ty(&self, ast_t: &ast::Ty) -> Ty<'tcx> { @@ -1958,7 +1963,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { cause: traits::ObligationCause<'tcx>) { let mut fulfillment_cx = self.inh.fulfillment_cx.borrow_mut(); - fulfillment_cx.register_region_obligation(ty, region, cause); + fulfillment_cx.register_region_obligation(self.tcx(), ty, region, cause); } pub fn add_default_region_param_bounds(&self, @@ -1993,90 +1998,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// and `T`. This routine will add a region obligation `$1:'$0` and register it locally. pub fn add_obligations_for_parameters(&self, cause: traits::ObligationCause<'tcx>, - substs: &Substs<'tcx>, generic_bounds: &ty::GenericBounds<'tcx>) { assert!(!generic_bounds.has_escaping_regions()); - debug!("add_obligations_for_parameters(substs={}, generic_bounds={})", - substs.repr(self.tcx()), + debug!("add_obligations_for_parameters(generic_bounds={})", generic_bounds.repr(self.tcx())); - self.add_trait_obligations_for_generics(cause, substs, generic_bounds); - self.add_region_obligations_for_generics(cause, substs, generic_bounds); - } + let obligations = traits::predicates_for_generics(self.tcx(), + cause, + generic_bounds); - fn add_trait_obligations_for_generics(&self, - cause: traits::ObligationCause<'tcx>, - substs: &Substs<'tcx>, - generic_bounds: &ty::GenericBounds<'tcx>) { - assert!(!generic_bounds.has_escaping_regions()); - assert!(!substs.has_regions_escaping_depth(0)); - - let obligations = - traits::obligations_for_generics(self.tcx(), - cause, - generic_bounds, - &substs.types); - obligations.map_move(|o| self.register_obligation(o)); - } - - fn add_region_obligations_for_generics(&self, - cause: traits::ObligationCause<'tcx>, - substs: &Substs<'tcx>, - generic_bounds: &ty::GenericBounds<'tcx>) - { - assert!(!generic_bounds.has_escaping_regions()); - assert_eq!(generic_bounds.types.iter().len(), substs.types.iter().len()); - - for (type_bounds, &type_param) in - generic_bounds.types.iter().zip( - substs.types.iter()) - { - self.add_region_obligations_for_type_parameter( - cause.span, type_bounds, type_param); - } - - assert_eq!(generic_bounds.regions.iter().len(), - substs.regions().iter().len()); - for (region_bounds, ®ion_param) in - generic_bounds.regions.iter().zip( - substs.regions().iter()) - { - self.add_region_obligations_for_region_parameter( - cause.span, region_bounds.as_slice(), region_param); - } - } - - fn add_region_obligations_for_type_parameter(&self, - span: Span, - param_bound: &ty::ParamBounds<'tcx>, - ty: Ty<'tcx>) - { - // For each declared region bound `T:r`, `T` must outlive `r`. - let region_bounds = - ty::required_region_bounds( - self.tcx(), - param_bound.region_bounds.as_slice(), - param_bound.builtin_bounds, - param_bound.trait_bounds.as_slice()); - for &r in region_bounds.iter() { - let cause = traits::ObligationCause::new(span, self.body_id, traits::MiscObligation); - self.register_region_obligation(ty, r, cause); - } - } - - fn add_region_obligations_for_region_parameter(&self, - span: Span, - region_bounds: &[ty::Region], - region_param: ty::Region) - { - for &b in region_bounds.iter() { - // For each bound `region:b`, `b <= region` must hold - // (i.e., `region` must outlive `b`). - let origin = infer::RelateRegionParamBound(span); - self.mk_subr(origin, b, region_param); - } + obligations.map_move(|o| self.register_predicate(o)); } } @@ -4029,6 +3962,9 @@ fn check_expr_with_unifier<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let typ = lookup_method_for_for_loop(fcx, &**head, expr.id); vtable::select_new_fcx_obligations(fcx); + debug!("ExprForLoop each item has type {}", + fcx.infcx().resolve_type_vars_if_possible(typ).repr(fcx.tcx())); + let pcx = pat_ctxt { fcx: fcx, map: pat_id_map(&tcx.def_map, &**pat), @@ -5162,7 +5098,6 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fcx.add_obligations_for_parameters( traits::ObligationCause::new(span, fcx.body_id, traits::ItemObligation(def.def_id())), - &substs, &bounds); // Substitute the values for the type parameters into the type of diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 328c1eafae5c..cadcee43b440 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -932,14 +932,9 @@ fn check_expr_fn_block(rcx: &mut Rcx, // Check that the type meets the criteria of the existential bounds: for builtin_bound in bounds.builtin_bounds.iter() { - let code = traits::ClosureCapture(var_node_id, expr.span); + let code = traits::ClosureCapture(var_node_id, expr.span, builtin_bound); let cause = traits::ObligationCause::new(freevar.span, rcx.fcx.body_id, code); - let obligation = traits::obligation_for_builtin_bound(rcx.tcx(), cause, - var_ty, builtin_bound); - if let Ok(obligation) = obligation { - rcx.fcx.inh.fulfillment_cx.borrow_mut().register_obligation(rcx.tcx(), - obligation) - } + rcx.fcx.register_builtin_bound(var_ty, builtin_bound, cause); } type_must_outlive( rcx, infer::RelateProcBound(expr.span, var_node_id, var_ty), @@ -1859,20 +1854,14 @@ fn param_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, region.repr(rcx.tcx()), param_ty.repr(rcx.tcx())); - // Collect all regions that `param_ty` is known to outlive into - // this vector: - let mut param_bounds; - // To start, collect bounds from user: - let param_bound = param_env.bounds.get(param_ty.space, param_ty.idx); - param_bounds = + let mut param_bounds = ty::required_region_bounds(rcx.tcx(), - param_bound.region_bounds.as_slice(), - param_bound.builtin_bounds, - param_bound.trait_bounds.as_slice()); + param_ty.to_ty(rcx.tcx()), + param_env.caller_bounds.predicates.as_slice().to_vec()); - // Collect default bound of fn body that applies to all in scope - // type parameters: + // Add in the default bound of fn body that applies to all in + // scope type parameters: param_bounds.push(param_env.implicit_region_bound); // Finally, collect regions we scraped from the well-formedness diff --git a/src/librustc_typeck/check/regionmanip.rs b/src/librustc_typeck/check/regionmanip.rs index 92dfd8b5f56d..112ad1fb5b9b 100644 --- a/src/librustc_typeck/check/regionmanip.rs +++ b/src/librustc_typeck/check/regionmanip.rs @@ -97,7 +97,9 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { } ty::ty_trait(ref t) => { - self.accumulate_from_object_ty(ty, &t.bounds) + let required_region_bounds = + ty::object_region_bounds(self.tcx, Some(&t.principal), t.bounds.builtin_bounds); + self.accumulate_from_object_ty(ty, t.bounds.region_bound, required_region_bounds) } ty::ty_enum(def_id, ref substs) | @@ -321,12 +323,15 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { ty::UniqTraitStore => { } } - self.accumulate_from_object_ty(ty, &c.bounds) + let required_region_bounds = + ty::object_region_bounds(self.tcx, None, c.bounds.builtin_bounds); + self.accumulate_from_object_ty(ty, c.bounds.region_bound, required_region_bounds); } fn accumulate_from_object_ty(&mut self, ty: Ty<'tcx>, - bounds: &ty::ExistentialBounds) + region_bound: ty::Region, + required_region_bounds: Vec) { // Imagine a type like this: // @@ -362,17 +367,12 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { // The content of this object type must outlive // `bounds.region_bound`: - let r_c = bounds.region_bound; + let r_c = region_bound; self.push_region_constraint_from_top(r_c); // And then, in turn, to be well-formed, the // `region_bound` that user specified must imply the // region bounds required from all of the trait types: - let required_region_bounds = - ty::required_region_bounds(self.tcx, - &[], - bounds.builtin_bounds, - &[]); for &r_d in required_region_bounds.iter() { // Each of these is an instance of the `'c <= 'b` // constraint above diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index 17651b9bfb61..7c5ceb6f5107 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -12,15 +12,14 @@ use check::{FnCtxt, structurally_resolved_type}; use middle::subst::{SelfSpace, FnSpace}; use middle::traits; use middle::traits::{SelectionError, OutputTypeParameterMismatch, Overflow, Unimplemented}; -use middle::traits::{Obligation, ObligationCause, obligation_for_builtin_bound}; +use middle::traits::{Obligation, ObligationCause}; use middle::traits::{FulfillmentError, CodeSelectionError, CodeAmbiguity}; -use middle::traits::{TraitObligation}; +use middle::traits::{PredicateObligation}; use middle::ty::{mod, Ty}; use middle::infer; use std::rc::Rc; use syntax::ast; use syntax::codemap::Span; -use util::common::ErrorReported; use util::ppaux::{UserString, Repr, ty_to_string}; pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, @@ -249,18 +248,10 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, -> Rc> { // We can only make objects from sized types. - let sized_obligation = - traits::obligation_for_builtin_bound( - fcx.tcx(), - traits::ObligationCause::new(span, fcx.body_id, traits::ObjectSized), - referent_ty, - ty::BoundSized); - match sized_obligation { - Ok(sized_obligation) => { - fcx.register_obligation(sized_obligation); - } - Err(ErrorReported) => { } - } + fcx.register_builtin_bound( + referent_ty, + ty::BoundSized, + traits::ObligationCause::new(span, fcx.body_id, traits::ObjectSized)); // This is just for better error reporting. Kinda goofy. The object type stuff // needs some refactoring so there is a more convenient type to pass around. @@ -289,24 +280,18 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, ObligationCause::new(span, fcx.body_id, traits::ObjectCastObligation(object_trait_ty)), - object_trait_ref.clone()); - fcx.register_obligation(object_obligation); + ty::Predicate::Trait(object_trait_ref.clone())); + fcx.register_predicate(object_obligation); // Create additional obligations for all the various builtin // bounds attached to the object cast. (In other words, if the // object type is Foo+Send, this would create an obligation // for the Send check.) for builtin_bound in object_trait.bounds.builtin_bounds.iter() { - let obligation = obligation_for_builtin_bound( - fcx.tcx(), - ObligationCause::new(span, - fcx.body_id, - traits::ObjectCastObligation(object_trait_ty)), - referent_ty, - builtin_bound); - if let Ok(obligation) = obligation { - fcx.register_obligation(obligation); - } + fcx.register_builtin_bound( + referent_ty, + builtin_bound, + ObligationCause::new(span, fcx.body_id, traits::ObjectCastObligation(object_trait_ty))); } object_trait_ref @@ -325,17 +310,6 @@ pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) { } } -fn resolve_trait_ref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, obligation: &TraitObligation<'tcx>) - -> (Rc>, Ty<'tcx>) -{ - let trait_ref = - fcx.infcx().resolve_type_vars_in_trait_ref_if_possible( - &*obligation.trait_ref); - let self_ty = - trait_ref.substs.self_ty().unwrap(); - (Rc::new(trait_ref), self_ty) -} - pub fn report_fulfillment_errors<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, errors: &Vec>) { for error in errors.iter() { @@ -356,18 +330,42 @@ pub fn report_fulfillment_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - obligation: &TraitObligation<'tcx>, + obligation: &PredicateObligation<'tcx>, error: &SelectionError<'tcx>) { match *error { Overflow => { - let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation); - fcx.tcx().sess.span_err( - obligation.cause.span, - format!( - "overflow evaluating the trait `{}` for the type `{}`", - trait_ref.user_string(fcx.tcx()), - self_ty.user_string(fcx.tcx())).as_slice()); + // We could track the stack here more precisely if we wanted, I imagine. + match obligation.trait_ref { + ty::Predicate::Trait(ref trait_ref) => { + let trait_ref = + fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(&**trait_ref); + fcx.tcx().sess.span_err( + obligation.cause.span, + format!( + "overflow evaluating the trait `{}` for the type `{}`", + trait_ref.user_string(fcx.tcx()), + trait_ref.self_ty().user_string(fcx.tcx())).as_slice()); + } + + ty::Predicate::Equate(a, b) => { + let a = fcx.infcx().resolve_type_vars_if_possible(a); + let b = fcx.infcx().resolve_type_vars_if_possible(b); + fcx.tcx().sess.span_err( + obligation.cause.span, + format!( + "overflow checking whether the types `{}` and `{}` are equal", + a.user_string(fcx.tcx()), + b.user_string(fcx.tcx())).as_slice()); + } + + ty::Predicate::TypeOutlives(..) | + ty::Predicate::RegionOutlives(..) => { + fcx.tcx().sess.span_err( + obligation.cause.span, + format!("overflow evaluating lifetime predicate").as_slice()); + } + } let current_limit = fcx.tcx().sess.recursion_limit.get(); let suggested_limit = current_limit * 2; @@ -380,31 +378,63 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, note_obligation_cause(fcx, obligation); } Unimplemented => { - let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation); - if !ty::type_is_error(self_ty) { - fcx.tcx().sess.span_err( - obligation.cause.span, - format!( - "the trait `{}` is not implemented for the type `{}`", - trait_ref.user_string(fcx.tcx()), - self_ty.user_string(fcx.tcx())).as_slice()); - note_obligation_cause(fcx, obligation); + match obligation.trait_ref { + ty::Predicate::Trait(ref trait_ref) => { + let trait_ref = + fcx.infcx().resolve_type_vars_in_trait_ref_if_possible( + &**trait_ref); + if !ty::type_is_error(trait_ref.self_ty()) { + fcx.tcx().sess.span_err( + obligation.cause.span, + format!( + "the trait `{}` is not implemented for the type `{}`", + trait_ref.user_string(fcx.tcx()), + trait_ref.self_ty().user_string(fcx.tcx())).as_slice()); + note_obligation_cause(fcx, obligation); + } + } + + ty::Predicate::Equate(a, b) => { + let a = fcx.infcx().resolve_type_vars_if_possible(a); + let b = fcx.infcx().resolve_type_vars_if_possible(b); + let err = infer::can_mk_eqty(fcx.infcx(), a, b).unwrap_err(); + fcx.tcx().sess.span_err( + obligation.cause.span, + format!( + "mismatched types: the types `{}` and `{}` are not equal ({})", + a.user_string(fcx.tcx()), + b.user_string(fcx.tcx()), + ty::type_err_to_str(fcx.tcx(), &err)).as_slice()); + } + + ty::Predicate::TypeOutlives(..) | + ty::Predicate::RegionOutlives(..) => { + // these kinds of predicates turn into + // constraints, and hence errors show up in region + // inference. + fcx.tcx().sess.span_bug( + obligation.cause.span, + format!("region predicate error {}", + obligation.repr(fcx.tcx())).as_slice()); + } } } - OutputTypeParameterMismatch(ref expected_trait_ref, ref e) => { + OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => { let expected_trait_ref = fcx.infcx().resolve_type_vars_in_trait_ref_if_possible( &**expected_trait_ref); - let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation); - if !ty::type_is_error(self_ty) { + let actual_trait_ref = + fcx.infcx().resolve_type_vars_in_trait_ref_if_possible( + &**actual_trait_ref); + if !ty::type_is_error(actual_trait_ref.self_ty()) { fcx.tcx().sess.span_err( obligation.cause.span, format!( "type mismatch: the type `{}` implements the trait `{}`, \ but the trait `{}` is required ({})", - self_ty.user_string(fcx.tcx()), + expected_trait_ref.self_ty().user_string(fcx.tcx()), expected_trait_ref.user_string(fcx.tcx()), - trait_ref.user_string(fcx.tcx()), + actual_trait_ref.user_string(fcx.tcx()), ty::type_err_to_str(fcx.tcx(), e)).as_slice()); note_obligation_cause(fcx, obligation); } @@ -413,12 +443,25 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } pub fn maybe_report_ambiguity<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - obligation: &TraitObligation<'tcx>) { + obligation: &PredicateObligation<'tcx>) { // Unable to successfully determine, probably means // insufficient type information, but could mean // ambiguous impls. The latter *ought* to be a // coherence violation, so we don't report it here. - let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation); + + let trait_ref = match obligation.trait_ref { + ty::Predicate::Trait(ref trait_ref) => { + fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(&**trait_ref) + } + _ => { + fcx.tcx().sess.span_bug( + obligation.cause.span, + format!("ambiguity from something other than a trait: {}", + obligation.trait_ref.repr(fcx.tcx())).as_slice()); + } + }; + let self_ty = trait_ref.self_ty(); + debug!("maybe_report_ambiguity(trait_ref={}, self_ty={}, obligation={})", trait_ref.repr(fcx.tcx()), self_ty.repr(fcx.tcx()), @@ -475,8 +518,8 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } /// Select as many obligations as we can at present. -pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt) { - +pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt) +{ match fcx.inh.fulfillment_cx .borrow_mut() @@ -502,9 +545,8 @@ pub fn select_new_fcx_obligations(fcx: &FnCtxt) { } fn note_obligation_cause<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - obligation: &TraitObligation<'tcx>) { + obligation: &PredicateObligation<'tcx>) { let tcx = fcx.tcx(); - let trait_name = ty::item_path_str(tcx, obligation.trait_ref.def_id); match obligation.cause.code { traits::MiscObligation => { } traits::ItemObligation(item_def_id) => { @@ -512,17 +554,14 @@ fn note_obligation_cause<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, tcx.sess.span_note( obligation.cause.span, format!( - "the trait `{}` must be implemented because it is required by `{}`", - trait_name, + "required by `{}`", item_name).as_slice()); } traits::ObjectCastObligation(object_ty) => { tcx.sess.span_note( obligation.cause.span, format!( - "the trait `{}` must be implemented for the cast \ - to the object type `{}`", - trait_name, + "required for the cast to the object type `{}`", fcx.infcx().ty_to_string(object_ty)).as_slice()); } traits::RepeatVec => { @@ -560,7 +599,9 @@ fn note_obligation_cause<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, "use \"#[unsafe_destructor]\" on the implementation \ to force the compiler to allow this"); } - traits::ClosureCapture(var_id, closure_span) => { + traits::ClosureCapture(var_id, closure_span, builtin_bound) => { + let def_id = tcx.lang_items.from_builtin_kind(builtin_bound).unwrap(); + let trait_name = ty::item_path_str(tcx, def_id); let name = ty::local_var_name_str(tcx, var_id); span_note!(tcx.sess, closure_span, "the closure that captures `{}` requires that all captured variables \" diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index 23db98b31758..e89b127799c0 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -122,16 +122,12 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { // For DST, all intermediate types must be sized. if variant.fields.len() > 0 { for field in variant.fields.init().iter() { - let cause = traits::ObligationCause::new(field.span, - fcx.body_id, - traits::FieldSized); - let obligation = traits::obligation_for_builtin_bound(fcx.tcx(), - cause, - field.ty, - ty::BoundSized); - if let Ok(obligation) = obligation { - fcx.register_obligation(obligation); - } + fcx.register_builtin_bound( + field.ty, + ty::BoundSized, + traits::ObligationCause::new(field.span, + fcx.body_id, + traits::FieldSized)); } } } @@ -220,8 +216,6 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { // the same way as we treat the self-type. bounds_checker.check_trait_ref(&trait_ref); - let trait_def = ty::lookup_trait_def(fcx.tcx(), trait_ref.def_id); - let cause = traits::ObligationCause::new( item.span, @@ -229,25 +223,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { traits::ItemObligation(trait_ref.def_id)); // Find the supertrait bounds. This will add `int:Bar`. - // - // FIXME -- This is a bit ill-factored. There is very similar - // code in traits::util::obligations_for_generics. - fcx.add_region_obligations_for_type_parameter(item.span, - &trait_def.bounds, - trait_ref.self_ty()); - for builtin_bound in trait_def.bounds.builtin_bounds.iter() { - let obligation = traits::obligation_for_builtin_bound(fcx.tcx(), - cause, - trait_ref.self_ty(), - builtin_bound); - if let Ok(obligation) = obligation { - fcx.register_obligation(obligation); - } - } - for trait_bound in trait_def.bounds.trait_bounds.iter() { - let trait_bound = trait_bound.subst(fcx.tcx(), &trait_ref.substs); - fcx.register_obligation( - traits::Obligation::new(cause, trait_bound)); + let predicates = ty::predicates_for_trait_ref(fcx.tcx(), &trait_ref); + for predicate in predicates.into_iter() { + fcx.register_predicate(traits::Obligation::new(cause, predicate)); } }); } @@ -296,7 +274,6 @@ impl<'cx,'tcx> BoundsChecker<'cx,'tcx> { self.span, self.fcx.body_id, traits::ItemObligation(trait_ref.def_id)), - &trait_ref.substs, &bounds); for &ty in trait_ref.substs.types.iter() { @@ -347,7 +324,6 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { traits::ObligationCause::new(self.span, self.fcx.body_id, traits::ItemObligation(type_id)), - substs, &polytype.generics.to_bounds(self.tcx(), substs)); } else { // There are two circumstances in which we ignore @@ -372,12 +348,13 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { // // (I believe we should do the same for traits, but // that will require an RFC. -nmatsakis) - self.fcx.add_trait_obligations_for_generics( + let bounds = polytype.generics.to_bounds(self.tcx(), substs); + let bounds = filter_to_trait_obligations(bounds); + self.fcx.add_obligations_for_parameters( traits::ObligationCause::new(self.span, self.fcx.body_id, traits::ItemObligation(type_id)), - substs, - &polytype.generics.to_bounds(self.tcx(), substs)); + &bounds); } self.fold_substs(substs); @@ -464,6 +441,24 @@ fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, .collect() } +fn filter_to_trait_obligations<'tcx>(bounds: ty::GenericBounds<'tcx>) + -> ty::GenericBounds<'tcx> +{ + let mut result = ty::GenericBounds::empty(); + for (space, _, predicate) in bounds.predicates.iter_enumerated() { + match *predicate { + ty::Predicate::Trait(..) => { + result.predicates.push(space, predicate.clone()) + } + ty::Predicate::Equate(..) | + ty::Predicate::TypeOutlives(..) | + ty::Predicate::RegionOutlives(..) => { + } + } + } + result +} + /////////////////////////////////////////////////////////////////////////// // Special drop trait checking @@ -476,13 +471,7 @@ fn check_struct_safe_for_destructor<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, && !struct_tpt.generics.has_region_params(subst::TypeSpace) { let cause = traits::ObligationCause::new(span, fcx.body_id, traits::DropTrait); - let obligation = traits::obligation_for_builtin_bound(fcx.tcx(), - cause, - self_ty, - ty::BoundSend); - if let Ok(obligation) = obligation { - fcx.register_obligation(obligation); - } + fcx.register_builtin_bound(self_ty, ty::BoundSend, cause); } else { span_err!(fcx.tcx().sess, span, E0141, "cannot implement a destructor on a structure \ diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 9cfb56fbf8cb..09cf70804760 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -42,7 +42,6 @@ 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}; @@ -50,7 +49,6 @@ 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}; @@ -1409,14 +1407,15 @@ pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, .collect(); // ...and also create generics synthesized from the associated types. + let mut index = 0; let assoc_types: Vec<_> = items.iter() .flat_map(|item| match *item { ast::TypeTraitItem(ref trait_item) => { - let index = types.len(); + index += 1; Some(ty::mk_param(ccx.tcx, subst::AssocSpace, - index, + index - 1, local_def(trait_item.ty_param.id))).into_iter() } ast::RequiredMethod(_) | ast::ProvidedMethod(_) => { @@ -1598,7 +1597,8 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, substs: &subst::Substs<'tcx>, ast_generics: &ast::Generics, items: &[ast::TraitItem]) - -> ty::Generics<'tcx> { + -> ty::Generics<'tcx> +{ let mut generics = ty_generics(ccx, subst::TypeSpace, @@ -1646,7 +1646,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, bounds: ty::ParamBounds { region_bounds: vec!(), builtin_bounds: ty::empty_builtin_bounds(), - trait_bounds: vec!(self_trait_ref), + trait_bounds: vec!(self_trait_ref.clone()), }, associated_with: None, default: None @@ -1656,6 +1656,9 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, generics.types.push(subst::SelfSpace, def); + generics.predicates.push(subst::SelfSpace, + ty::Predicate::Trait(self_trait_ref)); + generics } @@ -1904,24 +1907,18 @@ fn ty_generics<'tcx,AC>(this: &AC, 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 type_param_def in result.types.get_slice(space).iter() { + let param_ty = ty::mk_param_from_def(tcx, type_param_def); + for predicate in ty::predicates(tcx, param_ty, &type_param_def.bounds).into_iter() { + result.predicates.push(space, predicate); } + } - 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())); + for region_param_def in result.regions.get_slice(space).iter() { + let region = region_param_def.to_early_bound_region(); + for &bound_region in region_param_def.bounds.iter() { + result.predicates.push(space, ty::Predicate::RegionOutlives(region, + bound_region)); } } } @@ -2178,8 +2175,7 @@ pub fn mk_item_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let regions = ty_generics.regions.map( - |def| ty::ReEarlyBound(def.def_id.node, def.space, - def.index, def.name)); + |def| def.to_early_bound_region()); subst::Substs::new(types, regions) } diff --git a/src/test/compile-fail/builtin-superkinds-self-type.rs b/src/test/compile-fail/builtin-superkinds-self-type.rs index 86d3d7e9cbc6..4c7ff60fbdd0 100644 --- a/src/test/compile-fail/builtin-superkinds-self-type.rs +++ b/src/test/compile-fail/builtin-superkinds-self-type.rs @@ -17,7 +17,6 @@ trait Foo : Sync+'static { impl Foo for T { } //~^ ERROR the parameter type `T` may not live long enough -//~^^ ERROR the parameter type `T` may not live long enough fn main() { let (tx, rx) = channel(); diff --git a/src/test/compile-fail/builtin-superkinds-simple.rs b/src/test/compile-fail/builtin-superkinds-simple.rs index fda83c03a7dc..2c689f6909b3 100644 --- a/src/test/compile-fail/builtin-superkinds-simple.rs +++ b/src/test/compile-fail/builtin-superkinds-simple.rs @@ -14,6 +14,6 @@ trait Foo : Send { } impl <'a> Foo for &'a mut () { } -//~^ ERROR does not fulfill the required lifetime +//~^ ERROR declared lifetime bound not satisfied fn main() { } diff --git a/src/test/compile-fail/kindck-impl-type-params.rs b/src/test/compile-fail/kindck-impl-type-params.rs index a430fe72333c..57ee4cf7cc3b 100644 --- a/src/test/compile-fail/kindck-impl-type-params.rs +++ b/src/test/compile-fail/kindck-impl-type-params.rs @@ -34,6 +34,7 @@ fn g(val: T) { fn foo<'a>() { let t: S<&'a int> = S; let a = &t as &Gettable<&'a int>; + //~^ ERROR declared lifetime bound not satisfied } fn foo2<'a>() { diff --git a/src/test/compile-fail/kindck-send-object1.rs b/src/test/compile-fail/kindck-send-object1.rs index a55197536432..35e928d417c3 100644 --- a/src/test/compile-fail/kindck-send-object1.rs +++ b/src/test/compile-fail/kindck-send-object1.rs @@ -22,7 +22,7 @@ fn test51<'a>() { } fn test52<'a>() { assert_send::<&'a (Dummy+Send)>(); - //~^ ERROR does not fulfill the required lifetime + //~^ ERROR declared lifetime bound not satisfied } // ...unless they are properly bounded diff --git a/src/test/compile-fail/kindck-send-owned.rs b/src/test/compile-fail/kindck-send-owned.rs index 0eed05692b9c..11148d2846c1 100644 --- a/src/test/compile-fail/kindck-send-owned.rs +++ b/src/test/compile-fail/kindck-send-owned.rs @@ -19,7 +19,7 @@ fn test32() { assert_send:: >(); } // but not if they own a bad thing fn test40<'a>(_: &'a int) { - assert_send::>(); //~ ERROR does not fulfill the required lifetime + assert_send::>(); //~ ERROR declared lifetime bound not satisfied } fn main() { } diff --git a/src/test/compile-fail/kindck-send-region-pointers.rs b/src/test/compile-fail/kindck-send-region-pointers.rs index cc46d7f4de9c..04172932cfe6 100644 --- a/src/test/compile-fail/kindck-send-region-pointers.rs +++ b/src/test/compile-fail/kindck-send-region-pointers.rs @@ -22,13 +22,13 @@ fn test10() { assert_send::<&'static mut int>(); } // otherwise lifetime pointers are not ok fn test20<'a>(_: &'a int) { - assert_send::<&'a int>(); //~ ERROR does not fulfill the required lifetime + assert_send::<&'a int>(); //~ ERROR declared lifetime bound not satisfied } fn test21<'a>(_: &'a int) { - assert_send::<&'a str>(); //~ ERROR does not fulfill the required lifetime + assert_send::<&'a str>(); //~ ERROR declared lifetime bound not satisfied } fn test22<'a>(_: &'a int) { - assert_send::<&'a [int]>(); //~ ERROR does not fulfill the required lifetime + assert_send::<&'a [int]>(); //~ ERROR declared lifetime bound not satisfied } fn main() { } diff --git a/src/test/compile-fail/kindck-send-unsafe.rs b/src/test/compile-fail/kindck-send-unsafe.rs index a9bbfcfa2626..33314149d1fa 100644 --- a/src/test/compile-fail/kindck-send-unsafe.rs +++ b/src/test/compile-fail/kindck-send-unsafe.rs @@ -15,7 +15,7 @@ fn test70() { assert_send::<*mut int>(); } fn test71<'a>() { - assert_send::<*mut &'a int>(); //~ ERROR does not fulfill the required lifetime + assert_send::<*mut &'a int>(); //~ ERROR declared lifetime bound not satisfied } fn main() { diff --git a/src/test/compile-fail/recursion_limit.rs b/src/test/compile-fail/recursion_limit.rs index 17afb168a983..1da7f47677a2 100644 --- a/src/test/compile-fail/recursion_limit.rs +++ b/src/test/compile-fail/recursion_limit.rs @@ -44,8 +44,8 @@ fn main() { is_send::(); //~^ ERROR overflow evaluating //~^^ NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate - //~^^^ NOTE must be implemented + //~^^^ NOTE required by `is_send` //~^^^^ ERROR overflow evaluating //~^^^^^ NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate - //~^^^^^^ NOTE must be implemented + //~^^^^^^ NOTE required by `is_send` } diff --git a/src/test/compile-fail/region-object-lifetime-in-coercion.rs b/src/test/compile-fail/region-object-lifetime-in-coercion.rs index dfeba0410928..b2b2d3337c41 100644 --- a/src/test/compile-fail/region-object-lifetime-in-coercion.rs +++ b/src/test/compile-fail/region-object-lifetime-in-coercion.rs @@ -15,12 +15,12 @@ trait Foo {} impl<'a> Foo for &'a [u8] {} fn a(v: &[u8]) -> Box { - let x: Box = box v; //~ ERROR does not outlive + let x: Box = box v; //~ ERROR declared lifetime bound not satisfied x } fn b(v: &[u8]) -> Box { - box v //~ ERROR does not outlive + box v //~ ERROR declared lifetime bound not satisfied } fn c(v: &[u8]) -> Box { @@ -28,7 +28,7 @@ fn c(v: &[u8]) -> Box { } fn d<'a,'b>(v: &'a [u8]) -> Box { - box v //~ ERROR does not outlive + box v //~ ERROR declared lifetime bound not satisfied } fn e<'a:'b,'b>(v: &'a [u8]) -> Box { diff --git a/src/test/compile-fail/regions-bounded-by-send.rs b/src/test/compile-fail/regions-bounded-by-send.rs index 660a9be4f63c..ec679a7dda17 100644 --- a/src/test/compile-fail/regions-bounded-by-send.rs +++ b/src/test/compile-fail/regions-bounded-by-send.rs @@ -29,15 +29,15 @@ fn static_lifime_ok<'a,T,U:Send>(_: &'a int) { // otherwise lifetime pointers are not ok fn param_not_ok<'a>(x: &'a int) { - assert_send::<&'a int>(); //~ ERROR does not fulfill + assert_send::<&'a int>(); //~ ERROR declared lifetime bound not satisfied } fn param_not_ok1<'a>(_: &'a int) { - assert_send::<&'a str>(); //~ ERROR does not fulfill + assert_send::<&'a str>(); //~ ERROR declared lifetime bound not satisfied } fn param_not_ok2<'a>(_: &'a int) { - assert_send::<&'a [int]>(); //~ ERROR does not fulfill + assert_send::<&'a [int]>(); //~ ERROR declared lifetime bound not satisfied } // boxes are ok @@ -51,7 +51,7 @@ fn box_ok() { // but not if they own a bad thing fn box_with_region_not_ok<'a>() { - assert_send::>(); //~ ERROR does not fulfill + assert_send::>(); //~ ERROR declared lifetime bound not satisfied } // objects with insufficient bounds no ok @@ -63,7 +63,7 @@ fn object_with_random_bound_not_ok<'a>() { fn object_with_send_bound_not_ok<'a>() { assert_send::<&'a (Dummy+Send)>(); - //~^ ERROR does not fulfill + //~^ ERROR declared lifetime bound not satisfied } fn proc_with_lifetime_not_ok<'a>() { @@ -84,11 +84,11 @@ fn unsafe_ok1<'a>(_: &'a int) { } fn unsafe_ok2<'a>(_: &'a int) { - assert_send::<*const &'a int>(); //~ ERROR does not fulfill + assert_send::<*const &'a int>(); //~ ERROR declared lifetime bound not satisfied } fn unsafe_ok3<'a>(_: &'a int) { - assert_send::<*mut &'a int>(); //~ ERROR does not fulfill + assert_send::<*mut &'a int>(); //~ ERROR declared lifetime bound not satisfied } fn main() { diff --git a/src/test/compile-fail/regions-bounded-by-trait-requiring-static.rs b/src/test/compile-fail/regions-bounded-by-trait-requiring-static.rs index 04a94b75215a..e3939a4e3904 100644 --- a/src/test/compile-fail/regions-bounded-by-trait-requiring-static.rs +++ b/src/test/compile-fail/regions-bounded-by-trait-requiring-static.rs @@ -29,15 +29,15 @@ fn static_lifime_ok<'a,T,U:Send>(_: &'a int) { // otherwise lifetime pointers are not ok fn param_not_ok<'a>(x: &'a int) { - assert_send::<&'a int>(); //~ ERROR does not fulfill + assert_send::<&'a int>(); //~ ERROR declared lifetime bound not satisfied } fn param_not_ok1<'a>(_: &'a int) { - assert_send::<&'a str>(); //~ ERROR does not fulfill + assert_send::<&'a str>(); //~ ERROR declared lifetime bound not satisfied } fn param_not_ok2<'a>(_: &'a int) { - assert_send::<&'a [int]>(); //~ ERROR does not fulfill + assert_send::<&'a [int]>(); //~ ERROR declared lifetime bound not satisfied } // boxes are ok @@ -51,7 +51,7 @@ fn box_ok() { // but not if they own a bad thing fn box_with_region_not_ok<'a>() { - assert_send::>(); //~ ERROR does not fulfill + assert_send::>(); //~ ERROR declared lifetime bound not satisfied } // unsafe pointers are ok unless they point at unsendable things @@ -62,11 +62,11 @@ fn unsafe_ok1<'a>(_: &'a int) { } fn unsafe_ok2<'a>(_: &'a int) { - assert_send::<*const &'a int>(); //~ ERROR does not fulfill + assert_send::<*const &'a int>(); //~ ERROR declared lifetime bound not satisfied } fn unsafe_ok3<'a>(_: &'a int) { - assert_send::<*mut &'a int>(); //~ ERROR does not fulfill + assert_send::<*mut &'a int>(); //~ ERROR declared lifetime bound not satisfied } fn main() { diff --git a/src/test/compile-fail/regions-bounded-method-type-parameters.rs b/src/test/compile-fail/regions-bounded-method-type-parameters.rs index 279139d8de96..10484925980a 100644 --- a/src/test/compile-fail/regions-bounded-method-type-parameters.rs +++ b/src/test/compile-fail/regions-bounded-method-type-parameters.rs @@ -20,7 +20,7 @@ impl Foo { fn caller<'a>(x: &int) { Foo.some_method::<&'a int>(); - //~^ ERROR does not fulfill the required lifetime + //~^ ERROR declared lifetime bound not satisfied } fn main() { } diff --git a/src/test/compile-fail/regions-proc-bounds.rs b/src/test/compile-fail/regions-proc-bounds.rs index db71bc4e15c0..4c95e1eac6d5 100644 --- a/src/test/compile-fail/regions-proc-bounds.rs +++ b/src/test/compile-fail/regions-proc-bounds.rs @@ -12,7 +12,7 @@ fn is_static() {} fn foo<'a>() { is_static::(); - //~^ ERROR does not fulfill the required lifetime + //~^ ERROR declared lifetime bound not satisfied is_static::(); } From 07eebf69107b50082386fa8c74d31aebcba8e6f1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 9 Dec 2014 20:23:26 -0500 Subject: [PATCH 07/10] Remove diagnostic errors that were yielding warnings. --- src/librustc/diagnostics.rs | 85 ------------------------------------- 1 file changed, 85 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 0cdf6a68e44b..fcac718b3708 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -40,89 +40,8 @@ register_diagnostics!( E0019, E0020, E0022, - E0023, - E0024, - E0025, - E0026, - E0027, - E0029, - E0030, - E0031, - E0033, - E0034, - E0035, - E0036, - E0038, - E0040, - E0044, - E0045, - E0046, - E0049, - E0050, - E0051, - E0052, - E0053, - E0054, - E0055, - E0056, - E0057, - E0059, - E0060, - E0061, - E0062, - E0063, - E0066, - E0067, - E0068, - E0069, - E0070, - E0071, - E0072, - E0073, - E0074, - E0075, - E0076, - E0077, - E0079, - E0080, - E0081, - E0082, - E0083, - E0084, - E0085, - E0086, - E0087, - E0088, - E0089, - E0090, - E0091, - E0092, - E0093, - E0094, - E0100, - E0101, - E0102, - E0103, - E0104, - E0106, - E0107, - E0108, E0109, E0110, - E0116, - E0117, - E0118, - E0119, - E0120, - E0121, - E0122, - E0124, - E0127, - E0128, - E0129, - E0130, - E0131, - E0132, E0133, E0134, E0135, @@ -131,16 +50,12 @@ register_diagnostics!( E0138, E0139, E0140, - E0141, E0152, E0153, E0157, E0158, - E0159, E0161, E0162, - E0163, - E0164, E0165, E0166, E0167, From 97cf91aa30c84b14c72d88f51f9f22a50a8e3b54 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 9 Dec 2014 20:25:09 -0500 Subject: [PATCH 08/10] Fix the opt-out-copy behavior so that values with dtor etc are considered affine --- src/librustc/middle/traits/select.rs | 9 +++++ src/librustc_typeck/check/mod.rs | 1 - src/test/compile-fail/opt-out-copy-bad.rs | 42 +++++++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/opt-out-copy-bad.rs diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index c55335ea190e..88c70f5557c1 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -1289,6 +1289,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // don't supply any form of builtin impl. if !this.tcx().sess.features.borrow().opt_out_copy { return Ok(ParameterBuiltin) + } else { + // Older, backwards compatibility behavior: + if + Some(def_id) == tcx.lang_items.no_copy_bound() || + Some(def_id) == tcx.lang_items.managed_bound() || + ty::has_dtor(tcx, def_id) + { + return Err(Unimplemented); + } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 73fae9760971..573c63eb6af0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -104,7 +104,6 @@ use {CrateCtxt, lookup_def_ccx, no_params, require_same_types}; use TypeAndSubsts; use middle::lang_items::TypeIdLangItem; use lint; -use util::common::ErrorReported; use util::common::{block_query, indenter, loop_query}; use util::ppaux::{mod, UserString, Repr}; use util::nodemap::{DefIdMap, FnvHashMap, NodeMap}; diff --git a/src/test/compile-fail/opt-out-copy-bad.rs b/src/test/compile-fail/opt-out-copy-bad.rs new file mode 100644 index 000000000000..80f8a154d58e --- /dev/null +++ b/src/test/compile-fail/opt-out-copy-bad.rs @@ -0,0 +1,42 @@ +// 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. + +#![feature(opt_out_copy)] + +// Test that when using the `opt-out-copy` feature we still consider +// destructors to be non-movable + +struct CantCopyThis; + +impl Drop for CantCopyThis { + fn drop(&mut self) { } +} + +struct IWantToCopyThis { + but_i_cant: CantCopyThis, +} + +impl Copy for IWantToCopyThis {} +//~^ ERROR the trait `Copy` may not be implemented for this type + +enum CantCopyThisEither { + A, + B(::std::kinds::marker::NoCopy), +} + +enum IWantToCopyThisToo { + ButICant(CantCopyThisEither), +} + +impl Copy for IWantToCopyThisToo {} +//~^ ERROR the trait `Copy` may not be implemented for this type + +fn main() {} + From 5f43899db46f8211cf634ce9ce195662f3dfb97a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 10 Dec 2014 17:56:15 -0500 Subject: [PATCH 09/10] Implement the astencode rules for predicates. These don't actually get used by trans, but it's easy to do. --- src/librustc/middle/astencode.rs | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 319337bf48b7..50337ec25bd1 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -830,6 +830,8 @@ trait rbml_writer_helpers<'tcx> { fn emit_tys<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, tys: &[Ty<'tcx>]); fn emit_type_param_def<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, type_param_def: &ty::TypeParameterDef<'tcx>); + fn emit_predicate<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, + predicate: &ty::Predicate<'tcx>); fn emit_trait_ref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, ty: &ty::TraitRef<'tcx>); fn emit_polytype<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, @@ -936,6 +938,15 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { }); } + fn emit_predicate<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, + predicate: &ty::Predicate<'tcx>) { + self.emit_opaque(|this| { + Ok(tyencode::enc_predicate(this.writer, + &ecx.ty_str_ctxt(), + predicate)) + }); + } + fn emit_polytype<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, pty: ty::Polytype<'tcx>) { @@ -953,6 +964,11 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { Ok(encode_vec_per_param_space( this, &pty.generics.regions, |this, def| def.encode(this).unwrap())) + }); + this.emit_struct_field("predicates", 2, |this| { + Ok(encode_vec_per_param_space( + this, &pty.generics.predicates, + |this, def| this.emit_predicate(ecx, def))) }) }) }); @@ -1336,6 +1352,8 @@ trait rbml_decoder_decoder_helpers<'tcx> { -> Rc>; fn read_type_param_def<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> ty::TypeParameterDef<'tcx>; + fn read_predicate<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) + -> ty::Predicate<'tcx>; fn read_polytype<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> ty::Polytype<'tcx>; fn read_existential_bounds<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) @@ -1536,6 +1554,15 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { }).unwrap() } + fn read_predicate<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) + -> ty::Predicate<'tcx> + { + self.read_opaque(|this, doc| { + Ok(tydecode::parse_predicate_data(doc.data, doc.start, dcx.cdata.cnum, dcx.tcx, + |s, a| this.convert_def_id(dcx, s, a))) + }).unwrap() + } + fn read_polytype<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> ty::Polytype<'tcx> { self.read_struct("Polytype", 2, |this| { @@ -1556,7 +1583,10 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { }).unwrap(), predicates: - subst::VecPerParamSpace::empty(), // TODO fix in later commit + this.read_struct_field("predicates", 2, |this| { + Ok(this.read_vec_per_param_space( + |this| this.read_predicate(dcx))) + }).unwrap(), }) }) }).unwrap(), From 124e1e18cc4f327730a978a7a8c1e7876bb63c6e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 11 Dec 2014 04:35:51 -0500 Subject: [PATCH 10/10] Improve comments and address nits. --- src/librustc/middle/traits/fulfill.rs | 48 ++++++++++++++------------- src/librustc/middle/traits/mod.rs | 7 +++- src/librustc/middle/traits/util.rs | 15 ++++++++- src/librustc/middle/ty.rs | 21 +++++------- src/librustc_typeck/check/wf.rs | 1 - 5 files changed, 54 insertions(+), 38 deletions(-) diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 9d9c3e238d40..412c188f5f4a 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -250,13 +250,15 @@ impl<'tcx> FulfillmentContext<'tcx> { self.predicates.retain(|predicate| { // Hack: Retain does not pass in the index, but we want // to avoid processing the first `start_count` entries. - if skip == 0 { - retain_predicate(selcx, predicate, - &mut selections, &mut errors, region_obligations) - } else { - skip -= 1; - true - } + let processed = + if skip == 0 { + process_predicate(selcx, predicate, + &mut selections, &mut errors, region_obligations) + } else { + skip -= 1; + false + }; + !processed }); } @@ -286,17 +288,17 @@ impl<'tcx> FulfillmentContext<'tcx> { } } -fn retain_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, - predicate: &PredicateObligation<'tcx>, - selections: &mut Vec>, - errors: &mut Vec>, - region_obligations: &mut NodeMap>>) - -> bool +fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, + predicate: &PredicateObligation<'tcx>, + selections: &mut Vec>, + errors: &mut Vec>, + region_obligations: &mut NodeMap>>) + -> bool { /*! - * Evaluates a predicate obligation and modifies the appropriate - * output array. Returns `true` if the predicate must be retained - * because it could not be fully evaluated yet due to insufficient + * Processes a predicate obligation and modifies the appropriate + * output array with the successful/error result. Returns `false` + * if the predicate could not be processed due to insufficient * type inference. */ @@ -308,11 +310,11 @@ fn retain_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, trait_ref: trait_ref.clone() }; match selcx.select(&trait_obligation) { Ok(None) => { - true + false } Ok(Some(s)) => { selections.push(s); - false + true } Err(selection_err) => { debug!("predicate: {} error: {}", @@ -322,7 +324,7 @@ fn retain_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, FulfillmentError::new( predicate.clone(), CodeSelectionError(selection_err))); - false + true } } } @@ -331,14 +333,14 @@ fn retain_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, let origin = infer::EquatePredicate(predicate.cause.span); match infer::mk_eqty(selcx.infcx(), false, origin, a, b) { Ok(()) => { - false + true } Err(_) => { errors.push( FulfillmentError::new( predicate.clone(), CodeSelectionError(Unimplemented))); - false + true } } } @@ -346,12 +348,12 @@ fn retain_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, ty::Predicate::RegionOutlives(r_a, r_b) => { let origin = infer::RelateRegionParamBound(predicate.cause.span); let () = infer::mk_subr(selcx.infcx(), origin, r_b, r_a); // `b : a` ==> `a <= b` - false + true } ty::Predicate::TypeOutlives(t_a, r_b) => { register_region_obligation(tcx, t_a, r_b, predicate.cause, region_obligations); - false + true } } } diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index f438b61e27c2..604a0607c0b4 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -61,7 +61,12 @@ pub type TraitObligation<'tcx> = Obligation<'tcx, Rc>>; pub struct ObligationCause<'tcx> { pub span: Span, - // the id of XXX + // The id of the fn body that triggered this obligation. This is + // used for region obligations to determine the precise + // environment in which the region obligation should be evaluated + // (in particular, closures can add new assumptions). See the + // field `region_obligations` of the `FulfillmentContext` for more + // information. pub body_id: ast::NodeId, pub code: ObligationCauseCode<'tcx> diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index a9532aceebb1..52154e0be7ad 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -24,8 +24,16 @@ use super::{Obligation, ObligationCause, PredicateObligation, VtableImpl, VtableParam, VtableParamData, VtableImplData}; /////////////////////////////////////////////////////////////////////////// -// Elaboration iterator +// `Elaboration` iterator +/////////////////////////////////////////////////////////////////////////// +/// "Elaboration" is the process of identifying all the predicates that +/// are implied by a source predicate. Currently this basically means +/// walking the "supertraits" and other similar assumptions. For +/// example, if we know that `T : Ord`, the elaborator would deduce +/// that `T : PartialOrd` holds as well. Similarly, if we have `trait +/// Foo : 'static`, and we know that `T : Foo`, then we know that `T : +/// 'static`. pub struct Elaborator<'cx, 'tcx:'cx> { tcx: &'cx ty::ctxt<'tcx>, stack: Vec>, @@ -157,7 +165,10 @@ impl<'cx, 'tcx> Iterator> for Elaborator<'cx, 'tcx> { /////////////////////////////////////////////////////////////////////////// // Supertrait iterator +/////////////////////////////////////////////////////////////////////////// +/// A filter around the `Elaborator` that just yields up supertrait references, +/// not other kinds of predicates. pub struct Supertraits<'cx, 'tcx:'cx> { elaborator: Elaborator<'cx, 'tcx>, } @@ -197,6 +208,8 @@ impl<'cx, 'tcx> Iterator>> for Supertraits<'cx, 'tcx> { } } +/////////////////////////////////////////////////////////////////////////// +// Other /////////////////////////////////////////////////////////////////////////// // determine the `self` type, using fresh variables for all variables diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index ca226e2ca3fa..ddbf69685cd9 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1656,14 +1656,16 @@ impl<'tcx> Generics<'tcx> { #[deriving(Clone, PartialEq, Eq, Hash, Show)] pub enum Predicate<'tcx> { - /// where Foo : Bar + /// Corresponds to `where Foo : Bar`. `Foo` here would be + /// the `Self` type of the trait reference and `A`, `B`, and `C` + /// would be the parameters in the `TypeSpace`. Trait(Rc>), - /// where Foo == Bar - Equate(Ty<'tcx>, Ty<'tcx>), + /// where `T1 == T2`. + Equate(/* T1 */ Ty<'tcx>, /* T2 */ Ty<'tcx>), /// where 'a : 'b - RegionOutlives(Region, Region), + RegionOutlives(/* 'a */ Region, /* 'b */ Region), /// where T : 'a TypeOutlives(Ty<'tcx>, Region), @@ -1807,7 +1809,6 @@ impl<'tcx> ParameterEnvironment<'tcx> { let method_generics = &method_ty.generics; construct_parameter_environment( cx, - method.span, method_generics, method.pe_body().id) } @@ -1842,7 +1843,6 @@ impl<'tcx> ParameterEnvironment<'tcx> { let method_generics = &method_ty.generics; construct_parameter_environment( cx, - method.span, method_generics, method.pe_body().id) } @@ -1869,7 +1869,6 @@ impl<'tcx> ParameterEnvironment<'tcx> { let fn_pty = ty::lookup_item_type(cx, fn_def_id); construct_parameter_environment(cx, - item.span, &fn_pty.generics, body.id) } @@ -1880,8 +1879,7 @@ impl<'tcx> ParameterEnvironment<'tcx> { ast::ItemStatic(..) => { let def_id = ast_util::local_def(id); let pty = ty::lookup_item_type(cx, def_id); - construct_parameter_environment(cx, item.span, - &pty.generics, id) + construct_parameter_environment(cx, &pty.generics, id) } _ => { cx.sess.span_bug(item.span, @@ -5031,8 +5029,8 @@ pub fn lookup_trait_def<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId) }) } -/// Given a reference to a trait, returns the bounds declared on the -/// trait, with appropriate substitutions applied. +/// Given a reference to a trait, returns the "superbounds" declared +/// on the trait, with appropriate substitutions applied. pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>, trait_ref: &TraitRef<'tcx>) -> Vec> @@ -5929,7 +5927,6 @@ pub fn empty_parameter_environment<'tcx>() -> ParameterEnvironment<'tcx> { /// See `ParameterEnvironment` struct def'n for details pub fn construct_parameter_environment<'tcx>( tcx: &ctxt<'tcx>, - _span: Span, generics: &ty::Generics<'tcx>, free_id: ast::NodeId) -> ParameterEnvironment<'tcx> diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index e89b127799c0..8c82429e1c22 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -91,7 +91,6 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { let polytype = ty::lookup_item_type(ccx.tcx, item_def_id); let param_env = ty::construct_parameter_environment(ccx.tcx, - item.span, &polytype.generics, item.id); let inh = Inherited::new(ccx.tcx, param_env);