From 03d3ba7667ed9599f46b742ac314a43297d76b19 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 30 Mar 2015 17:46:34 -0400 Subject: [PATCH 1/6] Implement the changes to coherence such that we consider a type to be local only if matches `FUNDAMENTAL(LocalType)`, where `FUNDAMENTAL` includes `&T` and types marked as fundamental (which includes `Box`). Also apply these tests to negative reasoning. --- src/librustc/middle/traits/coherence.rs | 203 +++++++++++++++++------- src/librustc/middle/traits/select.rs | 103 ++++++++---- src/librustc/middle/traits/util.rs | 38 ++++- src/librustc/middle/ty.rs | 27 ++-- src/librustc/middle/ty_walk.rs | 117 +++++++------- src/librustc/util/ppaux.rs | 8 +- src/libsyntax/feature_gate.rs | 6 + 7 files changed, 337 insertions(+), 165 deletions(-) diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index 11d073ce72e73..411be28b89695 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -17,15 +17,17 @@ use super::PredicateObligation; use super::project; use super::util; -use middle::subst::{Subst, TypeSpace}; +use middle::subst::{Subst, Substs, TypeSpace}; use middle::ty::{self, ToPolyTraitRef, Ty}; use middle::infer::{self, InferCtxt}; -use std::collections::HashSet; use std::rc::Rc; use syntax::ast; -use syntax::codemap::DUMMY_SP; +use syntax::codemap::{DUMMY_SP, Span}; use util::ppaux::Repr; +#[derive(Copy)] +struct ParamIsLocal(bool); + /// True if there exist types that satisfy both of the two given impls. pub fn overlapping_impls(infcx: &InferCtxt, impl1_def_id: ast::DefId, @@ -56,10 +58,16 @@ fn overlap(selcx: &mut SelectionContext, a_def_id.repr(selcx.tcx()), b_def_id.repr(selcx.tcx())); - let (a_trait_ref, a_obligations) = impl_trait_ref_and_oblig(selcx, a_def_id); - let (b_trait_ref, b_obligations) = impl_trait_ref_and_oblig(selcx, b_def_id); + let (a_trait_ref, a_obligations) = impl_trait_ref_and_oblig(selcx, + a_def_id, + util::free_substs_for_impl); + + let (b_trait_ref, b_obligations) = impl_trait_ref_and_oblig(selcx, + b_def_id, + util::fresh_type_vars_for_impl); debug!("overlap: a_trait_ref={}", a_trait_ref.repr(selcx.tcx())); + debug!("overlap: b_trait_ref={}", b_trait_ref.repr(selcx.tcx())); // Does `a <: b` hold? If not, no overlap. @@ -74,28 +82,68 @@ fn overlap(selcx: &mut SelectionContext, debug!("overlap: subtraitref check succeeded"); // Are any of the obligations unsatisfiable? If so, no overlap. + let tcx = selcx.tcx(); + let infcx = selcx.infcx(); let opt_failing_obligation = a_obligations.iter() .chain(b_obligations.iter()) + .map(|o| infcx.resolve_type_vars_if_possible(o)) .find(|o| !selcx.evaluate_obligation(o)); if let Some(failing_obligation) = opt_failing_obligation { - debug!("overlap: obligation unsatisfiable {}", failing_obligation.repr(selcx.tcx())); - return false; + debug!("overlap: obligation unsatisfiable {}", failing_obligation.repr(tcx)); + return false } true } +pub fn trait_ref_is_knowable<'tcx>(tcx: &ty::ctxt<'tcx>, trait_ref: &ty::TraitRef<'tcx>) -> bool +{ + debug!("trait_ref_is_knowable(trait_ref={})", trait_ref.repr(tcx)); + + // if the orphan rules pass, that means that no ancestor crate can + // impl this, so it's up to us. + if orphan_check_trait_ref(tcx, trait_ref, ParamIsLocal(false)).is_ok() { + debug!("trait_ref_is_knowable: orphan check passed"); + return true; + } + + // if the trait is not marked fundamental, then it's always possible that + // an ancestor crate will impl this in the future, if they haven't + // already + if + trait_ref.def_id.krate != ast::LOCAL_CRATE && + !ty::has_attr(tcx, trait_ref.def_id, "fundamental") + { + debug!("trait_ref_is_knowable: trait is neither local nor fundamental"); + return false; + } + + // find out when some downstream (or cousin) crate could impl this + // trait-ref, presuming that all the parameters were instantiated + // with downstream types. If not, then it could only be + // implemented by an upstream crate, which means that the impl + // must be visible to us, and -- since the trait is fundamental + // -- we can test. + orphan_check_trait_ref(tcx, trait_ref, ParamIsLocal(true)).is_err() +} + +type SubstsFn = for<'a,'tcx> fn(infcx: &InferCtxt<'a, 'tcx>, + span: Span, + impl_def_id: ast::DefId) + -> Substs<'tcx>; + /// Instantiate fresh variables for all bound parameters of the impl /// and return the impl trait ref with those variables substituted. fn impl_trait_ref_and_oblig<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, - impl_def_id: ast::DefId) + impl_def_id: ast::DefId, + substs_fn: SubstsFn) -> (Rc>, Vec>) { let impl_substs = - &util::fresh_substs_for_impl(selcx.infcx(), DUMMY_SP, impl_def_id); + &substs_fn(selcx.infcx(), DUMMY_SP, impl_def_id); let impl_trait_ref = ty::impl_trait_ref(selcx.tcx(), impl_def_id).unwrap(); let impl_trait_ref = @@ -134,12 +182,12 @@ pub fn orphan_check<'tcx>(tcx: &ty::ctxt<'tcx>, impl_def_id: ast::DefId) -> Result<(), OrphanCheckErr<'tcx>> { - debug!("impl_is_local({})", impl_def_id.repr(tcx)); + debug!("orphan_check({})", impl_def_id.repr(tcx)); // We only except this routine to be invoked on implementations // of a trait, not inherent implementations. let trait_ref = ty::impl_trait_ref(tcx, impl_def_id).unwrap(); - debug!("trait_ref={}", trait_ref.repr(tcx)); + debug!("orphan_check: trait_ref={}", trait_ref.repr(tcx)); // If the *trait* is local to the crate, ok. if trait_ref.def_id.krate == ast::LOCAL_CRATE { @@ -148,34 +196,106 @@ pub fn orphan_check<'tcx>(tcx: &ty::ctxt<'tcx>, return Ok(()); } + orphan_check_trait_ref(tcx, &trait_ref, ParamIsLocal(false)) +} + +fn orphan_check_trait_ref<'tcx>(tcx: &ty::ctxt<'tcx>, + trait_ref: &ty::TraitRef<'tcx>, + param_is_local: ParamIsLocal) + -> Result<(), OrphanCheckErr<'tcx>> +{ + debug!("orphan_check_trait_ref(trait_ref={}, param_is_local={})", + trait_ref.repr(tcx), param_is_local.0); + // First, create an ordered iterator over all the type parameters to the trait, with the self // type appearing first. let input_tys = Some(trait_ref.self_ty()); let input_tys = input_tys.iter().chain(trait_ref.substs.types.get_slice(TypeSpace).iter()); - let mut input_tys = input_tys; // Find the first input type that either references a type parameter OR // some local type. - match input_tys.find(|&&input_ty| references_local_or_type_parameter(tcx, input_ty)) { - Some(&input_ty) => { - // Within this first type, check that all type parameters are covered by a local - // type constructor. Note that if there is no local type constructor, then any - // type parameter at all will be an error. - let covered_params = type_parameters_covered_by_ty(tcx, input_ty); - let all_params = type_parameters_reachable_from_ty(input_ty); - for ¶m in all_params.difference(&covered_params) { - return Err(OrphanCheckErr::UncoveredTy(param)); + for input_ty in input_tys { + if ty_is_local(tcx, input_ty, param_is_local) { + debug!("orphan_check_trait_ref: ty_is_local `{}`", input_ty.repr(tcx)); + + // First local input type. Check that there are no + // uncovered type parameters. + let uncovered_tys = uncovered_tys(tcx, input_ty, param_is_local); + for uncovered_ty in uncovered_tys { + if let Some(param) = uncovered_ty.walk().find(|t| is_type_parameter(t)) { + debug!("orphan_check_trait_ref: uncovered type `{}`", param.repr(tcx)); + return Err(OrphanCheckErr::UncoveredTy(param)); + } } + + // OK, found local type, all prior types upheld invariant. + return Ok(()); } - None => { - return Err(OrphanCheckErr::NoLocalInputType); + + // Otherwise, enforce invariant that there are no type + // parameters reachable. + if !param_is_local.0 { + if let Some(param) = input_ty.walk().find(|t| is_type_parameter(t)) { + debug!("orphan_check_trait_ref: uncovered type `{}`", param.repr(tcx)); + return Err(OrphanCheckErr::UncoveredTy(param)); + } } } - return Ok(()); + // If we exit above loop, never found a local type. + debug!("orphan_check_trait_ref: no local type"); + return Err(OrphanCheckErr::NoLocalInputType); +} + +fn uncovered_tys<'tcx>(tcx: &ty::ctxt<'tcx>, + ty: Ty<'tcx>, + param_is_local: ParamIsLocal) + -> Vec> +{ + if ty_is_local_constructor(tcx, ty, param_is_local) { + vec![] + } else if fundamental_ty(tcx, ty) { + ty.walk_shallow() + .flat_map(|t| uncovered_tys(tcx, t, param_is_local).into_iter()) + .collect() + } else { + vec![ty] + } } -fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { +fn is_type_parameter<'tcx>(ty: Ty<'tcx>) -> bool { + match ty.sty { + // FIXME(#20590) straighten story about projection types + ty::ty_projection(..) | ty::ty_param(..) => true, + _ => false, + } +} + +fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>, param_is_local: ParamIsLocal) -> bool +{ + ty_is_local_constructor(tcx, ty, param_is_local) || + fundamental_ty(tcx, ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, param_is_local)) +} + +fn fundamental_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool +{ + match ty.sty { + ty::ty_uniq(..) | ty::ty_rptr(..) => + true, + ty::ty_enum(def_id, _) | ty::ty_struct(def_id, _) => + ty::has_attr(tcx, def_id, "fundamental"), + ty::ty_trait(ref data) => + ty::has_attr(tcx, data.principal_def_id(), "fundamental"), + _ => + false + } +} + +fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, + ty: Ty<'tcx>, + param_is_local: ParamIsLocal) + -> bool +{ debug!("ty_is_local_constructor({})", ty.repr(tcx)); match ty.sty { @@ -190,11 +310,15 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { ty::ty_ptr(..) | ty::ty_rptr(..) | ty::ty_tup(..) | - ty::ty_param(..) | + ty::ty_infer(..) | ty::ty_projection(..) => { false } + ty::ty_param(..) => { + param_is_local.0 + } + ty::ty_enum(def_id, _) | ty::ty_struct(def_id, _) => { def_id.krate == ast::LOCAL_CRATE @@ -210,7 +334,6 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { } ty::ty_closure(..) | - ty::ty_infer(..) | ty::ty_err => { tcx.sess.bug( &format!("ty_is_local invoked on unexpected type: {}", @@ -219,30 +342,4 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { } } -fn type_parameters_covered_by_ty<'tcx>(tcx: &ty::ctxt<'tcx>, - ty: Ty<'tcx>) - -> HashSet> -{ - if ty_is_local_constructor(tcx, ty) { - type_parameters_reachable_from_ty(ty) - } else { - ty.walk_children().flat_map(|t| type_parameters_covered_by_ty(tcx, t).into_iter()).collect() - } -} - -/// All type parameters reachable from `ty` -fn type_parameters_reachable_from_ty<'tcx>(ty: Ty<'tcx>) -> HashSet> { - ty.walk().filter(|&t| is_type_parameter(t)).collect() -} - -fn references_local_or_type_parameter<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { - ty.walk().any(|ty| is_type_parameter(ty) || ty_is_local_constructor(tcx, ty)) -} -fn is_type_parameter<'tcx>(ty: Ty<'tcx>) -> bool { - match ty.sty { - // FIXME(#20590) straighten story about projection types - ty::ty_projection(..) | ty::ty_param(..) => true, - _ => false, - } -} diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 9e4f63dca4565..cb9d90744a446 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -17,6 +17,7 @@ use self::SelectionCandidate::*; use self::BuiltinBoundConditions::*; use self::EvaluationResult::*; +use super::coherence; use super::DerivedObligationCause; use super::project; use super::project::{normalize_with_depth, Normalized}; @@ -81,7 +82,7 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> { /// selection-context's freshener. Used to check for recursion. fresh_trait_ref: ty::PolyTraitRef<'tcx>, - previous: Option<&'prev TraitObligationStack<'prev, 'tcx>> + previous: TraitObligationStackList<'prev, 'tcx>, } #[derive(Clone)] @@ -245,7 +246,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!("select({})", obligation.repr(self.tcx())); assert!(!obligation.predicate.has_escaping_regions()); - let stack = self.push_stack(None, obligation); + let stack = self.push_stack(TraitObligationStackList::empty(), obligation); match try!(self.candidate_from_obligation(&stack)) { None => { self.consider_unification_despite_ambiguity(obligation); @@ -327,7 +328,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!("evaluate_obligation({})", obligation.repr(self.tcx())); - self.evaluate_predicate_recursively(None, obligation).may_apply() + self.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation) + .may_apply() } fn evaluate_builtin_bound_recursively<'o>(&mut self, @@ -346,7 +348,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match obligation { Ok(obligation) => { - self.evaluate_predicate_recursively(Some(previous_stack), &obligation) + self.evaluate_predicate_recursively(previous_stack.list(), &obligation) } Err(ErrorReported) => { EvaluatedToOk @@ -355,7 +357,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn evaluate_predicates_recursively<'a,'o,I>(&mut self, - stack: Option<&TraitObligationStack<'o, 'tcx>>, + stack: TraitObligationStackList<'o, 'tcx>, predicates: I) -> EvaluationResult<'tcx> where I : Iterator>, 'tcx:'a @@ -372,7 +374,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn evaluate_predicate_recursively<'o>(&mut self, - previous_stack: Option<&TraitObligationStack<'o, 'tcx>>, + previous_stack: TraitObligationStackList<'o, 'tcx>, obligation: &PredicateObligation<'tcx>) -> EvaluationResult<'tcx> { @@ -423,14 +425,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn evaluate_obligation_recursively<'o>(&mut self, - previous_stack: Option<&TraitObligationStack<'o, 'tcx>>, + previous_stack: TraitObligationStackList<'o, 'tcx>, obligation: &TraitObligation<'tcx>) -> EvaluationResult<'tcx> { debug!("evaluate_obligation_recursively({})", obligation.repr(self.tcx())); - let stack = self.push_stack(previous_stack.map(|x| x), obligation); + let stack = self.push_stack(previous_stack, obligation); let result = self.evaluate_stack(&stack); @@ -538,7 +540,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth + 1, skol_map, snapshot); - self.winnow_selection(None, VtableImpl(vtable_impl)).may_apply() + self.winnow_selection(TraitObligationStackList::empty(), + VtableImpl(vtable_impl)).may_apply() } Err(()) => { false @@ -607,6 +610,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Ok(Some(ErrorCandidate)); } + if !self.is_knowable(stack) { + debug!("intercrate not knowable"); + return Ok(None); + } + let candidate_set = try!(self.assemble_candidates(stack)); if candidate_set.ambiguous { @@ -707,6 +715,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(Some(candidate)) } + fn is_knowable<'o>(&mut self, + stack: &TraitObligationStack<'o, 'tcx>) + -> bool + { + debug!("is_knowable(intercrate={})", self.intercrate); + + if !self.intercrate { + return true; + } + + let obligation = &stack.obligation; + let predicate = self.infcx().resolve_type_vars_if_possible(&obligation.predicate); + + // ok to skip binder because of the nature of the + // trait-ref-is-knowable check, which does not care about + // bound regions + let trait_ref = &predicate.skip_binder().trait_ref; + + coherence::trait_ref_is_knowable(self.tcx(), trait_ref) + } + fn pick_candidate_cache(&self) -> &SelectionCache<'tcx> { // If there are any where-clauses in scope, then we always use // a cache local to this particular scope. Otherwise, we @@ -1026,7 +1055,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx().probe(move |_| { match self.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { Ok(obligations) => { - self.evaluate_predicates_recursively(Some(stack), obligations.iter()) + self.evaluate_predicates_recursively(stack.list(), obligations.iter()) } Err(()) => { EvaluatedToErr(Unimplemented) @@ -1310,7 +1339,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let result = self.infcx.probe(|_| { let candidate = (*candidate).clone(); match self.confirm_candidate(stack.obligation, candidate) { - Ok(selection) => self.winnow_selection(Some(stack), selection), + Ok(selection) => self.winnow_selection(stack.list(), + selection), Err(error) => EvaluatedToErr(error), } }); @@ -1320,7 +1350,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn winnow_selection<'o>(&mut self, - stack: Option<&TraitObligationStack<'o, 'tcx>>, + stack: TraitObligationStackList<'o,'tcx>, selection: Selection<'tcx>) -> EvaluationResult<'tcx> { @@ -2303,9 +2333,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Err(()); } - let impl_substs = util::fresh_substs_for_impl(self.infcx, - obligation.cause.span, - impl_def_id); + let impl_substs = util::fresh_type_vars_for_impl(self.infcx, + obligation.cause.span, + impl_def_id); let impl_trait_ref = impl_trait_ref.subst(self.tcx(), &impl_substs); @@ -2423,9 +2453,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { { // Create fresh type variables for each type parameter declared // on the impl etc. - let impl_substs = util::fresh_substs_for_impl(self.infcx, - obligation_cause.span, - impl_def_id); + let impl_substs = util::fresh_type_vars_for_impl(self.infcx, + obligation_cause.span, + impl_def_id); // Find the self type for the impl. let impl_self_ty = ty::lookup_item_type(self.tcx(), impl_def_id).ty; @@ -2476,7 +2506,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Miscellany fn push_stack<'o,'s:'o>(&mut self, - previous_stack: Option<&'s TraitObligationStack<'s, 'tcx>>, + previous_stack: TraitObligationStackList<'s, 'tcx>, obligation: &'o TraitObligation<'tcx>) -> TraitObligationStack<'o, 'tcx> { @@ -2486,7 +2516,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { TraitObligationStack { obligation: obligation, fresh_trait_ref: fresh_trait_ref, - previous: previous_stack.map(|p| p), // FIXME variance + previous: previous_stack, } } @@ -2639,17 +2669,36 @@ impl<'tcx> SelectionCache<'tcx> { } } -impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> { - fn iter(&self) -> Option<&TraitObligationStack<'o, 'tcx>> { - Some(self) +impl<'o,'tcx> TraitObligationStack<'o,'tcx> { + fn list(&'o self) -> TraitObligationStackList<'o,'tcx> { + TraitObligationStackList::with(self) + } + + fn iter(&'o self) -> TraitObligationStackList<'o,'tcx> { + self.list() } } -impl<'o, 'tcx> Iterator for Option<&'o TraitObligationStack<'o, 'tcx>> { +#[derive(Copy, Clone)] +struct TraitObligationStackList<'o,'tcx:'o> { + head: Option<&'o TraitObligationStack<'o,'tcx>> +} + +impl<'o,'tcx> TraitObligationStackList<'o,'tcx> { + fn empty() -> TraitObligationStackList<'o,'tcx> { + TraitObligationStackList { head: None } + } + + fn with(r: &'o TraitObligationStack<'o,'tcx>) -> TraitObligationStackList<'o,'tcx> { + TraitObligationStackList { head: Some(r) } + } +} + +impl<'o,'tcx> Iterator for TraitObligationStackList<'o,'tcx>{ type Item = &'o TraitObligationStack<'o,'tcx>; - fn next(&mut self) -> Option<&'o TraitObligationStack<'o, 'tcx>> { - match *self { + fn next(&mut self) -> Option<&'o TraitObligationStack<'o,'tcx>> { + match self.head { Some(o) => { *self = o.previous; Some(o) @@ -2659,7 +2708,7 @@ impl<'o, 'tcx> Iterator for Option<&'o TraitObligationStack<'o, 'tcx>> { } } -impl<'o, 'tcx> Repr<'tcx> for TraitObligationStack<'o, 'tcx> { +impl<'o,'tcx> Repr<'tcx> for TraitObligationStack<'o,'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { format!("TraitObligationStack({})", self.obligation.repr(tcx)) diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 7c7db4a64c02e..297cea13207e5 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use middle::region; use middle::subst::{Substs, VecPerParamSpace}; use middle::infer::InferCtxt; use middle::ty::{self, Ty, AsPredicate, ToPolyTraitRef}; @@ -285,7 +286,6 @@ impl<'tcx,I:Iterator>> Iterator for FilterToTraits { } } - /////////////////////////////////////////////////////////////////////////// // Other /////////////////////////////////////////////////////////////////////////// @@ -294,16 +294,44 @@ impl<'tcx,I:Iterator>> Iterator for FilterToTraits { // declared on the impl declaration e.g., `impl for Box<[(A,B)]>` // would return ($0, $1) where $0 and $1 are freshly instantiated type // variables. -pub fn fresh_substs_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, - span: Span, - impl_def_id: ast::DefId) - -> Substs<'tcx> +pub fn fresh_type_vars_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + span: Span, + impl_def_id: ast::DefId) + -> Substs<'tcx> { let tcx = infcx.tcx; let impl_generics = ty::lookup_item_type(tcx, impl_def_id).generics; infcx.fresh_substs_for_generics(span, &impl_generics) } +// 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 +// variables. +pub fn free_substs_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + _span: Span, + impl_def_id: ast::DefId) + -> Substs<'tcx> +{ + let tcx = infcx.tcx; + let impl_generics = ty::lookup_item_type(tcx, impl_def_id).generics; + + let some_types = impl_generics.types.map(|def| { + ty::mk_param_from_def(tcx, def) + }); + + let some_regions = impl_generics.regions.map(|def| { + // FIXME. This destruction scope information is pretty darn + // bogus; after all, the impl might not even be in this crate! + // But given what we do in coherence, it is harmless enough + // for now I think. -nmatsakis + let extent = region::DestructionScopeData::new(ast::DUMMY_NODE_ID); + ty::free_region_from_def(extent, def) + }); + + Substs::new(some_types, some_regions) +} + impl<'tcx, N> fmt::Debug for VtableImplData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "VtableImpl({:?})", self.impl_def_id) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 6e81d14d73cad..0814ec2c84e70 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -58,7 +58,7 @@ use middle::subst::{self, ParamSpace, Subst, Substs, VecPerParamSpace}; use middle::traits; use middle::ty; use middle::ty_fold::{self, TypeFoldable, TypeFolder}; -use middle::ty_walk::TypeWalker; +use middle::ty_walk::{self, TypeWalker}; use util::ppaux::{note_and_explain_region, bound_region_ptr_to_string}; use util::ppaux::ty_to_string; use util::ppaux::{Repr, UserString}; @@ -89,7 +89,8 @@ use syntax::codemap::Span; use syntax::parse::token::{self, InternedString, special_idents}; use syntax::print::pprust; use syntax::ptr::P; -use syntax::{ast, ast_map}; +use syntax::ast; +use syntax::ast_map::{self, LinkedPath}; pub type Disr = u64; @@ -3167,21 +3168,11 @@ impl<'tcx> TyS<'tcx> { TypeWalker::new(self) } - /// Iterator that walks types reachable from `self`, in - /// depth-first order. Note that this is a shallow walk. For - /// example: - /// - /// ```notrust - /// isize => { } - /// Foo> => { Bar, isize } - /// [isize] => { isize } - /// ``` - pub fn walk_children(&'tcx self) -> TypeWalker<'tcx> { - // Walks type reachable from `self` but not `self - let mut walker = self.walk(); - let r = walker.next(); - assert_eq!(r, Some(self)); - walker + /// Iterator that walks the immediate children of `self`. Hence + /// `Foo, u32>` yields the sequence `[Bar, u32]` + /// (but not `i32`, like `walk`). + pub fn walk_shallow(&'tcx self) -> IntoIter> { + ty_walk::walk_shallow(self) } pub fn as_opt_param_ty(&self) -> Option { @@ -5484,7 +5475,7 @@ pub fn with_path(cx: &ctxt, id: ast::DefId, f: F) -> T where if id.krate == ast::LOCAL_CRATE { cx.map.with_path(id.node, f) } else { - f(csearch::get_item_path(cx, id).iter().cloned().chain(None)) + f(csearch::get_item_path(cx, id).iter().cloned().chain(LinkedPath::empty())) } } diff --git a/src/librustc/middle/ty_walk.rs b/src/librustc/middle/ty_walk.rs index 5d492f1c95e11..ec09d6dcc1ee2 100644 --- a/src/librustc/middle/ty_walk.rs +++ b/src/librustc/middle/ty_walk.rs @@ -12,6 +12,7 @@ use middle::ty::{self, Ty}; use std::iter::Iterator; +use std::vec::IntoIter; pub struct TypeWalker<'tcx> { stack: Vec>, @@ -23,60 +24,6 @@ impl<'tcx> TypeWalker<'tcx> { TypeWalker { stack: vec!(ty), last_subtree: 1, } } - fn push_subtypes(&mut self, parent_ty: Ty<'tcx>) { - match parent_ty.sty { - ty::ty_bool | ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) | - ty::ty_str | ty::ty_infer(_) | ty::ty_param(_) | ty::ty_err => { - } - ty::ty_uniq(ty) | ty::ty_vec(ty, _) => { - self.stack.push(ty); - } - ty::ty_ptr(ref mt) | ty::ty_rptr(_, ref mt) => { - self.stack.push(mt.ty); - } - ty::ty_projection(ref data) => { - self.push_reversed(data.trait_ref.substs.types.as_slice()); - } - ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => { - self.push_reversed(principal.substs().types.as_slice()); - self.push_reversed(&bounds.projection_bounds.iter().map(|pred| { - pred.0.ty - }).collect::>()); - } - ty::ty_enum(_, ref substs) | - ty::ty_struct(_, ref substs) | - ty::ty_closure(_, ref substs) => { - self.push_reversed(substs.types.as_slice()); - } - ty::ty_tup(ref ts) => { - self.push_reversed(ts); - } - ty::ty_bare_fn(_, ref ft) => { - self.push_sig_subtypes(&ft.sig); - } - } - } - - fn push_sig_subtypes(&mut self, sig: &ty::PolyFnSig<'tcx>) { - match sig.0.output { - ty::FnConverging(output) => { self.stack.push(output); } - ty::FnDiverging => { } - } - self.push_reversed(&sig.0.inputs); - } - - fn push_reversed(&mut self, tys: &[Ty<'tcx>]) { - // We push slices on the stack in reverse order so as to - // maintain a pre-order traversal. As of the time of this - // writing, the fact that the traversal is pre-order is not - // known to be significant to any code, but it seems like the - // natural order one would expect (basically, the order of the - // types as they are written). - for &ty in tys.iter().rev() { - self.stack.push(ty); - } - } - /// Skips the subtree of types corresponding to the last type /// returned by `next()`. /// @@ -105,10 +52,70 @@ impl<'tcx> Iterator for TypeWalker<'tcx> { } Some(ty) => { self.last_subtree = self.stack.len(); - self.push_subtypes(ty); + push_subtypes(&mut self.stack, ty); debug!("next: stack={:?}", self.stack); Some(ty) } } } } + +pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> IntoIter> { + let mut stack = vec![]; + push_subtypes(&mut stack, ty); + stack.into_iter() +} + +fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { + match parent_ty.sty { + ty::ty_bool | ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) | + ty::ty_str | ty::ty_infer(_) | ty::ty_param(_) | ty::ty_err => { + } + ty::ty_uniq(ty) | ty::ty_vec(ty, _) => { + stack.push(ty); + } + ty::ty_ptr(ref mt) | ty::ty_rptr(_, ref mt) => { + stack.push(mt.ty); + } + ty::ty_projection(ref data) => { + push_reversed(stack, data.trait_ref.substs.types.as_slice()); + } + ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => { + push_reversed(stack, principal.substs().types.as_slice()); + push_reversed(stack, &bounds.projection_bounds.iter().map(|pred| { + pred.0.ty + }).collect::>()); + } + ty::ty_enum(_, ref substs) | + ty::ty_struct(_, ref substs) | + ty::ty_closure(_, ref substs) => { + push_reversed(stack, substs.types.as_slice()); + } + ty::ty_tup(ref ts) => { + push_reversed(stack, ts); + } + ty::ty_bare_fn(_, ref ft) => { + push_sig_subtypes(stack, &ft.sig); + } + } +} + +fn push_sig_subtypes<'tcx>(stack: &mut Vec>, sig: &ty::PolyFnSig<'tcx>) { + match sig.0.output { + ty::FnConverging(output) => { stack.push(output); } + ty::FnDiverging => { } + } + push_reversed(stack, &sig.0.inputs); +} + +fn push_reversed<'tcx>(stack: &mut Vec>, tys: &[Ty<'tcx>]) { + // We push slices on the stack in reverse order so as to + // maintain a pre-order traversal. As of the time of this + // writing, the fact that the traversal is pre-order is not + // known to be significant to any code, but it seems like the + // natural order one would expect (basically, the order of the + // types as they are written). + for &ty in tys.iter().rev() { + stack.push(ty); + } +} diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 452589a240754..4405a9d75ee62 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -384,13 +384,7 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { } ty_infer(infer_ty) => infer_ty_to_string(cx, infer_ty), ty_err => "[type error]".to_string(), - ty_param(ref param_ty) => { - if cx.sess.verbose() { - param_ty.repr(cx) - } else { - param_ty.user_string(cx) - } - } + ty_param(ref param_ty) => param_ty.user_string(cx), ty_enum(did, substs) | ty_struct(did, substs) => { let base = ty::item_path_str(cx, did); parameterized(cx, &base, substs, did, &[], diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index f88381fb36f86..113827a3b402f 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -91,6 +91,8 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ ("start", "1.0.0", Active), ("main", "1.0.0", Active), + ("fundamental", "1.0.0", Active), + // Deprecate after snapshot // SNAP 5520801 ("unsafe_destructor", "1.0.0", Active), @@ -237,6 +239,10 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ ("allow_internal_unstable", Gated("allow_internal_unstable", EXPLAIN_ALLOW_INTERNAL_UNSTABLE)), + ("fundamental", Gated("fundamental", + "the `#[fundamental]` attribute \ + is an experimental feature")), + // FIXME: #14408 whitelist docs since rustdoc looks at them ("doc", Whitelisted), From 35c261aea0d891d31b3fda83da653cb1e385681f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 30 Mar 2015 17:52:00 -0400 Subject: [PATCH 2/6] Add `#[fundamental]` annotations into libcore so that `Sized` and the `Fn` traits are considered fundamental, along with `Box` (though that is mostly for show; the real type is `~T` in the compiler). --- src/liballoc/boxed.rs | 1 + src/liballoc/lib.rs | 2 ++ src/libcore/lib.rs | 2 ++ src/libcore/marker.rs | 1 + src/libcore/ops.rs | 3 +++ 5 files changed, 9 insertions(+) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 550b25ac3a7cf..adfe0f461bea3 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -86,6 +86,7 @@ pub static HEAP: () = (); /// See the [module-level documentation](../../std/boxed/index.html) for more. #[lang = "owned_box"] #[stable(feature = "rust1", since = "1.0.0")] +#[fundamental] pub struct Box(Unique); impl Box { diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index b92dfa9117e6b..a8be63d637359 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -71,6 +71,8 @@ #![feature(no_std)] #![no_std] #![feature(allocator)] +#![feature(custom_attribute)] +#![feature(fundamental)] #![feature(lang_items, unsafe_destructor)] #![feature(box_syntax)] #![feature(optin_builtin_traits)] diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 5e8b7fba1f15c..3a9af50fefbc7 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -70,8 +70,10 @@ #![feature(unboxed_closures)] #![feature(rustc_attrs)] #![feature(optin_builtin_traits)] +#![feature(fundamental)] #![feature(concat_idents)] #![feature(reflect)] +#![feature(custom_attribute)] #[macro_use] mod macros; diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index f755c912fcd4a..97bde9fc96eec 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -49,6 +49,7 @@ impl !Send for Managed { } #[stable(feature = "rust1", since = "1.0.0")] #[lang="sized"] #[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"] +#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable pub trait Sized : MarkerTrait { // Empty. } diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 862eb16d0bfb3..399aec9afd440 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -1117,6 +1117,7 @@ impl<'a, T: ?Sized> DerefMut for &'a mut T { #[lang="fn"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_paren_sugar] +#[fundamental] // so that regex can rely that `&str: !FnMut` pub trait Fn : FnMut { /// This is called when the call operator is used. extern "rust-call" fn call(&self, args: Args) -> Self::Output; @@ -1126,6 +1127,7 @@ pub trait Fn : FnMut { #[lang="fn_mut"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_paren_sugar] +#[fundamental] // so that regex can rely that `&str: !FnMut` pub trait FnMut : FnOnce { /// This is called when the call operator is used. extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; @@ -1135,6 +1137,7 @@ pub trait FnMut : FnOnce { #[lang="fn_once"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_paren_sugar] +#[fundamental] // so that regex can rely that `&str: !FnMut` pub trait FnOnce { /// The returned type after the call operator is used. type Output; From b0af587b64786b45ac9651ee4608e1edbd53a733 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 30 Mar 2015 17:49:30 -0400 Subject: [PATCH 3/6] Update tests for new coherence rules, and add a swatch of new tests probing the specifics of `Fundamental`. Fixes #23086. Fixes #23516. --- src/test/auxiliary/coherence_copy_like_lib.rs | 22 ++++++++++++ .../coherence-cow-1.rs | 9 +++-- .../coherence-cow-2.rs | 8 +++-- .../compile-fail/coherence-cow-no-cover.rs | 4 +-- src/test/compile-fail/coherence-impls-copy.rs | 7 ++++ src/test/compile-fail/coherence-impls-send.rs | 8 ++--- .../compile-fail/coherence-impls-sized.rs | 11 ++++-- .../coherence-overlap-issue-23516.rs | 19 ++++++++++ .../coherence-vec-local-2.rs} | 5 ++- .../coherence-vec-local.rs} | 5 ++- ...erence_copy_like_err_fundamental_struct.rs | 36 +++++++++++++++++++ ...ce_copy_like_err_fundamental_struct_ref.rs | 36 +++++++++++++++++++ ..._copy_like_err_fundamental_struct_tuple.rs | 32 +++++++++++++++++ .../coherence_copy_like_err_struct.rs | 33 +++++++++++++++++ .../coherence_copy_like_err_tuple.rs | 32 +++++++++++++++++ src/test/compile-fail/coherence_local.rs | 33 +++++++++++++++++ .../coherence_local_err_struct.rs | 29 +++++++++++++++ .../compile-fail/coherence_local_err_tuple.rs | 29 +++++++++++++++ src/test/compile-fail/coherence_local_ref.rs | 27 ++++++++++++++ ...efault-trait-impl-cross-crate-coherence.rs | 6 ++-- src/test/run-pass/coherence_copy_like.rs | 29 +++++++++++++++ .../method-two-trait-defer-resolution-2.rs | 31 +++++++++------- .../run-pass/traits-conditional-dispatch.rs | 16 ++++++--- 23 files changed, 431 insertions(+), 36 deletions(-) create mode 100644 src/test/auxiliary/coherence_copy_like_lib.rs rename src/test/{run-pass => compile-fail}/coherence-cow-1.rs (71%) rename src/test/{run-pass => compile-fail}/coherence-cow-2.rs (67%) create mode 100644 src/test/compile-fail/coherence-overlap-issue-23516.rs rename src/test/{run-pass/coherence-local-2.rs => compile-fail/coherence-vec-local-2.rs} (77%) rename src/test/{run-pass/coherence-local-1.rs => compile-fail/coherence-vec-local.rs} (76%) create mode 100644 src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs create mode 100644 src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs create mode 100644 src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs create mode 100644 src/test/compile-fail/coherence_copy_like_err_struct.rs create mode 100644 src/test/compile-fail/coherence_copy_like_err_tuple.rs create mode 100644 src/test/compile-fail/coherence_local.rs create mode 100644 src/test/compile-fail/coherence_local_err_struct.rs create mode 100644 src/test/compile-fail/coherence_local_err_tuple.rs create mode 100644 src/test/compile-fail/coherence_local_ref.rs create mode 100644 src/test/run-pass/coherence_copy_like.rs diff --git a/src/test/auxiliary/coherence_copy_like_lib.rs b/src/test/auxiliary/coherence_copy_like_lib.rs new file mode 100644 index 0000000000000..a1e1b48c2c4e9 --- /dev/null +++ b/src/test/auxiliary/coherence_copy_like_lib.rs @@ -0,0 +1,22 @@ +// Copyright 2015 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. + +#![crate_type = "rlib"] +#![feature(fundamental)] + +use std::marker::MarkerTrait; + +pub trait MyCopy : MarkerTrait { } +impl MyCopy for i32 { } + +pub struct MyStruct(T); + +#[fundamental] +pub struct MyFundamentalStruct(T); diff --git a/src/test/run-pass/coherence-cow-1.rs b/src/test/compile-fail/coherence-cow-1.rs similarity index 71% rename from src/test/run-pass/coherence-cow-1.rs rename to src/test/compile-fail/coherence-cow-1.rs index 31f6c9af02024..530bbf57d9104 100644 --- a/src/test/run-pass/coherence-cow-1.rs +++ b/src/test/compile-fail/coherence-cow-1.rs @@ -10,16 +10,19 @@ // aux-build:coherence_lib.rs -// Test that it's ok for T to appear first in the self-type, as long -// as it's covered somewhere. - // pretty-expanded FIXME #23616 +// Test that the `Pair` type reports an error if it contains type +// parameters, even when they are covered by local types. This test +// was originally intended to test the opposite, but the rules changed +// with RFC 1023 and this became illegal. + extern crate coherence_lib as lib; use lib::{Remote,Pair}; pub struct Cover(T); impl Remote for Pair> { } +//~^ ERROR E0210 fn main() { } diff --git a/src/test/run-pass/coherence-cow-2.rs b/src/test/compile-fail/coherence-cow-2.rs similarity index 67% rename from src/test/run-pass/coherence-cow-2.rs rename to src/test/compile-fail/coherence-cow-2.rs index ccda8440ea228..52abceab98b69 100644 --- a/src/test/run-pass/coherence-cow-2.rs +++ b/src/test/compile-fail/coherence-cow-2.rs @@ -10,8 +10,10 @@ // aux-build:coherence_lib.rs -// Test that it's ok for T to appear second in the self-type, as long -// as it's covered somewhere. +// Test that the `Pair` type reports an error if it contains type +// parameters, even when they are covered by local types. This test +// was originally intended to test the opposite, but the rules changed +// with RFC 1023 and this became illegal. // pretty-expanded FIXME #23616 @@ -20,6 +22,6 @@ use lib::{Remote,Pair}; pub struct Cover(T); -impl Remote for Pair,T> { } +impl Remote for Pair,T> { } //~ ERROR E0210 fn main() { } diff --git a/src/test/compile-fail/coherence-cow-no-cover.rs b/src/test/compile-fail/coherence-cow-no-cover.rs index 475d7df1fdb4f..cd32e797ae9bf 100644 --- a/src/test/compile-fail/coherence-cow-no-cover.rs +++ b/src/test/compile-fail/coherence-cow-no-cover.rs @@ -10,7 +10,7 @@ // aux-build:coherence_lib.rs -// Test that it's not ok for U to appear uncovered +// Test that it's not ok for T to appear uncovered extern crate coherence_lib as lib; use lib::{Remote,Pair}; @@ -18,6 +18,6 @@ use lib::{Remote,Pair}; pub struct Cover(T); impl Remote for Pair,U> { } -//~^ ERROR type parameter `U` must be used as the type parameter for some local type +//~^ ERROR type parameter `T` must be used as the type parameter for some local type fn main() { } diff --git a/src/test/compile-fail/coherence-impls-copy.rs b/src/test/compile-fail/coherence-impls-copy.rs index 3034be177ca68..b99b2e1205b9b 100644 --- a/src/test/compile-fail/coherence-impls-copy.rs +++ b/src/test/compile-fail/coherence-impls-copy.rs @@ -23,17 +23,24 @@ impl !Sync for NotSync {} impl Copy for TestE {} impl Copy for MyType {} + +impl Copy for &'static mut MyType {} +//~^ ERROR E0206 + impl Copy for (MyType, MyType) {} //~^ ERROR E0206 +//~| ERROR E0117 impl Copy for &'static NotSync {} //~^ ERROR E0206 impl Copy for [MyType] {} //~^ ERROR E0206 +//~| ERROR E0117 impl Copy for &'static [NotSync] {} //~^ ERROR E0206 +//~| ERROR E0117 fn main() { } diff --git a/src/test/compile-fail/coherence-impls-send.rs b/src/test/compile-fail/coherence-impls-send.rs index b05c1ff0f0b72..f130a9353516f 100644 --- a/src/test/compile-fail/coherence-impls-send.rs +++ b/src/test/compile-fail/coherence-impls-send.rs @@ -24,17 +24,17 @@ impl !Sync for NotSync {} unsafe impl Send for TestE {} unsafe impl Send for MyType {} unsafe impl Send for (MyType, MyType) {} -//~^ ERROR E0321 +//~^ ERROR E0117 unsafe impl Send for &'static NotSync {} //~^ ERROR E0321 unsafe impl Send for [MyType] {} -//~^ ERROR E0321 +//~^ ERROR E0117 unsafe impl Send for &'static [NotSync] {} -//~^ ERROR E0321 -//~| ERROR conflicting implementations +//~^ ERROR E0117 +//~| ERROR E0119 fn main() { } diff --git a/src/test/compile-fail/coherence-impls-sized.rs b/src/test/compile-fail/coherence-impls-sized.rs index a9a3ebaffb75a..2ac4bb0492b1f 100644 --- a/src/test/compile-fail/coherence-impls-sized.rs +++ b/src/test/compile-fail/coherence-impls-sized.rs @@ -22,12 +22,17 @@ struct NotSync; impl !Sync for NotSync {} impl Sized for TestE {} //~ ERROR E0322 + impl Sized for MyType {} //~ ERROR E0322 -impl Sized for (MyType, MyType) {} //~ ERROR E0322 + +impl Sized for (MyType, MyType) {} //~ ERROR E0117 + impl Sized for &'static NotSync {} //~ ERROR E0322 -impl Sized for [MyType] {} //~ ERROR E0322 + +impl Sized for [MyType] {} //~ ERROR E0117 //~^ ERROR E0277 -impl Sized for &'static [NotSync] {} //~ ERROR E0322 + +impl Sized for &'static [NotSync] {} //~ ERROR E0117 fn main() { } diff --git a/src/test/compile-fail/coherence-overlap-issue-23516.rs b/src/test/compile-fail/coherence-overlap-issue-23516.rs new file mode 100644 index 0000000000000..d7f060a3bfe73 --- /dev/null +++ b/src/test/compile-fail/coherence-overlap-issue-23516.rs @@ -0,0 +1,19 @@ +// Copyright 2015 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. + +// Tests that we consider `Box: !Sugar` to be ambiguous, even +// though we see no impl of `Sugar` for `Box`. Therefore, an overlap +// error is reported for the following pair of impls (#23516). + +pub trait Sugar { fn dummy(&self) { } } +pub trait Sweet { fn dummy(&self) { } } +impl Sweet for T { } //~ ERROR E0119 +impl Sweet for Box { } +fn main() { } diff --git a/src/test/run-pass/coherence-local-2.rs b/src/test/compile-fail/coherence-vec-local-2.rs similarity index 77% rename from src/test/run-pass/coherence-local-2.rs rename to src/test/compile-fail/coherence-vec-local-2.rs index 5fd3e8ca86ef7..5f0b56af2c226 100644 --- a/src/test/run-pass/coherence-local-2.rs +++ b/src/test/compile-fail/coherence-vec-local-2.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Test that a local, generic type appearing within a +// *non-fundamental* remote type like `Vec` is not considered local. + // aux-build:coherence_lib.rs // pretty-expanded FIXME #23616 @@ -17,6 +20,6 @@ use lib::Remote; struct Local(T); -impl Remote for Vec> { } +impl Remote for Vec> { } //~ ERROR E0210 fn main() { } diff --git a/src/test/run-pass/coherence-local-1.rs b/src/test/compile-fail/coherence-vec-local.rs similarity index 76% rename from src/test/run-pass/coherence-local-1.rs rename to src/test/compile-fail/coherence-vec-local.rs index 21faa30245d9a..c354caac2b5c2 100644 --- a/src/test/run-pass/coherence-local-1.rs +++ b/src/test/compile-fail/coherence-vec-local.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Test that a local type (with no type parameters) appearing within a +// *non-fundamental* remote type like `Vec` is not considered local. + // aux-build:coherence_lib.rs // pretty-expanded FIXME #23616 @@ -17,6 +20,6 @@ use lib::Remote; struct Local; -impl Remote for Vec { } +impl Remote for Vec { } //~ ERROR E0117 fn main() { } diff --git a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs new file mode 100644 index 0000000000000..f13175ce8e2a4 --- /dev/null +++ b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs @@ -0,0 +1,36 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +extern crate coherence_copy_like_lib as lib; + +use std::marker::MarkerTrait; + +struct MyType { x: i32 } + +trait MyTrait : MarkerTrait { } +impl MyTrait for T { } + +// `MyFundamentalStruct` is declared fundamental, so we can test that +// +// MyFundamentalStruct: !MyTrait +// +// Huzzah. +impl MyTrait for lib::MyFundamentalStruct { } + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs new file mode 100644 index 0000000000000..ae3d242af705e --- /dev/null +++ b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs @@ -0,0 +1,36 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +extern crate coherence_copy_like_lib as lib; + +use std::marker::MarkerTrait; + +struct MyType { x: i32 } + +trait MyTrait : MarkerTrait { } +impl MyTrait for T { } + +// `MyFundamentalStruct` is declared fundamental, so we can test that +// +// MyFundamentalStruct<&MyTrait>: !MyTrait +// +// Huzzah. +impl<'a> MyTrait for lib::MyFundamentalStruct<&'a MyType> { } + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs new file mode 100644 index 0000000000000..c4e95e772356a --- /dev/null +++ b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs @@ -0,0 +1,32 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +#![feature(rustc_attrs)] + +extern crate coherence_copy_like_lib as lib; + +use std::marker::MarkerTrait; + +struct MyType { x: i32 } + +trait MyTrait : MarkerTrait { } + +impl MyTrait for T { } //~ ERROR E0119 + +// Tuples are not fundamental. +impl MyTrait for lib::MyFundamentalStruct<(MyType,)> { } + +#[rustc_error] +fn main() { } diff --git a/src/test/compile-fail/coherence_copy_like_err_struct.rs b/src/test/compile-fail/coherence_copy_like_err_struct.rs new file mode 100644 index 0000000000000..f768a475ee820 --- /dev/null +++ b/src/test/compile-fail/coherence_copy_like_err_struct.rs @@ -0,0 +1,33 @@ +// Copyright 2015 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. + +// aux-build:coherence_copy_like_lib.rs + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +extern crate coherence_copy_like_lib as lib; + +use std::marker::MarkerTrait; + +struct MyType { x: i32 } + +trait MyTrait : MarkerTrait { } +impl MyTrait for T { } //~ ERROR E0119 + +// `MyStruct` is not declared fundamental, therefore this would +// require that +// +// MyStruct: !MyTrait +// +// which we cannot approve. +impl MyTrait for lib::MyStruct { } + +fn main() { } diff --git a/src/test/compile-fail/coherence_copy_like_err_tuple.rs b/src/test/compile-fail/coherence_copy_like_err_tuple.rs new file mode 100644 index 0000000000000..0c78fffd2dfab --- /dev/null +++ b/src/test/compile-fail/coherence_copy_like_err_tuple.rs @@ -0,0 +1,32 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +extern crate coherence_copy_like_lib as lib; + +use std::marker::MarkerTrait; + +struct MyType { x: i32 } + +trait MyTrait : MarkerTrait { } +impl MyTrait for T { } //~ ERROR E0119 + +// Tuples are not fundamental, therefore this would require that +// +// (MyType,): !MyTrait +// +// which we cannot approve. +impl MyTrait for (MyType,) { } + +fn main() { } diff --git a/src/test/compile-fail/coherence_local.rs b/src/test/compile-fail/coherence_local.rs new file mode 100644 index 0000000000000..551577b6b4e08 --- /dev/null +++ b/src/test/compile-fail/coherence_local.rs @@ -0,0 +1,33 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +extern crate coherence_copy_like_lib as lib; + +struct MyType { x: i32 } + +// These are all legal because they are all fundamental types: + +impl lib::MyCopy for MyType { } +impl<'a> lib::MyCopy for &'a MyType { } +impl<'a> lib::MyCopy for &'a Box { } +impl lib::MyCopy for Box { } +impl lib::MyCopy for lib::MyFundamentalStruct { } +impl lib::MyCopy for lib::MyFundamentalStruct> { } + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/coherence_local_err_struct.rs b/src/test/compile-fail/coherence_local_err_struct.rs new file mode 100644 index 0000000000000..01f4c1cd8a5c9 --- /dev/null +++ b/src/test/compile-fail/coherence_local_err_struct.rs @@ -0,0 +1,29 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +extern crate coherence_copy_like_lib as lib; + +struct MyType { x: i32 } + +// These are all legal because they are all fundamental types: + +// MyStruct is not fundamental. +impl lib::MyCopy for lib::MyStruct { } //~ ERROR E0117 + +#[rustc_error] +fn main() { } diff --git a/src/test/compile-fail/coherence_local_err_tuple.rs b/src/test/compile-fail/coherence_local_err_tuple.rs new file mode 100644 index 0000000000000..590f68cee59ef --- /dev/null +++ b/src/test/compile-fail/coherence_local_err_tuple.rs @@ -0,0 +1,29 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +extern crate coherence_copy_like_lib as lib; + +struct MyType { x: i32 } + +// These are all legal because they are all fundamental types: + +// Tuples are not fundamental, so this is not a local impl. +impl lib::MyCopy for (MyType,) { } //~ ERROR E0117 + +#[rustc_error] +fn main() { } diff --git a/src/test/compile-fail/coherence_local_ref.rs b/src/test/compile-fail/coherence_local_ref.rs new file mode 100644 index 0000000000000..f6e1aab59766a --- /dev/null +++ b/src/test/compile-fail/coherence_local_ref.rs @@ -0,0 +1,27 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +extern crate coherence_copy_like_lib as lib; + +struct MyType { x: i32 } + +// naturally, legal +impl lib::MyCopy for MyType { } + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/typeck-default-trait-impl-cross-crate-coherence.rs b/src/test/compile-fail/typeck-default-trait-impl-cross-crate-coherence.rs index 7d25c04882f24..b1febae768036 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-cross-crate-coherence.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-cross-crate-coherence.rs @@ -20,15 +20,15 @@ extern crate typeck_default_trait_impl_cross_crate_coherence_lib as lib; use lib::DefaultedTrait; struct A; -impl DefaultedTrait for (A,) { } //~ ERROR E0321 +impl DefaultedTrait for (A,) { } //~ ERROR E0117 struct B; -impl !DefaultedTrait for (B,) { } //~ ERROR E0321 +impl !DefaultedTrait for (B,) { } //~ ERROR E0117 struct C; struct D(T); impl DefaultedTrait for Box { } //~ ERROR E0321 -impl DefaultedTrait for lib::Something { } //~ ERROR E0321 +impl DefaultedTrait for lib::Something { } //~ ERROR E0117 impl DefaultedTrait for D { } // OK fn main() { } diff --git a/src/test/run-pass/coherence_copy_like.rs b/src/test/run-pass/coherence_copy_like.rs new file mode 100644 index 0000000000000..db9893613ad11 --- /dev/null +++ b/src/test/run-pass/coherence_copy_like.rs @@ -0,0 +1,29 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +extern crate coherence_copy_like_lib as lib; + +use std::marker::MarkerTrait; + +struct MyType { x: i32 } + +trait MyTrait : MarkerTrait { } +impl MyTrait for T { } +impl MyTrait for MyType { } +impl<'a> MyTrait for &'a MyType { } +impl MyTrait for Box { } +impl<'a> MyTrait for &'a Box { } + +fn main() { } diff --git a/src/test/run-pass/method-two-trait-defer-resolution-2.rs b/src/test/run-pass/method-two-trait-defer-resolution-2.rs index d87ed03e94e01..2ceff22adb9eb 100644 --- a/src/test/run-pass/method-two-trait-defer-resolution-2.rs +++ b/src/test/run-pass/method-two-trait-defer-resolution-2.rs @@ -8,13 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test that we pick which version of `Foo` to run based on whether -// the type we (ultimately) inferred for `x` is copyable or not. -// -// In this case, the two versions are both impls of same trait, and -// hence we we can resolve method even without knowing yet which -// version will run (note that the `push` occurs after the call to -// `foo()`). +// Test that when we write `x.foo()`, we do nothave to know the +// complete type of `x` in order to type-check the method call. In +// this case, we know that `x: Vec<_1>`, but we don't know what type +// `_1` is (because the call to `push` comes later). To pick between +// the impls, we would have to know `_1`, since we have to know +// whether `_1: MyCopy` or `_1 == Box`. However (and this is the +// point of the test), we don't have to pick between the two impls -- +// it is enough to know that `foo` comes from the `Foo` trait. We can +// translate the call as `Foo::foo(&x)` and let the specific impl get +// chosen later. // pretty-expanded FIXME #23616 @@ -25,25 +28,29 @@ trait Foo { fn foo(&self) -> isize; } -impl Foo for Vec { +trait MyCopy { fn foo(&self) { } } +impl MyCopy for i32 { } + +impl Foo for Vec { fn foo(&self) -> isize {1} } -impl Foo for Vec> { +impl Foo for Vec> { fn foo(&self) -> isize {2} } fn call_foo_copy() -> isize { let mut x = Vec::new(); let y = x.foo(); - x.push(0_usize); + x.push(0_i32); y } fn call_foo_other() -> isize { - let mut x: Vec> = Vec::new(); + let mut x: Vec<_> = Vec::new(); let y = x.foo(); - x.push(box 0); + let z: Box = box 0; + x.push(z); y } diff --git a/src/test/run-pass/traits-conditional-dispatch.rs b/src/test/run-pass/traits-conditional-dispatch.rs index 5edd3dfbc9ef5..0190b7b7b9628 100644 --- a/src/test/run-pass/traits-conditional-dispatch.rs +++ b/src/test/run-pass/traits-conditional-dispatch.rs @@ -17,16 +17,24 @@ #![allow(unknown_features)] #![feature(box_syntax)] +use std::marker::MarkerTrait; + trait Get { fn get(&self) -> Self; } -impl Get for T { - fn get(&self) -> T { *self } +trait MyCopy : MarkerTrait { fn copy(&self) -> Self; } +impl MyCopy for u16 { fn copy(&self) -> Self { *self } } +impl MyCopy for u32 { fn copy(&self) -> Self { *self } } +impl MyCopy for i32 { fn copy(&self) -> Self { *self } } +impl MyCopy for Option { fn copy(&self) -> Self { *self } } + +impl Get for T { + fn get(&self) -> T { self.copy() } } -impl Get for Box { - fn get(&self) -> Box { box get_it(&**self) } +impl Get for Box { + fn get(&self) -> Box { box get_it(&**self) } } fn get_it(t: &T) -> T { From 30b2d9e7643de3a267029c2763edb0b44ff2396e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 30 Mar 2015 17:50:31 -0400 Subject: [PATCH 4/6] Fallout in libstd: remove impls now considered to conflict. --- src/liballoc/boxed.rs | 7 ------- src/liballoc/boxed_test.rs | 8 ++++---- src/libcore/any.rs | 8 ++++++++ src/libcore/fmt/mod.rs | 6 ------ 4 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index adfe0f461bea3..c4541e34cdb35 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -278,13 +278,6 @@ impl fmt::Debug for Box { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Box { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("Box") - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl Deref for Box { type Target = T; diff --git a/src/liballoc/boxed_test.rs b/src/liballoc/boxed_test.rs index 682d5f407c4ea..fc44ac4eac628 100644 --- a/src/liballoc/boxed_test.rs +++ b/src/liballoc/boxed_test.rs @@ -55,17 +55,17 @@ fn test_show() { let b = Box::new(Test) as Box; let a_str = format!("{:?}", a); let b_str = format!("{:?}", b); - assert_eq!(a_str, "Box"); - assert_eq!(b_str, "Box"); + assert_eq!(a_str, "Any"); + assert_eq!(b_str, "Any"); static EIGHT: usize = 8; static TEST: Test = Test; let a = &EIGHT as &Any; let b = &TEST as &Any; let s = format!("{:?}", a); - assert_eq!(s, "&Any"); + assert_eq!(s, "Any"); let s = format!("{:?}", b); - assert_eq!(s, "&Any"); + assert_eq!(s, "Any"); } #[test] diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 0ffc4a229b5ae..320fdd50b3510 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -71,6 +71,7 @@ #![stable(feature = "rust1", since = "1.0.0")] +use fmt; use marker::Send; use mem::transmute; use option::Option::{self, Some, None}; @@ -105,6 +106,13 @@ impl Any for T // Extension methods for Any trait objects. /////////////////////////////////////////////////////////////////////////////// +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Any { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Any") + } +} + impl Any { /// Returns true if the boxed type is the same as `T` #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index ffb358cdac84d..3f8bbeb1feb88 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -12,7 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use any; use cell::{Cell, RefCell, Ref, RefMut, BorrowState}; use char::CharExt; use iter::Iterator; @@ -997,11 +996,6 @@ macro_rules! tuple { tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, } -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Debug for &'a (any::Any+'a) { - fn fmt(&self, f: &mut Formatter) -> Result { f.pad("&Any") } -} - #[stable(feature = "rust1", since = "1.0.0")] impl Debug for [T] { fn fmt(&self, f: &mut Formatter) -> Result { From 15b58fedcacba7d10a9f7d460a83da645a09ad3e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 30 Mar 2015 17:51:26 -0400 Subject: [PATCH 5/6] Fallout in libsyntax/librustc: use newtype'd options for linked lists, since `Option` is not fundamental and hence the old impls run afoul of the orphan rules. --- src/librustc/metadata/encoder.rs | 7 +++---- src/libsyntax/ast_map/mod.rs | 21 ++++++++++++++++----- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index a8f83bee7f682..862ced78c082c 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -34,8 +34,7 @@ use std::io::prelude::*; use std::io::{Cursor, SeekFrom}; use syntax::abi; use syntax::ast::{self, DefId, NodeId}; -use syntax::ast_map::{PathElem, PathElems}; -use syntax::ast_map; +use syntax::ast_map::{self, LinkedPath, PathElem, PathElems}; use syntax::ast_util::*; use syntax::ast_util; use syntax::attr; @@ -1513,7 +1512,7 @@ fn encode_info_for_items(ecx: &EncodeContext, &krate.module, &[], ast::CRATE_NODE_ID, - [].iter().cloned().chain(None), + [].iter().cloned().chain(LinkedPath::empty()), syntax::parse::token::special_idents::invalid, ast::Public); @@ -1874,7 +1873,7 @@ fn encode_misc_info(ecx: &EncodeContext, } // Encode reexports for the root module. - encode_reexports(ecx, rbml_w, 0, [].iter().cloned().chain(None)); + encode_reexports(ecx, rbml_w, 0, [].iter().cloned().chain(LinkedPath::empty())); rbml_w.end_tag(); rbml_w.end_tag(); diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index 48bb044cb1854..2b5cb7076f463 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -53,18 +53,29 @@ impl fmt::Display for PathElem { } #[derive(Clone)] -struct LinkedPathNode<'a> { +pub struct LinkedPathNode<'a> { node: PathElem, next: LinkedPath<'a>, } -type LinkedPath<'a> = Option<&'a LinkedPathNode<'a>>; +#[derive(Copy, Clone)] +pub struct LinkedPath<'a>(Option<&'a LinkedPathNode<'a>>); + +impl<'a> LinkedPath<'a> { + pub fn empty() -> LinkedPath<'a> { + LinkedPath(None) + } + + pub fn from(node: &'a LinkedPathNode) -> LinkedPath<'a> { + LinkedPath(Some(node)) + } +} impl<'a> Iterator for LinkedPath<'a> { type Item = PathElem; fn next(&mut self) -> Option { - match *self { + match self.0 { Some(node) => { *self = node.next; Some(node.node) @@ -384,7 +395,7 @@ impl<'ast> Map<'ast> { pub fn with_path(&self, id: NodeId, f: F) -> T where F: FnOnce(PathElems) -> T, { - self.with_path_next(id, None, f) + self.with_path_next(id, LinkedPath::empty(), f) } pub fn path_to_string(&self, id: NodeId) -> String { @@ -422,7 +433,7 @@ impl<'ast> Map<'ast> { _ => f([].iter().cloned().chain(next)) } } else { - self.with_path_next(parent, Some(&LinkedPathNode { + self.with_path_next(parent, LinkedPath::from(&LinkedPathNode { node: self.get_path_elem(id), next: next }), f) From 19d3dab31b1fca3abc3ba00173b9148bd70d24b0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 1 Apr 2015 15:25:47 -0400 Subject: [PATCH 6/6] Collect the definition of the `Error` trait into `libstd` for now. This sidesteps a coherence difficulty where `liballoc` had to prove that `&str: !Error`, which didn't involve any local types. --- src/liballoc/boxed.rs | 53 +----------- src/libcollections/string.rs | 11 --- src/libcore/error.rs | 56 ------------- src/libcore/lib.rs | 1 - src/libcore/num/mod.rs | 41 +++++----- src/libcore/str/mod.rs | 16 ---- src/libstd/error.rs | 152 +++++++++++++++++++++++++++++++++++ src/libstd/lib.rs | 2 +- 8 files changed, 175 insertions(+), 157 deletions(-) delete mode 100644 src/libcore/error.rs create mode 100644 src/libstd/error.rs diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index c4541e34cdb35..bbf5d7a6042f2 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -51,15 +51,12 @@ use core::prelude::*; use core::any::Any; use core::cmp::Ordering; use core::default::Default; -use core::error::Error; use core::fmt; use core::hash::{self, Hash}; use core::mem; use core::ops::{Deref, DerefMut}; -use core::ptr::{self, Unique}; -use core::raw::{TraitObject, Slice}; - -use heap; +use core::ptr::{Unique}; +use core::raw::{TraitObject}; /// A value that represents the heap. This is the default place that the `box` /// keyword allocates into when no place is supplied. @@ -303,49 +300,3 @@ impl DoubleEndedIterator for Box { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Box {} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, E: Error + 'a> From for Box { - fn from(err: E) -> Box { - Box::new(err) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, E: Error + Send + 'a> From for Box { - fn from(err: E) -> Box { - Box::new(err) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b> From<&'b str> for Box { - fn from(err: &'b str) -> Box { - #[derive(Debug)] - struct StringError(Box); - impl Error for StringError { - fn description(&self) -> &str { &self.0 } - } - impl fmt::Display for StringError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } - } - - // Unfortunately `String` is located in libcollections, so we construct - // a `Box` manually here. - unsafe { - let alloc = if err.len() == 0 { - 0 as *mut u8 - } else { - let ptr = heap::allocate(err.len(), 1); - if ptr.is_null() { ::oom(); } - ptr as *mut u8 - }; - ptr::copy(err.as_bytes().as_ptr(), alloc, err.len()); - Box::new(StringError(mem::transmute(Slice { - data: alloc, - len: err.len(), - }))) - } - } -} diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index d8d7ad9887a8c..7a7725320914f 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -17,7 +17,6 @@ use core::prelude::*; use core::default::Default; -use core::error::Error; use core::fmt; use core::hash; use core::iter::{IntoIterator, FromIterator}; @@ -723,11 +722,6 @@ impl fmt::Display for FromUtf8Error { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for FromUtf8Error { - fn description(&self) -> &str { "invalid utf-8" } -} - #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for FromUtf16Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -735,11 +729,6 @@ impl fmt::Display for FromUtf16Error { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for FromUtf16Error { - fn description(&self) -> &str { "invalid utf-16" } -} - #[stable(feature = "rust1", since = "1.0.0")] impl FromIterator for String { fn from_iter>(iter: I) -> String { diff --git a/src/libcore/error.rs b/src/libcore/error.rs deleted file mode 100644 index 24035b7d9a83b..0000000000000 --- a/src/libcore/error.rs +++ /dev/null @@ -1,56 +0,0 @@ -// 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. - -//! Traits for working with Errors. -//! -//! # The `Error` trait -//! -//! `Error` is a trait representing the basic expectations for error values, -//! i.e. values of type `E` in `Result`. At a minimum, errors must provide -//! a description, but they may optionally provide additional detail (via -//! `Display`) and cause chain information: -//! -//! ``` -//! use std::fmt::Display; -//! -//! trait Error: Display { -//! fn description(&self) -> &str; -//! -//! fn cause(&self) -> Option<&Error> { None } -//! } -//! ``` -//! -//! The `cause` method is generally used when errors cross "abstraction -//! boundaries", i.e. when a one module must report an error that is "caused" -//! by an error from a lower-level module. This setup makes it possible for the -//! high-level module to provide its own errors that do not commit to any -//! particular implementation, but also reveal some of its implementation for -//! debugging via `cause` chains. - -#![stable(feature = "rust1", since = "1.0.0")] - -use prelude::*; -use fmt::{Debug, Display}; - -/// Base functionality for all errors in Rust. -#[stable(feature = "rust1", since = "1.0.0")] -pub trait Error: Debug + Display { - /// A short description of the error. - /// - /// The description should not contain newlines or sentence-ending - /// punctuation, to facilitate embedding in larger user-facing - /// strings. - #[stable(feature = "rust1", since = "1.0.0")] - fn description(&self) -> &str; - - /// The lower-level cause of this error, if any. - #[stable(feature = "rust1", since = "1.0.0")] - fn cause(&self) -> Option<&Error> { None } -} diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 3a9af50fefbc7..2189e2c3ad1ba 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -147,7 +147,6 @@ pub mod slice; pub mod str; pub mod hash; pub mod fmt; -pub mod error; #[doc(primitive = "bool")] mod bool { diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index a4829ed96b353..7daa1a9f420b6 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -20,7 +20,6 @@ use self::wrapping::{OverflowingOps, WrappingOps}; use char::CharExt; use clone::Clone; use cmp::{PartialEq, Eq, PartialOrd, Ord}; -use error::Error; use fmt; use intrinsics; use iter::Iterator; @@ -2948,16 +2947,9 @@ enum IntErrorKind { Underflow, } -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for ParseIntError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.description().fmt(f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for ParseIntError { - fn description(&self) -> &str { +impl ParseIntError { + #[unstable(feature = "core", reason = "available through Error trait")] + pub fn description(&self) -> &str { match self.kind { IntErrorKind::Empty => "cannot parse integer from empty string", IntErrorKind::InvalidDigit => "invalid digit found in string", @@ -2967,6 +2959,13 @@ impl Error for ParseIntError { } } +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for ParseIntError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.description().fmt(f) + } +} + /// An error which can be returned when parsing a float. #[derive(Debug, Clone, PartialEq)] #[stable(feature = "rust1", since = "1.0.0")] @@ -2978,19 +2977,19 @@ enum FloatErrorKind { Invalid, } -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for ParseFloatError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.description().fmt(f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for ParseFloatError { - fn description(&self) -> &str { +impl ParseFloatError { + #[unstable(feature = "core", reason = "available through Error trait")] + pub fn description(&self) -> &str { match self.kind { FloatErrorKind::Empty => "cannot parse float from empty string", FloatErrorKind::Invalid => "invalid float literal", } } } + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for ParseFloatError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.description().fmt(f) + } +} diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 934c4515614ef..4c366d327187e 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -22,7 +22,6 @@ use char::CharExt; use clone::Clone; use cmp::{self, Eq}; use default::Default; -use error::Error; use fmt; use iter::ExactSizeIterator; use iter::{Map, Iterator, DoubleEndedIterator}; @@ -192,11 +191,6 @@ impl fmt::Display for ParseBoolError { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for ParseBoolError { - fn description(&self) -> &str { "failed to parse bool" } -} - /* Section: Creating a string */ @@ -241,16 +235,6 @@ pub unsafe fn from_utf8_unchecked<'a>(v: &'a [u8]) -> &'a str { mem::transmute(v) } -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for Utf8Error { - fn description(&self) -> &str { - match *self { - Utf8Error::TooShort => "invalid utf-8: not enough bytes", - Utf8Error::InvalidByte(..) => "invalid utf-8: corrupt contents", - } - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Utf8Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/libstd/error.rs b/src/libstd/error.rs new file mode 100644 index 0000000000000..150ffcdd77a9f --- /dev/null +++ b/src/libstd/error.rs @@ -0,0 +1,152 @@ +// 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. + +//! Traits for working with Errors. +//! +//! # The `Error` trait +//! +//! `Error` is a trait representing the basic expectations for error values, +//! i.e. values of type `E` in `Result`. At a minimum, errors must provide +//! a description, but they may optionally provide additional detail (via +//! `Display`) and cause chain information: +//! +//! ``` +//! use std::fmt::Display; +//! +//! trait Error: Display { +//! fn description(&self) -> &str; +//! +//! fn cause(&self) -> Option<&Error> { None } +//! } +//! ``` +//! +//! The `cause` method is generally used when errors cross "abstraction +//! boundaries", i.e. when a one module must report an error that is "caused" +//! by an error from a lower-level module. This setup makes it possible for the +//! high-level module to provide its own errors that do not commit to any +//! particular implementation, but also reveal some of its implementation for +//! debugging via `cause` chains. + +#![stable(feature = "rust1", since = "1.0.0")] + +// A note about crates and the facade: +// +// Originally, the `Error` trait was defined in libcore, and the impls +// were scattered about. However, coherence objected to this +// arrangement, because to create the blanket impls for `Box` required +// knowing that `&str: !Error`, and we have no means to deal with that +// sort of conflict just now. Therefore, for the time being, we have +// moved the `Error` trait into libstd. As we evolve a sol'n to the +// coherence challenge (e.g., specialization, neg impls, etc) we can +// reconsider what crate these items belong in. + +use boxed::Box; +use convert::From; +use fmt::{self, Debug, Display}; +use marker::Send; +use num; +use option::Option; +use option::Option::None; +use str; +use string::{self, String}; + +/// Base functionality for all errors in Rust. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait Error: Debug + Display { + /// A short description of the error. + /// + /// The description should not contain newlines or sentence-ending + /// punctuation, to facilitate embedding in larger user-facing + /// strings. + #[stable(feature = "rust1", since = "1.0.0")] + fn description(&self) -> &str; + + /// The lower-level cause of this error, if any. + #[stable(feature = "rust1", since = "1.0.0")] + fn cause(&self) -> Option<&Error> { None } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, E: Error + 'a> From for Box { + fn from(err: E) -> Box { + Box::new(err) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, E: Error + Send + 'a> From for Box { + fn from(err: E) -> Box { + Box::new(err) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, 'b> From<&'b str> for Box { + fn from(err: &'b str) -> Box { + #[derive(Debug)] + struct StringError(String); + + impl Error for StringError { + fn description(&self) -> &str { &self.0 } + } + + impl Display for StringError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.0, f) + } + } + + Box::new(StringError(String::from_str(err))) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for str::ParseBoolError { + fn description(&self) -> &str { "failed to parse bool" } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for str::Utf8Error { + fn description(&self) -> &str { + match *self { + str::Utf8Error::TooShort => "invalid utf-8: not enough bytes", + str::Utf8Error::InvalidByte(..) => "invalid utf-8: corrupt contents", + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for num::ParseIntError { + fn description(&self) -> &str { + self.description() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for num::ParseFloatError { + fn description(&self) -> &str { + self.description() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for string::FromUtf8Error { + fn description(&self) -> &str { + "invalid utf-8" + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for string::FromUtf16Error { + fn description(&self) -> &str { + "invalid utf-16" + } +} + diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 41ac3d60df558..807f0c5753e6b 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -183,7 +183,7 @@ pub use core::raw; pub use core::simd; pub use core::result; pub use core::option; -pub use core::error; +pub mod error; #[cfg(not(test))] pub use alloc::boxed; pub use alloc::rc;