diff options
| author | bors <bors@rust-lang.org> | 2015-02-24 02:22:44 +0000 | 
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2015-02-24 02:22:44 +0000 | 
| commit | 2890508d97af287a136ac50ffa13a1c0a3e32e4e (patch) | |
| tree | d4cba9bfc722d5fb7d44c74dfebde016c45130aa | |
| parent | c4fe7d6aea022330efb8d1b470cac030a859f8f5 (diff) | |
| parent | 3dcc631dee7b2f4be3443b4bbc1dd916436d60ca (diff) | |
| download | rust-2890508d97af287a136ac50ffa13a1c0a3e32e4e.tar.gz rust-2890508d97af287a136ac50ffa13a1c0a3e32e4e.zip  | |
Auto merge of #21689 - FlaPer87:oibit-send-and-friends, r=nikomatsakis
This is one more step towards completing #13231
This series of commits add support for default trait implementations. The changes in this PR don't break existing code and they are expected to preserve the existing behavior in the compiler as far as built-in bounds checks go.
The PR adds negative implementations of `Send`/`Sync` for some types and it removes the special cases for `Send`/`Sync` during the trait obligations checks. That is, it now fully relies on the traits check rather than lang items.
Once this patch lands and a new snapshot is created, it'll be possible to add default impls for `Send` and `Sync` and remove entirely the use of `BuiltinBound::{BoundSend,BoundSync}` for positive implementations as well.
This PR also removes the restriction on negative implementations. That is, it is now possible to add negative implementations for traits other than `Send`/`Sync`
68 files changed, 1208 insertions, 176 deletions
diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index eb138e6142b..b8a22c30f9e 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -144,7 +144,7 @@ use clone::Clone; use cmp::PartialEq; use default::Default; -use marker::{Copy, Send}; +use marker::{Copy, Send, Sync}; use ops::{Deref, DerefMut, Drop}; use option::Option; use option::Option::{None, Some}; @@ -660,6 +660,8 @@ pub struct UnsafeCell<T> { pub value: T, } +impl<T> !Sync for UnsafeCell<T> {} + impl<T> UnsafeCell<T> { /// Construct a new instance of `UnsafeCell` which will wrap the specified /// value. diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 7f52f071080..a9d69973590 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -68,6 +68,7 @@ #![feature(staged_api)] #![feature(unboxed_closures)] #![feature(rustc_attrs)] +#![feature(optin_builtin_traits)] #[macro_use] mod macros; diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 99385725a99..6c934a998de 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -39,6 +39,10 @@ pub unsafe trait Send : MarkerTrait { // empty. } +impl<T> !Send for *const T { } +impl<T> !Send for *mut T { } +impl !Send for Managed { } + /// Types with a constant size known at compile-time. #[stable(feature = "rust1", since = "1.0.0")] #[lang="sized"] @@ -204,6 +208,10 @@ pub unsafe trait Sync : MarkerTrait { // Empty } +impl<T> !Sync for *const T { } +impl<T> !Sync for *mut T { } +impl !Sync for Managed { } + /// A type which is considered "not POD", meaning that it is not /// implicitly copyable. This is typically embedded in other types to /// ensure that they are never copied, even if they lack a destructor. diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 38e15af2056..5ee2f890189 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -410,3 +410,7 @@ pub fn is_associated_type(cstore: &cstore::CStore, def: ast::DefId) -> bool { decoder::is_associated_type(&*cdata, def.node) } +pub fn is_default_trait(cstore: &cstore::CStore, def: ast::DefId) -> bool { + let cdata = cstore.get_crate_data(def.krate); + decoder::is_default_trait(&*cdata, def.node) +} diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index f883c8a1bb9..aeae101a123 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -126,6 +126,7 @@ enum Family { TupleVariant, // v StructVariant, // V Impl, // i + DefaultImpl, // d Trait, // I Struct, // S PublicField, // g @@ -151,6 +152,7 @@ fn item_family(item: rbml::Doc) -> Family { 'v' => TupleVariant, 'V' => StructVariant, 'i' => Impl, + 'd' => DefaultImpl, 'I' => Trait, 'S' => Struct, 'g' => PublicField, @@ -355,9 +357,9 @@ fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum) let enum_did = item_reqd_and_translated_parent_item(cnum, item); DlDef(def::DefVariant(enum_did, did, false)) } - Trait => DlDef(def::DefTrait(did)), + Trait => DlDef(def::DefaultImpl(did)), Enum => DlDef(def::DefTy(did, true)), - Impl => DlImpl(did), + Impl | DefaultImpl => DlImpl(did), PublicField | InheritedField => DlField, } } @@ -480,7 +482,7 @@ pub fn get_impl_trait<'tcx>(cdata: Cmd, let item_doc = lookup_item(id, cdata.data()); let fam = item_family(item_doc); match fam { - Family::Impl => { + Family::Impl | Family::DefaultImpl => { reader::maybe_get_doc(item_doc, tag_item_trait_ref).map(|tp| { doc_trait_ref(tp, tcx, cdata) }) @@ -1356,7 +1358,7 @@ pub fn get_trait_of_item(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt) let parent_item_doc = lookup_item(parent_item_id.node, cdata.data()); match item_family(parent_item_doc) { Trait => Some(item_def_id(parent_item_doc, cdata)), - Impl => { + Impl | DefaultImpl => { reader::maybe_get_doc(parent_item_doc, tag_item_trait_ref) .map(|_| item_trait_ref(parent_item_doc, tcx, cdata).def_id) } @@ -1561,3 +1563,12 @@ pub fn is_associated_type(cdata: Cmd, id: ast::NodeId) -> bool { Some(item) => item_sort(item) == 't', } } + + +pub fn is_default_trait<'tcx>(cdata: Cmd, id: ast::NodeId) -> bool { + let item_doc = lookup_item(id, cdata.data()); + match item_family(item_doc) { + Family::DefaultImpl => true, + _ => false + } +} diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index bb7fd40ced5..e0832bb683a 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -1193,6 +1193,18 @@ fn encode_info_for_item(ecx: &EncodeContext, None => {} } } + ast::ItemDefaultImpl(unsafety, ref ast_trait_ref) => { + add_to_index(item, rbml_w, index); + rbml_w.start_tag(tag_items_data_item); + encode_def_id(rbml_w, def_id); + encode_family(rbml_w, 'd'); + encode_name(rbml_w, item.ident.name); + encode_unsafety(rbml_w, unsafety); + + let trait_ref = ty::node_id_to_trait_ref(tcx, ast_trait_ref.ref_id); + encode_trait_ref(rbml_w, ecx, &*trait_ref, tag_item_trait_ref); + rbml_w.end_tag(); + } ast::ItemImpl(unsafety, polarity, _, ref opt_trait, ref ty, ref ast_items) => { // We need to encode information about the default methods we // have inherited, so we drive this based on the impl structure. diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index eb723830d38..e63901c21b2 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -440,7 +440,7 @@ impl tr for def::Def { def::DefVariant(e_did, v_did, is_s) => { def::DefVariant(e_did.tr(dcx), v_did.tr(dcx), is_s) }, - def::DefTrait(did) => def::DefTrait(did.tr(dcx)), + def::DefaultImpl(did) => def::DefaultImpl(did.tr(dcx)), def::DefTy(did, is_enum) => def::DefTy(did.tr(dcx), is_enum), def::DefAssociatedTy(did) => def::DefAssociatedTy(did.tr(dcx)), def::DefAssociatedPath(def::TyParamProvenance::FromSelf(did), ident) => diff --git a/src/librustc/middle/def.rs b/src/librustc/middle/def.rs index 7857bcad813..009bfaf8728 100644 --- a/src/librustc/middle/def.rs +++ b/src/librustc/middle/def.rs @@ -38,7 +38,7 @@ pub enum Def { // type `U` (indicated by the Ident). // FIXME(#20301) -- should use Name DefAssociatedPath(TyParamProvenance, ast::Ident), - DefTrait(ast::DefId), + DefaultImpl(ast::DefId), DefPrimTy(ast::PrimTy), DefTyParam(ParamSpace, u32, ast::DefId, ast::Name), DefUse(ast::DefId), @@ -135,7 +135,7 @@ impl Def { DefFn(id, _) | DefStaticMethod(id, _) | DefMod(id) | DefForeignMod(id) | DefStatic(id, _) | DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(id) | - DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) | + DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefaultImpl(id) | DefMethod(id, _, _) | DefConst(id) | DefAssociatedPath(TyParamProvenance::FromSelf(id), _) | DefAssociatedPath(TyParamProvenance::FromParam(id), _) => { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index d1fba421bbe..5aa6be43002 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -579,7 +579,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { Ok(self.cat_rvalue_node(id, span, expr_ty)) } def::DefMod(_) | def::DefForeignMod(_) | def::DefUse(_) | - def::DefTrait(_) | def::DefTy(..) | def::DefPrimTy(_) | + def::DefaultImpl(_) | def::DefTy(..) | def::DefPrimTy(_) | def::DefTyParam(..) | def::DefTyParamBinder(..) | def::DefRegion(_) | def::DefLabel(_) | def::DefSelfTy(..) | def::DefAssociatedTy(..) | def::DefAssociatedPath(..)=> { diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 4fd5a02b052..550f4e39447 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -290,7 +290,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { ast::ItemTy(..) | ast::ItemStatic(_, _, _) | ast::ItemMod(..) | ast::ItemForeignMod(..) | ast::ItemImpl(..) | ast::ItemTrait(..) | - ast::ItemStruct(..) | ast::ItemEnum(..) => {} + ast::ItemStruct(..) | ast::ItemEnum(..) | + ast::ItemDefaultImpl(..) => {} _ => { self.tcx.sess.span_bug(item.span, diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 3ba08c10320..bef98f5bd02 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -115,6 +115,7 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { ast::ItemUse(_) | ast::ItemMod(..) | ast::ItemMac(..) | + ast::ItemDefaultImpl(..) | ast::ItemForeignMod(..) | ast::ItemStatic(..) | ast::ItemConst(..) => { @@ -168,7 +169,7 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { // if this path references a trait, then this will resolve to // a trait ref, which introduces a binding scope. match self.def_map.borrow().get(&id) { - Some(&def::DefTrait(..)) => { + Some(&def::DefaultImpl(..)) => { self.with(LateScope(&Vec::new(), self.scope), |_, this| { this.visit_path(path, id); }); diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index a63dcfc24a1..8b836fd322e 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -221,6 +221,12 @@ pub enum Vtable<'tcx, N> { /// Vtable identifying a particular impl. VtableImpl(VtableImplData<'tcx, N>), + /// Vtable for default trait implementations + /// This carries the information and nested obligations with regards + /// to a default implementation for a trait `Trait`. The nested obligations + /// ensure the trait implementation holds for all the constituent types. + VtableDefaultImpl(VtableDefaultImplData<N>), + /// Successful resolution to an obligation provided by the caller /// for some type parameter. The `Vec<N>` represents the /// obligations incurred from normalizing the where-clause (if @@ -260,6 +266,12 @@ pub struct VtableImplData<'tcx, N> { } #[derive(Debug,Clone)] +pub struct VtableDefaultImplData<N> { + pub trait_def_id: ast::DefId, + pub nested: Vec<N> +} + +#[derive(Debug,Clone)] pub struct VtableBuiltinData<N> { pub nested: subst::VecPerParamSpace<N> } @@ -513,17 +525,18 @@ impl<'tcx, N> Vtable<'tcx, N> { pub fn iter_nested(&self) -> Iter<N> { match *self { VtableImpl(ref i) => i.iter_nested(), - VtableFnPointer(..) => (&[]).iter(), - VtableClosure(..) => (&[]).iter(), VtableParam(ref n) => n.iter(), - VtableObject(_) => (&[]).iter(), VtableBuiltin(ref i) => i.iter_nested(), + VtableObject(_) | + VtableDefaultImpl(..) | VtableFnPointer(..) | + VtableClosure(..) => (&[]).iter(), } } pub fn map_nested<M, F>(&self, op: F) -> Vtable<'tcx, M> where F: FnMut(&N) -> M { match *self { VtableImpl(ref i) => VtableImpl(i.map_nested(op)), + VtableDefaultImpl(ref t) => VtableDefaultImpl(t.map_nested(op)), VtableFnPointer(ref sig) => VtableFnPointer((*sig).clone()), VtableClosure(d, ref s) => VtableClosure(d, s.clone()), VtableParam(ref n) => VtableParam(n.iter().map(op).collect()), @@ -539,6 +552,7 @@ impl<'tcx, N> Vtable<'tcx, N> { VtableImpl(i) => VtableImpl(i.map_move_nested(op)), VtableFnPointer(sig) => VtableFnPointer(sig), VtableClosure(d, s) => VtableClosure(d, s), + VtableDefaultImpl(t) => VtableDefaultImpl(t.map_move_nested(op)), VtableParam(n) => VtableParam(n.into_iter().map(op).collect()), VtableObject(p) => VtableObject(p), VtableBuiltin(no) => VtableBuiltin(no.map_move_nested(op)), @@ -573,6 +587,31 @@ impl<'tcx, N> VtableImplData<'tcx, N> { } } +impl<N> VtableDefaultImplData<N> { + pub fn iter_nested(&self) -> Iter<N> { + self.nested.iter() + } + + pub fn map_nested<M, F>(&self, op: F) -> VtableDefaultImplData<M> where + F: FnMut(&N) -> M, + { + VtableDefaultImplData { + trait_def_id: self.trait_def_id, + nested: self.nested.iter().map(op).collect() + } + } + + pub fn map_move_nested<M, F>(self, op: F) -> VtableDefaultImplData<M> where + F: FnMut(N) -> M, + { + let VtableDefaultImplData { trait_def_id, nested } = self; + VtableDefaultImplData { + trait_def_id: trait_def_id, + nested: nested.into_iter().map(op).collect() + } + } +} + impl<N> VtableBuiltinData<N> { pub fn iter_nested(&self) -> Iter<N> { self.nested.iter() diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index 13f309e129a..7d4febb38e6 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -709,6 +709,7 @@ fn assemble_candidates_from_impls<'cx,'tcx>( // projection. And the projection where clause is handled // in `assemble_candidates_from_param_env`. } + super::VtableDefaultImpl(..) | super::VtableBuiltin(..) => { // These traits have no associated types. selcx.tcx().sess.span_bug( diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 2ce8eeb8f5a..daf7e50e1bc 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -17,17 +17,17 @@ use self::SelectionCandidate::*; use self::BuiltinBoundConditions::*; use self::EvaluationResult::*; -use super::{DerivedObligationCause}; -use super::{project}; -use super::project::Normalized; +use super::DerivedObligationCause; +use super::project; +use super::project::{normalize_with_depth, Normalized}; use super::{PredicateObligation, TraitObligation, ObligationCause}; -use super::{ObligationCauseCode, BuiltinDerivedObligation}; +use super::{ObligationCauseCode, BuiltinDerivedObligation, ImplDerivedObligation}; use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch}; use super::{Selection}; use super::{SelectionResult}; use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure, - VtableFnPointer, VtableObject}; -use super::{VtableImplData, VtableObjectData, VtableBuiltinData}; + VtableFnPointer, VtableObject, VtableDefaultImpl}; +use super::{VtableImplData, VtableObjectData, VtableBuiltinData, VtableDefaultImplData}; use super::object_safety; use super::{util}; @@ -136,6 +136,7 @@ enum SelectionCandidate<'tcx> { BuiltinCandidate(ty::BuiltinBound), ParamCandidate(ty::PolyTraitRef<'tcx>), ImplCandidate(ast::DefId), + DefaultImplCandidate(ast::DefId), /// This is a trait matching with a projected type as `Self`, and /// we found an applicable bound in the trait definition. @@ -151,6 +152,8 @@ enum SelectionCandidate<'tcx> { ObjectCandidate, + BuiltinObjectCandidate, + ErrorCandidate, } @@ -818,31 +821,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!("obligation self ty is {}", obligation.predicate.0.self_ty().repr(self.tcx())); + // User-defined copy impls are permitted, but only for + // structs and enums. try!(self.assemble_candidates_from_impls(obligation, &mut candidates)); + // For other types, we'll use the builtin rules. try!(self.assemble_builtin_bound_candidates(ty::BoundCopy, stack, &mut candidates)); } - Some(bound @ ty::BoundSend) | - Some(bound @ ty::BoundSync) => { - try!(self.assemble_candidates_from_impls(obligation, &mut candidates)); - - // No explicit impls were declared for this type, consider the fallback rules. - if candidates.vec.is_empty() && !candidates.ambiguous { - try!(self.assemble_builtin_bound_candidates(bound, stack, &mut candidates)); - } - } - Some(bound @ ty::BoundSized) => { - // Sized and Copy are always automatically computed. + // Sized is never implementable by end-users, it is + // always automatically computed. try!(self.assemble_builtin_bound_candidates(bound, stack, &mut candidates)); } + Some(ty::BoundSend) | + Some(ty::BoundSync) | None => { - // For the time being, we ignore user-defined impls for builtin-bounds, other than - // `Copy`. - // (And unboxed candidates only apply to the Fn/FnMut/etc traits.) try!(self.assemble_closure_candidates(obligation, &mut candidates)); try!(self.assemble_fn_pointer_candidates(obligation, &mut candidates)); try!(self.assemble_candidates_from_impls(obligation, &mut candidates)); @@ -852,6 +848,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_candidates_from_projected_tys(obligation, &mut candidates); try!(self.assemble_candidates_from_caller_bounds(stack, &mut candidates)); + // Default implementations have lower priority, so we only + // consider triggering a default if there is no other impl that can apply. + if candidates.vec.len() == 0 { + try!(self.assemble_candidates_from_default_impls(obligation, &mut candidates)); + } debug!("candidate list size: {}", candidates.vec.len()); Ok(candidates) } @@ -1131,7 +1132,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); debug!("assemble_candidates_from_impls(self_ty={})", self_ty.repr(self.tcx())); - let all_impls = self.all_impls(obligation.predicate.def_id()); + let def_id = obligation.predicate.def_id(); + let all_impls = self.all_impls(def_id); for &impl_def_id in &all_impls { self.infcx.probe(|snapshot| { let (skol_obligation_trait_pred, skol_map) = @@ -1145,6 +1147,65 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } }); } + + Ok(()) + } + + fn assemble_candidates_from_default_impls(&mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>) + -> Result<(), SelectionError<'tcx>> + { + + let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); + debug!("assemble_candidates_from_default_impls(self_ty={})", self_ty.repr(self.tcx())); + + let def_id = obligation.predicate.def_id(); + + if ty::trait_has_default_impl(self.tcx(), def_id) { + match self_ty.sty { + ty::ty_trait(..) | + ty::ty_param(..) | + ty::ty_projection(..) => { + // In these cases, we don't know what the actual + // type is. Therefore, we cannot break it down + // into its constituent types. So we don't + // consider the `..` impl but instead just add no + // candidates: this means that typeck will only + // succeed if there is another reason to believe + // that this obligation holds. That could be a + // where-clause or, in the case of an object type, + // it could be that the object type lists the + // trait (e.g. `Foo+Send : Send`). See + // `compile-fail/typeck-default-trait-impl-send-param.rs` + // for an example of a test case that exercises + // this path. + } + ty::ty_infer(ty::TyVar(_)) => { + // the defaulted impl might apply, we don't know + candidates.ambiguous = true; + } + _ => { + if self.constituent_types_for_ty(self_ty).is_some() { + candidates.vec.push(DefaultImplCandidate(def_id.clone())) + } else { + // We don't yet know what the constituent + // types are. So call it ambiguous for now, + // though this is a bit stronger than + // necessary: that is, we know that the + // defaulted impl applies, but we can't + // process the confirmation step without + // knowing the constituent types. (Anyway, in + // the particular case of defaulted impls, it + // doesn't really matter much either way, + // since we won't be aiding inference by + // processing the confirmation step.) + candidates.ambiguous = true; + } + } + } + } + Ok(()) } @@ -1171,6 +1232,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let poly_trait_ref = match self_ty.sty { ty::ty_trait(ref data) => { + match self.tcx().lang_items.to_builtin_kind(obligation.predicate.def_id()) { + Some(bound @ ty::BoundSend) | Some(bound @ ty::BoundSync) => { + if data.bounds.builtin_bounds.contains(&bound) { + debug!("assemble_candidates_from_object_ty: matched builtin bound, \ + pushing candidate"); + candidates.vec.push(BuiltinObjectCandidate); + return; + } + } + _ => {} + } + data.principal_trait_ref_with_self_ty(self.tcx(), self_ty) } ty::ty_infer(ty::TyVar(_)) => { @@ -1258,6 +1331,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { (&ImplCandidate(..), &ParamCandidate(..)) | (&ClosureCandidate(..), &ParamCandidate(..)) | (&FnPointerCandidate(..), &ParamCandidate(..)) | + (&BuiltinObjectCandidate(..), &ParamCandidate(_)) | (&BuiltinCandidate(..), &ParamCandidate(..)) => { // We basically prefer always prefer to use a // where-clause over another option. Where clauses @@ -1267,6 +1341,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // #18453. true } + (&DefaultImplCandidate(_), _) => { + // Prefer other candidates over default implementations. + self.tcx().sess.bug( + "default implementations shouldn't be recorded \ + when there are other valid candidates"); + } (&ProjectionCandidate, &ParamCandidate(_)) => { // FIXME(#20297) -- this gives where clauses precedent // over projections. Really these are just two means @@ -1341,7 +1421,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(If(Vec::new())) } - ty::ty_uniq(referent_ty) => { // Box<T> + ty::ty_uniq(_) => { // Box<T> match bound { ty::BoundCopy => { Err(Unimplemented) @@ -1351,24 +1431,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(If(Vec::new())) } - ty::BoundSync | - ty::BoundSend => { - Ok(If(vec![referent_ty])) + ty::BoundSync | ty::BoundSend => { + self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()"); } } } ty::ty_ptr(..) => { // *const T, *mut T match bound { - ty::BoundCopy | - ty::BoundSized => { + ty::BoundCopy | ty::BoundSized => { Ok(If(Vec::new())) } - ty::BoundSync | - ty::BoundSend => { - // sync and send are not implemented for *const, *mut - Err(Unimplemented) + ty::BoundSync | ty::BoundSend => { + self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()"); } } } @@ -1378,7 +1454,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::BoundSized => { Err(Unimplemented) } - ty::BoundCopy | ty::BoundSync | ty::BoundSend => { + ty::BoundCopy => { if data.bounds.builtin_bounds.contains(&bound) { Ok(If(Vec::new())) } else { @@ -1397,10 +1473,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Err(Unimplemented) } } + ty::BoundSync | ty::BoundSend => { + self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()"); + } } } - ty::ty_rptr(_, ty::mt { ty: referent_ty, mutbl }) => { + ty::ty_rptr(_, ty::mt { ty: _, mutbl }) => { // &mut T or &T match bound { ty::BoundCopy => { @@ -1421,9 +1500,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(If(Vec::new())) } - ty::BoundSync | - ty::BoundSend => { - Ok(If(vec![referent_ty])) + ty::BoundSync | ty::BoundSend => { + self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()"); } } } @@ -1452,9 +1530,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::BoundSync | - ty::BoundSend => { - Ok(If(vec![element_ty])) + ty::BoundSync | ty::BoundSend => { + self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()"); } } } @@ -1462,13 +1539,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::ty_str => { // Equivalent to [u8] match bound { - ty::BoundSync | - ty::BoundSend => { - Ok(If(Vec::new())) + ty::BoundSync | ty::BoundSend => { + self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()"); } - ty::BoundCopy | - ty::BoundSized => { + ty::BoundCopy | ty::BoundSized => { Err(Unimplemented) } } @@ -1521,7 +1596,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::struct_fields(self.tcx(), def_id, substs).iter() .map(|f| f.mt.ty) .collect(); - nominal(self, bound, def_id, types) + nominal(bound, types) } ty::ty_enum(def_id, substs) => { @@ -1531,7 +1606,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .flat_map(|variant| variant.args.iter()) .cloned() .collect(); - nominal(self, bound, def_id, types) + nominal(bound, types) } ty::ty_projection(_) | @@ -1556,15 +1631,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // "opened" unsized/existential type (one that has // been dereferenced) match bound { - ty::BoundCopy | - ty::BoundSync | - ty::BoundSend => { + ty::BoundCopy => { Ok(If(vec!(ty))) } ty::BoundSized => { Err(Unimplemented) } + + ty::BoundSync | + ty::BoundSend => { + self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()"); + } } } ty::ty_err => { @@ -1580,38 +1658,108 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } }; - fn nominal<'cx, 'tcx>(this: &mut SelectionContext<'cx, 'tcx>, - bound: ty::BuiltinBound, - def_id: ast::DefId, + fn nominal<'cx, 'tcx>(bound: ty::BuiltinBound, types: Vec<Ty<'tcx>>) -> Result<BuiltinBoundConditions<'tcx>,SelectionError<'tcx>> { // First check for markers and other nonsense. - let tcx = this.tcx(); match bound { - ty::BoundSend => { - if Some(def_id) == tcx.lang_items.managed_bound() { - return Err(Unimplemented) - } - } + // Fallback to whatever user-defined impls exist in this case. + ty::BoundCopy => Ok(ParameterBuiltin), - ty::BoundCopy => { - return Ok(ParameterBuiltin) - } + // Sized if all the component types are sized. + ty::BoundSized => Ok(If(types)), + + // Shouldn't be coming through here. + ty::BoundSend | ty::BoundSync => unreachable!(), + } + } + } + + /// For default impls, we need to break apart a type into its + /// "constituent types" -- meaning, the types that it contains. + /// + /// Here are some (simple) examples: + /// + /// ``` + /// (i32, u32) -> [i32, u32] + /// Foo where struct Foo { x: i32, y: u32 } -> [i32, u32] + /// Bar<i32> where struct Bar<T> { x: T, y: u32 } -> [i32, u32] + /// Zed<i32> where enum Zed { A(T), B(u32) } -> [i32, u32] + /// ``` + fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Option<Vec<Ty<'tcx>>> { + match t.sty { + ty::ty_uint(_) | + ty::ty_int(_) | + ty::ty_bool | + ty::ty_float(_) | + ty::ty_bare_fn(..) | + ty::ty_str | + ty::ty_err | + ty::ty_infer(ty::IntVar(_)) | + ty::ty_infer(ty::FloatVar(_)) | + ty::ty_char => { + Some(Vec::new()) + } + + ty::ty_trait(..) | + ty::ty_param(..) | + ty::ty_projection(..) | + ty::ty_infer(ty::TyVar(_)) | + ty::ty_infer(ty::FreshTy(_)) | + ty::ty_infer(ty::FreshIntTy(_)) => { + self.tcx().sess.bug( + &format!( + "asked to assemble constituent types of unexpected type: {}", + t.repr(self.tcx()))[]); + } + + ty::ty_uniq(referent_ty) => { // Box<T> + Some(vec![referent_ty]) + } + + ty::ty_open(element_ty) => {Some(vec![element_ty])}, + + ty::ty_ptr(ty::mt { ty: element_ty, ..}) | + ty::ty_rptr(_, ty::mt { ty: element_ty, ..}) => { + Some(vec![element_ty]) + }, - ty::BoundSync => { - if - Some(def_id) == tcx.lang_items.managed_bound() || - Some(def_id) == tcx.lang_items.unsafe_cell_type() - { - return Err(Unimplemented) + ty::ty_vec(element_ty, _) => { + Some(vec![element_ty]) + } + + ty::ty_tup(ref tys) => { + // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet + Some(tys.clone()) + } + + ty::ty_closure(def_id, _, substs) => { + assert_eq!(def_id.krate, ast::LOCAL_CRATE); + + match self.closure_typer.closure_upvars(def_id, substs) { + Some(upvars) => { + Some(upvars.iter().map(|c| c.ty).collect()) + } + None => { + None } } + } - ty::BoundSized => { } + ty::ty_struct(def_id, substs) => { + Some(ty::struct_fields(self.tcx(), def_id, substs).iter() + .map(|f| f.mt.ty) + .collect()) } - Ok(If(types)) + ty::ty_enum(def_id, substs) => { + Some(ty::substd_enum_variants(self.tcx(), def_id, substs) + .iter() + .flat_map(|variant| variant.args.iter()) + .map(|&ty| ty) + .collect()) + } } } @@ -1647,6 +1795,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(VtableParam(obligations)) } + DefaultImplCandidate(trait_def_id) => { + let data = try!(self.confirm_default_impl_candidate(obligation, trait_def_id)); + Ok(VtableDefaultImpl(data)) + } + ImplCandidate(impl_def_id) => { let vtable_impl = try!(self.confirm_impl_candidate(obligation, impl_def_id)); @@ -1658,6 +1811,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(VtableClosure(closure_def_id, substs)) } + BuiltinObjectCandidate => { + // This indicates something like `(Trait+Send) : + // Send`. In this case, we know that this holds + // because that's what the object type is telling us, + // and there's really no additional obligations to + // prove and no types in particular to unify etc. + Ok(VtableParam(Vec::new())) + } + ObjectCandidate => { let data = self.confirm_object_candidate(obligation); Ok(VtableObject(data)) @@ -1779,6 +1941,99 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { VtableBuiltinData { nested: obligations } } + /// This handles the case where a `impl Foo for ..` impl is being used. + /// The idea is that the impl applies to `X : Foo` if the following conditions are met: + /// + /// 1. For each constituent type `Y` in `X`, `Y : Foo` holds + /// 2. For each where-clause `C` declared on `Foo`, `[Self => X] C` holds. + fn confirm_default_impl_candidate(&mut self, + obligation: &TraitObligation<'tcx>, + impl_def_id: ast::DefId) + -> Result<VtableDefaultImplData<PredicateObligation<'tcx>>, + SelectionError<'tcx>> + { + debug!("confirm_default_impl_candidate({}, {})", + obligation.repr(self.tcx()), + impl_def_id.repr(self.tcx())); + + let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty()); + match self.constituent_types_for_ty(self_ty) { + Some(types) => { + Ok(self.vtable_default_impl(obligation, impl_def_id, types)) + } + None => { + self.tcx().sess.bug( + &format!( + "asked to confirm default implementation for ambiguous type: {}", + self_ty.repr(self.tcx()))[]); + } + } + } + + /// See `confirm_default_impl_candidate` + fn vtable_default_impl(&mut self, + obligation: &TraitObligation<'tcx>, + trait_def_id: ast::DefId, + nested: Vec<Ty<'tcx>>) + -> VtableDefaultImplData<PredicateObligation<'tcx>> + { + let derived_cause = self.derived_cause(obligation, ImplDerivedObligation); + + let obligations = nested.iter().map(|&nested_ty| { + // the obligation might be higher-ranked, e.g. for<'a> &'a + // int : Copy. In that case, we will wind up with + // late-bound regions in the `nested` vector. So for each + // one we instantiate to a skolemized region, do our work + // to produce something like `&'0 int : Copy`, and then + // re-bind it. This is a bit of busy-work but preserves + // the invariant that we only manipulate free regions, not + // bound ones. + self.infcx.try(|snapshot| { + let (skol_ty, skol_map) = + self.infcx().skolemize_late_bound_regions(&ty::Binder(nested_ty), snapshot); + let skol_predicate = + util::predicate_for_default_trait_impl( + self.tcx(), + derived_cause.clone(), + trait_def_id, + obligation.recursion_depth + 1, + skol_ty); + match skol_predicate { + Ok(skol_predicate) => Ok(self.infcx().plug_leaks(skol_map, snapshot, + &skol_predicate)), + Err(ErrorReported) => Err(ErrorReported) + } + }) + }).collect::<Result<_, _>>(); + + let mut obligations = match obligations { + Ok(o) => o, + Err(ErrorReported) => Vec::new() + }; + + let _: Result<(),()> = self.infcx.try(|snapshot| { + let (_, skol_map) = + self.infcx().skolemize_late_bound_regions(&obligation.predicate, snapshot); + + let substs = obligation.predicate.to_poly_trait_ref().substs(); + let trait_obligations = self.impl_or_trait_obligations(obligation.cause.clone(), + obligation.recursion_depth + 1, + trait_def_id, + substs, + skol_map, + snapshot); + obligations.push_all(trait_obligations.as_slice()); + Ok(()) + }); + + debug!("vtable_default_impl_data: obligations={}", obligations.repr(self.tcx())); + + VtableDefaultImplData { + trait_def_id: trait_def_id, + nested: obligations + } + } + fn confirm_impl_candidate(&mut self, obligation: &TraitObligation<'tcx>, impl_def_id: ast::DefId) @@ -1819,12 +2074,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { skol_map.repr(self.tcx())); let mut impl_obligations = - self.impl_obligations(cause, - recursion_depth, - impl_def_id, - &substs.value, - skol_map, - snapshot); + self.impl_or_trait_obligations(cause, + recursion_depth, + impl_def_id, + &substs.value, + skol_map, + snapshot); debug!("vtable_impl: impl_def_id={} impl_obligations={}", impl_def_id.repr(self.tcx()), @@ -2244,28 +2499,30 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::Binder(trait_ref) } - fn impl_obligations(&mut self, - cause: ObligationCause<'tcx>, - recursion_depth: uint, - impl_def_id: ast::DefId, - impl_substs: &Substs<'tcx>, - skol_map: infer::SkolemizationMap, - snapshot: &infer::CombinedSnapshot) - -> VecPerParamSpace<PredicateObligation<'tcx>> + /// Returns the obligations that are implied by instantiating an + /// impl or trait. The obligations are substituted and fully + /// normalized. This is used when confirming an impl or default + /// impl. + fn impl_or_trait_obligations(&mut self, + cause: ObligationCause<'tcx>, + recursion_depth: uint, + def_id: ast::DefId, // of impl or trait + substs: &Substs<'tcx>, // for impl or trait + skol_map: infer::SkolemizationMap, + snapshot: &infer::CombinedSnapshot) + -> VecPerParamSpace<PredicateObligation<'tcx>> { - let impl_bounds = ty::lookup_predicates(self.tcx(), impl_def_id); - let bounds = impl_bounds.instantiate(self.tcx(), impl_substs); - let normalized_bounds = - project::normalize_with_depth(self, cause.clone(), recursion_depth, &bounds); - let normalized_bounds = - self.infcx().plug_leaks(skol_map, snapshot, &normalized_bounds); - let mut impl_obligations = + let predicates = ty::lookup_predicates(self.tcx(), def_id); + let predicates = predicates.instantiate(self.tcx(), substs); + let predicates = normalize_with_depth(self, cause.clone(), recursion_depth, &predicates); + let predicates = self.infcx().plug_leaks(skol_map, snapshot, &predicates); + let mut obligations = util::predicates_for_generics(self.tcx(), cause, recursion_depth, - &normalized_bounds.value); - impl_obligations.extend(TypeSpace, normalized_bounds.obligations.into_iter()); - impl_obligations + &predicates.value); + obligations.extend(TypeSpace, predicates.obligations.into_iter()); + obligations } #[allow(unused_comparisons)] @@ -2307,8 +2564,10 @@ impl<'tcx> Repr<'tcx> for SelectionCandidate<'tcx> { PhantomFnCandidate => format!("PhantomFnCandidate"), ErrorCandidate => format!("ErrorCandidate"), BuiltinCandidate(b) => format!("BuiltinCandidate({:?})", b), + BuiltinObjectCandidate => format!("BuiltinObjectCandidate"), ParamCandidate(ref a) => format!("ParamCandidate({})", a.repr(tcx)), ImplCandidate(a) => format!("ImplCandidate({})", a.repr(tcx)), + DefaultImplCandidate(t) => format!("DefaultImplCandidate({:?})", t), ProjectionCandidate => format!("ProjectionCandidate"), FnPointerCandidate => format!("FnPointerCandidate"), ObjectCandidate => { diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 6c54da1c134..9b462e6be60 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -20,7 +20,7 @@ use util::nodemap::FnvHashSet; use util::ppaux::Repr; use super::{Obligation, ObligationCause, PredicateObligation, - VtableImpl, VtableParam, VtableImplData}; + VtableImpl, VtableParam, VtableImplData, VtableDefaultImplData}; struct PredicateSet<'a,'tcx:'a> { tcx: &'a ty::ctxt<'tcx>, @@ -323,6 +323,35 @@ pub fn trait_ref_for_builtin_bound<'tcx>( } } + +pub fn predicate_for_trait_ref<'tcx>( + cause: ObligationCause<'tcx>, + trait_ref: Rc<ty::TraitRef<'tcx>>, + recursion_depth: uint) + -> Result<PredicateObligation<'tcx>, ErrorReported> +{ + Ok(Obligation { + cause: cause, + recursion_depth: recursion_depth, + predicate: trait_ref.as_predicate(), + }) +} + +pub fn predicate_for_default_trait_impl<'tcx>( + tcx: &ty::ctxt<'tcx>, + cause: ObligationCause<'tcx>, + trait_def_id: ast::DefId, + recursion_depth: uint, + param_ty: Ty<'tcx>) + -> Result<PredicateObligation<'tcx>, ErrorReported> +{ + let trait_ref = Rc::new(ty::TraitRef { + def_id: trait_def_id, + substs: tcx.mk_substs(Substs::empty().with_self_ty(param_ty)) + }); + predicate_for_trait_ref(cause, trait_ref, recursion_depth) +} + pub fn predicate_for_builtin_bound<'tcx>( tcx: &ty::ctxt<'tcx>, cause: ObligationCause<'tcx>, @@ -332,11 +361,7 @@ pub fn predicate_for_builtin_bound<'tcx>( -> Result<PredicateObligation<'tcx>, ErrorReported> { let trait_ref = try!(trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty)); - Ok(Obligation { - cause: cause, - recursion_depth: recursion_depth, - predicate: trait_ref.as_predicate(), - }) + predicate_for_trait_ref(cause, trait_ref, recursion_depth) } /// Cast a trait reference into a reference to one of its super @@ -444,6 +469,9 @@ impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::Vtable<'tcx, N> { super::VtableImpl(ref v) => v.repr(tcx), + super::VtableDefaultImpl(ref t) => + t.repr(tcx), + super::VtableClosure(ref d, ref s) => format!("VtableClosure({},{})", d.repr(tcx), @@ -483,6 +511,14 @@ impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::VtableBuiltinData<N> { } } +impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::VtableDefaultImplData<N> { + fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { + format!("VtableDefaultImplData(trait_def_id={}, nested={})", + self.trait_def_id.repr(tcx), + self.nested.repr(tcx)) + } +} + impl<'tcx> Repr<'tcx> for super::VtableObjectData<'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { format!("VtableObject(object_ty={})", diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 1206424550f..a461297dd95 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -756,6 +756,9 @@ pub struct ctxt<'tcx> { /// Maps a trait onto a list of impls of that trait. pub trait_impls: RefCell<DefIdMap<Rc<RefCell<Vec<ast::DefId>>>>>, + /// Maps a trait onto a list of *default* trait implementations + default_trait_impls: RefCell<DefIdMap<ast::DefId>>, + /// Maps a DefId of a type to a list of its inherent impls. /// Contains implementations of methods that are inherent to a type. /// Methods in these implementations don't need to be exported. @@ -2478,6 +2481,7 @@ pub fn mk_ctxt<'tcx>(s: Session, destructor_for_type: RefCell::new(DefIdMap()), destructors: RefCell::new(DefIdSet()), trait_impls: RefCell::new(DefIdMap()), + default_trait_impls: RefCell::new(DefIdMap()), inherent_impls: RefCell::new(DefIdMap()), impl_items: RefCell::new(DefIdMap()), used_unsafe: RefCell::new(NodeSet()), @@ -5156,6 +5160,9 @@ pub fn impl_trait_ref<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) &None => None } } + ast::ItemDefaultImpl(_, ref ast_trait_ref) => { + Some(ty::node_id_to_trait_ref(cx, ast_trait_ref.ref_id)) + } _ => None } } @@ -5977,6 +5984,32 @@ pub fn item_variances(tcx: &ctxt, item_id: ast::DefId) -> Rc<ItemVariances> { || Rc::new(csearch::get_item_variances(&tcx.sess.cstore, item_id))) } +pub fn trait_default_impl(tcx: &ctxt, trait_def_id: DefId) -> Option<ast::DefId> { + match tcx.default_trait_impls.borrow().get(&trait_def_id) { + Some(id) => Some(*id), + None => None + } +} + +pub fn trait_has_default_impl(tcx: &ctxt, trait_def_id: DefId) -> bool { + match tcx.lang_items.to_builtin_kind(trait_def_id) { + Some(BoundSend) | Some(BoundSync) => true, + _ => tcx.default_trait_impls.borrow().contains_key(&trait_def_id) + } +} + +/// Records a trait-to-implementation mapping. +pub fn record_default_trait_implementation(tcx: &ctxt, + trait_def_id: DefId, + impl_def_id: DefId) { + + // We're using the latest implementation found as the reference one. + // Duplicated implementations are caught and reported in the coherence + // step. + tcx.default_trait_impls.borrow_mut().insert(trait_def_id, impl_def_id); +} + + /// Records a trait-to-implementation mapping. pub fn record_trait_implementation(tcx: &ctxt, trait_def_id: DefId, @@ -6059,11 +6092,22 @@ pub fn populate_implementations_for_trait_if_necessary( } csearch::each_implementation_for_trait(&tcx.sess.cstore, trait_id, - |implementation_def_id| { + |implementation_def_id|{ let impl_items = csearch::get_impl_items(&tcx.sess.cstore, implementation_def_id); - // Record the trait->implementation mapping. - record_trait_implementation(tcx, trait_id, implementation_def_id); + if csearch::is_default_trait(&tcx.sess.cstore, implementation_def_id) { + record_default_trait_implementation(tcx, trait_id, + implementation_def_id); + tcx.populated_external_traits.borrow_mut().insert(trait_id); + + // Nothing else to do for default trait implementations since + // they are not allowed to have type parameters, methods, or any + // other item that could be associated to a trait implementation. + return; + } else { + // Record the trait->implementation mapping. + record_trait_implementation(tcx, trait_id, implementation_def_id); + } // For any methods that use a default implementation, add them to // the map. This is a bit unfortunate. diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 5e46ce08e4f..92b0ea905ac 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -507,6 +507,15 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableImplData< } } +impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableDefaultImplData<N> { + fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableDefaultImplData<N> { + traits::VtableDefaultImplData { + trait_def_id: self.trait_def_id, + nested: self.nested.fold_with(folder), + } + } +} + impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableBuiltinData<N> { fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableBuiltinData<N> { traits::VtableBuiltinData { @@ -519,6 +528,7 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Vtable<'tcx, N> { match *self { traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)), + traits::VtableDefaultImpl(ref t) => traits::VtableDefaultImpl(t.fold_with(folder)), traits::VtableClosure(d, ref s) => { traits::VtableClosure(d, s.fold_with(folder)) } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index fbbd72e2c76..cdcc9850e42 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -206,7 +206,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> { ast::ItemEnum(..) | ast::ItemStruct(..) | ast::ItemTrait(..) | ast::ItemImpl(..) | - ast::ItemMac(..) => { + ast::ItemMac(..) | ast::ItemDefaultImpl(..) => { None } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index eae02e0bf66..f0a640aa2e0 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -209,7 +209,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { match item.node { // impls/extern blocks do not break the "public chain" because they // cannot have visibility qualifiers on them anyway - ast::ItemImpl(..) | ast::ItemForeignMod(..) => {} + ast::ItemImpl(..) | ast::ItemDefaultImpl(..) | ast::ItemForeignMod(..) => {} // Traits are a little special in that even if they themselves are // not public they may still be exported. @@ -802,7 +802,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { def::DefVariant(..) => ck("variant"), def::DefTy(_, false) => ck("type"), def::DefTy(_, true) => ck("enum"), - def::DefTrait(..) => ck("trait"), + def::DefaultImpl(..) => ck("trait"), def::DefStruct(..) => ck("struct"), def::DefMethod(_, Some(..), _) => ck("trait method"), def::DefMethod(..) => ck("method"), @@ -1145,6 +1145,7 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> { } } + ast::ItemDefaultImpl(..) | ast::ItemConst(..) | ast::ItemStatic(..) | ast::ItemStruct(..) | ast::ItemFn(..) | ast::ItemMod(..) | ast::ItemTy(..) | ast::ItemExternCrate(_) | ast::ItemUse(_) | ast::ItemMac(..) => {} @@ -1204,7 +1205,7 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> { } } - ast::ItemExternCrate(_) | ast::ItemUse(_) | + ast::ItemDefaultImpl(..) | ast::ItemExternCrate(_) | ast::ItemUse(_) | ast::ItemStatic(..) | ast::ItemConst(..) | ast::ItemFn(..) | ast::ItemMod(..) | ast::ItemTy(..) | ast::ItemMac(..) => {} diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 3b3106af818..31f21a84f84 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -40,7 +40,7 @@ use syntax::ast::{Block, Crate}; use syntax::ast::{DeclItem, DefId}; use syntax::ast::{ForeignItem, ForeignItemFn, ForeignItemStatic}; use syntax::ast::{Item, ItemConst, ItemEnum, ItemExternCrate, ItemFn}; -use syntax::ast::{ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic}; +use syntax::ast::{ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic, ItemDefaultImpl}; use syntax::ast::{ItemStruct, ItemTrait, ItemTy, ItemUse}; use syntax::ast::{MethodImplItem, Name, NamedField, NodeId}; use syntax::ast::{PathListIdent, PathListMod}; @@ -656,6 +656,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { parent.clone() } + ItemDefaultImpl(_, _) | ItemImpl(_, _, _, Some(_), _, _) => parent.clone(), ItemTrait(_, _, _, ref items) => { @@ -735,7 +736,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { self.trait_item_map.insert((name, def_id), kind); } - name_bindings.define_type(DefTrait(def_id), sp, modifiers); + name_bindings.define_type(DefaultImpl(def_id), sp, modifiers); parent.clone() } ItemMac(..) => parent.clone() @@ -917,7 +918,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { } child_name_bindings.define_value(def, DUMMY_SP, modifiers); } - DefTrait(def_id) => { + DefaultImpl(def_id) => { debug!("(building reduced graph for external \ crate) building type {}", final_ident); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 062ea885bf4..c38b8fc7502 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -70,7 +70,7 @@ use syntax::ast::{ExprClosure, ExprLoop, ExprWhile, ExprMethodCall}; use syntax::ast::{ExprPath, ExprQPath, ExprStruct, FnDecl}; use syntax::ast::{ForeignItemFn, ForeignItemStatic, Generics}; use syntax::ast::{Ident, ImplItem, Item, ItemConst, ItemEnum, ItemExternCrate}; -use syntax::ast::{ItemFn, ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic}; +use syntax::ast::{ItemFn, ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic, ItemDefaultImpl}; use syntax::ast::{ItemStruct, ItemTrait, ItemTy, ItemUse}; use syntax::ast::{Local, MethodImplItem, Mod, Name, NodeId}; use syntax::ast::{Pat, PatEnum, PatIdent, PatLit}; @@ -2840,6 +2840,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }); } + ItemDefaultImpl(_, ref trait_ref) => { + self.resolve_trait_reference(item.id, trait_ref, TraitImplementation); + } ItemImpl(_, _, ref generics, ref implemented_traits, @@ -2986,7 +2989,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // check for imports shadowing primitive types if let ast::ViewPathSimple(ident, _) = view_path.node { match self.def_map.borrow().get(&item.id) { - Some(&DefTy(..)) | Some(&DefStruct(..)) | Some(&DefTrait(..)) | None => { + Some(&DefTy(..)) | Some(&DefStruct(..)) | Some(&DefaultImpl(..)) | None => { self.check_if_primitive_type_name(ident.name, item.span); } _ => {} @@ -3196,7 +3199,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } Some(def) => { match def { - (DefTrait(_), _) => { + (DefaultImpl(_), _) => { debug!("(resolving trait) found trait def: {:?}", def); self.record_def(trait_reference.ref_id, def); } @@ -4672,7 +4675,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { None => continue }; let trait_def_id = match def { - DefTrait(trait_def_id) => trait_def_id, + DefaultImpl(trait_def_id) => trait_def_id, _ => continue, }; if self.trait_item_map.contains_key(&(name, trait_def_id)) { @@ -4688,7 +4691,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Some(target) => target, }; let did = match target.bindings.def_for_namespace(TypeNS) { - Some(DefTrait(trait_def_id)) => trait_def_id, + Some(DefaultImpl(trait_def_id)) => trait_def_id, Some(..) | None => continue, }; if self.trait_item_map.contains_key(&(name, did)) { diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 59fca4b0318..591450a2595 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -239,7 +239,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { def::DefTy(..) | def::DefAssociatedTy(..) | def::DefAssociatedPath(..) | - def::DefTrait(_) => Some(recorder::TypeRef), + def::DefaultImpl(_) => Some(recorder::TypeRef), def::DefStatic(_, _) | def::DefConst(_) | def::DefLocal(_) | diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 25568db8148..a358a3d89e9 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -207,7 +207,7 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) def::DefUpvar(..) => { datum_callee(bcx, ref_expr) } - def::DefMod(..) | def::DefForeignMod(..) | def::DefTrait(..) | + def::DefMod(..) | def::DefForeignMod(..) | def::DefaultImpl(..) | def::DefTy(..) | def::DefPrimTy(..) | def::DefAssociatedTy(..) | def::DefUse(..) | def::DefTyParamBinder(..) | def::DefRegion(..) | def::DefLabel(..) | def::DefTyParam(..) | diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 65d8f8ec361..7644ecf2cfd 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -390,6 +390,7 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, Callee { bcx: bcx, data: Fn(llfn) } } traits::VtableBuiltin(..) | + traits::VtableDefaultImpl(..) | traits::VtableParam(..) => { bcx.sess().bug( &format!("resolved vtable bad vtable {} in trans", @@ -714,6 +715,8 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let methods = traits::supertraits(tcx, trait_ref.clone()).flat_map(|trait_ref| { let vtable = fulfill_obligation(ccx, DUMMY_SP, trait_ref.clone()); match vtable { + // Should default trait error here? + traits::VtableDefaultImpl(_) | traits::VtableBuiltin(_) => { Vec::new().into_iter() } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index afdc414c163..ff397d99430 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -617,7 +617,7 @@ pub fn instantiate_trait_ref<'tcx>( -> Rc<ty::TraitRef<'tcx>> { match ::lookup_def_tcx(this.tcx(), ast_trait_ref.path.span, ast_trait_ref.ref_id) { - def::DefTrait(trait_def_id) => { + def::DefaultImpl(trait_def_id) => { let trait_ref = ast_path_to_trait_ref(this, rscope, trait_def_id, @@ -931,7 +931,7 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>, match ty.node { ast::TyPath(ref path, id) => { match this.tcx().def_map.borrow().get(&id) { - Some(&def::DefTrait(trait_def_id)) => { + Some(&def::DefaultImpl(trait_def_id)) => { let mut projection_bounds = Vec::new(); let trait_ref = object_path_to_poly_trait_ref(this, rscope, @@ -1211,7 +1211,7 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, Some(&d) => d }; match a_def { - def::DefTrait(trait_def_id) => { + def::DefaultImpl(trait_def_id) => { // N.B. this case overlaps somewhat with // TyObjectSum, see that fn for details let mut projection_bounds = Vec::new(); @@ -1821,7 +1821,7 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt, match *ast_bound { ast::TraitTyParamBound(ref b, ast::TraitBoundModifier::None) => { match ::lookup_def_tcx(tcx, b.trait_ref.path.span, b.trait_ref.ref_id) { - def::DefTrait(trait_did) => { + def::DefaultImpl(trait_did) => { match trait_def_ids.get(&trait_did) { // Already seen this trait. We forbid // duplicates in the list (for some diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 34c52981b79..26ba0fe8ed1 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -435,7 +435,7 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat, let def = tcx.def_map.borrow()[pat.id].clone(); let (enum_def_id, variant_def_id) = match def { - def::DefTrait(_) => { + def::DefaultImpl(_) => { let name = pprust::path_to_string(path); span_err!(tcx.sess, pat.span, E0168, "use of trait `{}` in a struct pattern", name); diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index f5a03f0721a..9b1693cba1e 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -330,7 +330,7 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> { cstore: &cstore::CStore, dl: decoder::DefLike) { match dl { - decoder::DlDef(def::DefTrait(did)) => { + decoder::DlDef(def::DefaultImpl(did)) => { traits.push(TraitInfo::new(did)); } decoder::DlDef(def::DefMod(did)) => { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0430954ad7e..81e72ef6326 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3862,7 +3862,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, variant_id, &fields[..]); enum_id } - Some(def::DefTrait(def_id)) => { + Some(def::DefaultImpl(def_id)) => { span_err!(tcx.sess, path.span, E0159, "use of trait `{}` as a struct constructor", pprust::path_to_string(path)); @@ -4634,7 +4634,7 @@ fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, def::DefStruct(id) | def::DefConst(id) => { (ty::lookup_item_type(fcx.tcx(), id), ty::lookup_predicates(fcx.tcx(), id)) } - def::DefTrait(_) | + def::DefaultImpl(_) | def::DefTy(..) | def::DefAssociatedTy(..) | def::DefAssociatedPath(..) | @@ -4738,7 +4738,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, def::DefTy(..) | def::DefAssociatedTy(..) | def::DefAssociatedPath(..) | - def::DefTrait(..) | + def::DefaultImpl(..) | def::DefPrimTy(..) | def::DefTyParam(..) => { // Everything but the final segment should have no diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index b0ded25af17..399795c6656 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -83,12 +83,15 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { } ast::ItemImpl(_, ast::ImplPolarity::Negative, _, Some(ref tref), _, _) => { let trait_ref = ty::node_id_to_trait_ref(ccx.tcx, tref.ref_id); + ty::populate_implementations_for_trait_if_necessary(ccx.tcx, trait_ref.def_id); match ccx.tcx.lang_items.to_builtin_kind(trait_ref.def_id) { Some(ty::BoundSend) | Some(ty::BoundSync) => {} Some(_) | None => { - span_err!(ccx.tcx.sess, item.span, E0192, - "negative impls are currently \ - allowed just for `Send` and `Sync`") + if !ty::trait_has_default_impl(ccx.tcx, trait_ref.def_id) { + span_err!(ccx.tcx.sess, item.span, E0192, + "negative impls are only allowed for traits with \ + default impls (e.g., `Send` and `Sync`)") + } } } } diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index f43469363cd..d34a16a924f 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -96,6 +96,16 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> { } } } + ast::ItemDefaultImpl(_, ref ast_trait_ref) => { + // "Trait" impl + debug!("coherence2::orphan check: default trait impl {}", item.repr(self.tcx)); + let trait_ref = ty::node_id_to_trait_ref(self.tcx, ast_trait_ref.ref_id); + if trait_ref.def_id.krate != ast::LOCAL_CRATE { + span_err!(self.tcx.sess, item.span, E0318, + "cannot create default implementations for traits outside the \ + crate they're defined in; define a new trait instead."); + } + } _ => { // Not an impl } diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 403dcf1e25a..366e934b4dd 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -17,16 +17,22 @@ use middle::infer::{self, new_infer_ctxt}; use syntax::ast::{DefId}; use syntax::ast::{LOCAL_CRATE}; use syntax::ast; -use syntax::codemap::{Span}; +use syntax::ast_util; +use syntax::visit; +use syntax::codemap::Span; use util::ppaux::Repr; pub fn check(tcx: &ty::ctxt) { - let overlap = OverlapChecker { tcx: tcx }; + let mut overlap = OverlapChecker { tcx: tcx }; overlap.check_for_overlapping_impls(); + + // this secondary walk specifically checks for impls of defaulted + // traits, for which additional overlap rules exist + visit::walk_crate(&mut overlap, tcx.map.krate()); } struct OverlapChecker<'cx, 'tcx:'cx> { - tcx: &'cx ty::ctxt<'tcx> + tcx: &'cx ty::ctxt<'tcx>, } impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { @@ -90,17 +96,28 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { return; } - span_err!(self.tcx.sess, self.span_of_impl(impl1_def_id), E0119, + self.report_overlap_error(trait_def_id, impl1_def_id, impl2_def_id); + } + + fn report_overlap_error(&self, trait_def_id: ast::DefId, + impl1: ast::DefId, impl2: ast::DefId) { + + span_err!(self.tcx.sess, self.span_of_impl(impl1), E0119, "conflicting implementations for trait `{}`", ty::item_path_str(self.tcx, trait_def_id)); - if impl2_def_id.krate == ast::LOCAL_CRATE { - span_note!(self.tcx.sess, self.span_of_impl(impl2_def_id), + self.report_overlap_note(impl1, impl2); + } + + fn report_overlap_note(&self, impl1: ast::DefId, impl2: ast::DefId) { + + if impl2.krate == ast::LOCAL_CRATE { + span_note!(self.tcx.sess, self.span_of_impl(impl2), "note conflicting implementation here"); } else { let crate_store = &self.tcx.sess.cstore; - let cdata = crate_store.get_crate_data(impl2_def_id.krate); - span_note!(self.tcx.sess, self.span_of_impl(impl1_def_id), + let cdata = crate_store.get_crate_data(impl2.krate); + span_note!(self.tcx.sess, self.span_of_impl(impl1), "conflicting implementation in crate `{}`", cdata.name); } @@ -111,3 +128,33 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { self.tcx.map.span(impl_did.node) } } + + +impl<'cx, 'tcx,'v> visit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { + fn visit_item(&mut self, item: &'v ast::Item) { + match item.node { + ast::ItemDefaultImpl(_, _) => { + let impl_def_id = ast_util::local_def(item.id); + match ty::impl_trait_ref(self.tcx, impl_def_id) { + Some(ref trait_ref) => { + match ty::trait_default_impl(self.tcx, trait_ref.def_id) { + Some(other_impl) if other_impl != impl_def_id => { + self.report_overlap_error(trait_ref.def_id, + other_impl, + impl_def_id); + } + Some(_) => {} + None => { + self.tcx.sess.bug( + &format!("no default implementation recorded for `{:?}`", + item)[]); + } + } + } + _ => {} + } + } + _ => {} + } + } +} diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index bb5566ab131..353e8e097a8 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -648,6 +648,12 @@ fn convert_item(ccx: &CollectCtxt, it: &ast::Item) { predicates, &enum_definition.variants); }, + ast::ItemDefaultImpl(_, ref ast_trait_ref) => { + let trait_ref = astconv::instantiate_trait_ref(ccx, &ExplicitRscope, + ast_trait_ref, None, None); + + ty::record_default_trait_implementation(tcx, trait_ref.def_id, local_def(it.id)) + } ast::ItemImpl(_, _, ref generics, ref opt_trait_ref, @@ -1141,6 +1147,7 @@ fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, let t = ty::mk_struct(tcx, local_def(it.id), tcx.mk_substs(substs)); ty::TypeScheme { ty: t, generics: ty_generics } } + ast::ItemDefaultImpl(..) | ast::ItemTrait(..) | ast::ItemImpl(..) | ast::ItemMod(..) | @@ -1183,6 +1190,7 @@ fn convert_typed_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, ast::ItemStruct(_, ref generics) => { ty_generic_bounds_for_type_or_impl(ccx, &scheme.generics, generics) } + ast::ItemDefaultImpl(..) | ast::ItemTrait(..) | ast::ItemExternCrate(..) | ast::ItemUse(..) | diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 17cf92d39d8..6f363faef60 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -171,7 +171,9 @@ register_diagnostics! { E0247, // found module name used as a type E0248, // found value name used as a type E0249, // expected constant expr for array length - E0250 // expected constant expr for array length + E0250, // expected constant expr for array length + E0318, // can't create default impls for traits outside their crates + E0319 // trait impls for defaulted traits allowed just for structs/enums } __build_diagnostic_array! { DIAGNOSTICS } diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs index cd4406b770d..93d9ce3df84 100644 --- a/src/librustc_typeck/variance.rs +++ b/src/librustc_typeck/variance.rs @@ -476,6 +476,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> { ast::ItemExternCrate(_) | ast::ItemUse(_) | + ast::ItemDefaultImpl(..) | ast::ItemImpl(..) | ast::ItemStatic(..) | ast::ItemConst(..) | @@ -626,6 +627,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> { ast::ItemForeignMod(..) | ast::ItemTy(..) | ast::ItemImpl(..) | + ast::ItemDefaultImpl(..) | ast::ItemMac(..) => { } } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index d1283d6f46b..4cd6f6551d0 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -69,7 +69,7 @@ fn try_inline_def(cx: &DocContext, tcx: &ty::ctxt, let mut ret = Vec::new(); let did = def.def_id(); let inner = match def { - def::DefTrait(did) => { + def::DefaultImpl(did) => { record_extern_fqn(cx, did, clean::TypeTrait); clean::TraitItem(build_external_trait(cx, tcx, did)) } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 19c34aff9a8..d8ef3194e83 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2431,7 +2431,7 @@ fn register_def(cx: &DocContext, def: def::Def) -> ast::DefId { def::DefFn(i, _) => (i, TypeFunction), def::DefTy(i, false) => (i, TypeTypedef), def::DefTy(i, true) => (i, TypeEnum), - def::DefTrait(i) => (i, TypeTrait), + def::DefaultImpl(i) => (i, TypeTrait), def::DefStruct(i) => (i, TypeStruct), def::DefMod(i) => (i, TypeModule), def::DefStatic(i, _) => (i, TypeStatic), diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index ba5df56f4fb..8143926982f 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -39,6 +39,7 @@ pub struct Module { pub vis: ast::Visibility, pub stab: Option<attr::Stability>, pub impls: Vec<Impl>, + pub def_traits: Vec<DefaultImpl>, pub foreigns: Vec<ast::ForeignMod>, pub macros: Vec<Macro>, pub is_crate: bool, @@ -65,6 +66,7 @@ impl Module { constants : Vec::new(), traits : Vec::new(), impls : Vec::new(), + def_traits : Vec::new(), foreigns : Vec::new(), macros : Vec::new(), is_crate : false, @@ -196,6 +198,12 @@ pub struct Impl { pub id: ast::NodeId, } +pub struct DefaultImpl { + pub unsafety: ast::Unsafety, + pub trait_: ast::TraitRef, + pub id: ast::NodeId, +} + pub struct Macro { pub name: Ident, pub id: ast::NodeId, diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 9181682d176..9f5e3be9e32 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -358,6 +358,14 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { }; om.impls.push(i); }, + ast::ItemDefaultImpl(unsafety, ref trait_ref) => { + let i = DefaultImpl { + unsafety: unsafety, + trait_: trait_ref.clone(), + id: item.id + }; + om.def_traits.push(i); + } ast::ItemForeignMod(ref fm) => { om.foreigns.push(fm.clone()); } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 140e21b5d04..effaac52716 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1641,6 +1641,10 @@ pub enum Item_ { Generics, TyParamBounds, Vec<TraitItem>), + + // Default trait implementations + // `impl Trait for ..` + ItemDefaultImpl(Unsafety, TraitRef), ItemImpl(Unsafety, ImplPolarity, Generics, @@ -1666,7 +1670,8 @@ impl Item_ { ItemStruct(..) => "struct", ItemTrait(..) => "trait", ItemMac(..) | - ItemImpl(..) => "item" + ItemImpl(..) | + ItemDefaultImpl(..) => "item" } } } diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index ba08f61b557..c33158193ce 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -1044,6 +1044,7 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { ItemStruct(..) => "struct", ItemTrait(..) => "trait", ItemImpl(..) => "impl", + ItemDefaultImpl(..) => "default impl", ItemMac(..) => "macro" }; format!("{} {}{}", item_str, path_str, id_str) diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index f660296fcd7..f1228c1d363 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -252,8 +252,12 @@ pub fn name_to_dummy_lifetime(name: Name) -> Lifetime { /// hint of where they came from, (previously they would all just be /// listed as `__extensions__::method_name::hash`, with no indication /// of the type). -pub fn impl_pretty_name(trait_ref: &Option<TraitRef>, ty: &Ty) -> Ident { - let mut pretty = pprust::ty_to_string(ty); +pub fn impl_pretty_name(trait_ref: &Option<TraitRef>, ty: Option<&Ty>) -> Ident { + let mut pretty = match ty { + Some(t) => pprust::ty_to_string(t), + None => String::from_str("..") + }; + match *trait_ref { Some(ref trait_ref) => { pretty.push('.'); diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 36bd8d39a83..a36d3a155b8 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -498,7 +498,7 @@ impl<'a> TraitDef<'a> { // Just mark it now since we know that it'll end up used downstream attr::mark_used(&attr); let opt_trait_ref = Some(trait_ref); - let ident = ast_util::impl_pretty_name(&opt_trait_ref, &*self_type); + let ident = ast_util::impl_pretty_name(&opt_trait_ref, Some(&*self_type)); let mut a = vec![attr]; a.extend(self.attributes.iter().cloned()); cx.item( diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 1fb0642d24f..dae830583c4 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -999,6 +999,9 @@ pub fn noop_fold_item_underscore<T: Folder>(i: Item_, folder: &mut T) -> Item_ { let struct_def = folder.fold_struct_def(struct_def); ItemStruct(struct_def, folder.fold_generics(generics)) } + ItemDefaultImpl(unsafety, ref trait_ref) => { + ItemDefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone())) + } ItemImpl(unsafety, polarity, generics, ifce, ty, impl_items) => { let new_impl_items = impl_items.into_iter().flat_map(|item| { folder.fold_impl_item(item).into_iter() @@ -1150,7 +1153,7 @@ pub fn noop_fold_item_simple<T: Folder>(Item {id, ident, attrs, node, vis, span} let ident = match node { // The node may have changed, recompute the "pretty" impl name. ItemImpl(_, _, _, ref maybe_trait, ref ty, _) => { - ast_util::impl_pretty_name(maybe_trait, &**ty) + ast_util::impl_pretty_name(maybe_trait, Some(&**ty)) } _ => ident }; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 7977574b02b..fec33eddb91 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -31,7 +31,7 @@ use ast::{ExprVec, ExprWhile, ExprWhileLet, ExprForLoop, Field, FnDecl}; use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod, FunctionRetTy}; use ast::{Ident, Inherited, ImplItem, Item, Item_, ItemStatic}; use ast::{ItemEnum, ItemFn, ItemForeignMod, ItemImpl, ItemConst}; -use ast::{ItemMac, ItemMod, ItemStruct, ItemTrait, ItemTy}; +use ast::{ItemMac, ItemMod, ItemStruct, ItemTrait, ItemTy, ItemDefaultImpl}; use ast::{ItemExternCrate, ItemUse}; use ast::{LifetimeDef, Lit, Lit_}; use ast::{LitBool, LitChar, LitByte, LitBinary}; @@ -4787,10 +4787,13 @@ impl<'a> Parser<'a> { (impl_items, inner_attrs) } - /// Parses two variants (with the region/type params always optional): + /// Parses items implementations variants /// impl<T> Foo { ... } - /// impl<T> ToString for ~[T] { ... } + /// impl<T> ToString for &'static T { ... } + /// impl Send for .. {} fn parse_item_impl(&mut self, unsafety: ast::Unsafety) -> ItemInfo { + let impl_span = self.span; + // First, parse type parameters if necessary. let mut generics = self.parse_generics(); @@ -4811,7 +4814,7 @@ impl<'a> Parser<'a> { // Parse traits, if necessary. let opt_trait = if could_be_trait && self.eat_keyword(keywords::For) { // New-style trait. Reinterpret the type as a trait. - let opt_trait_ref = match ty.node { + match ty.node { TyPath(ref path, node_id) => { Some(TraitRef { path: (*path).clone(), @@ -4822,10 +4825,7 @@ impl<'a> Parser<'a> { self.span_err(ty.span, "not a trait"); None } - }; - - ty = self.parse_ty_sum(); - opt_trait_ref + } } else { match polarity { ast::ImplPolarity::Negative => { @@ -4838,14 +4838,27 @@ impl<'a> Parser<'a> { None }; - self.parse_where_clause(&mut generics); - let (impl_items, attrs) = self.parse_impl_items(); + if self.eat(&token::DotDot) { + if generics.is_parameterized() { + self.span_err(impl_span, "default trait implementations are not \ + allowed to have genercis"); + } - let ident = ast_util::impl_pretty_name(&opt_trait, &*ty); + self.expect(&token::OpenDelim(token::Brace)); + self.expect(&token::CloseDelim(token::Brace)); + (ast_util::impl_pretty_name(&opt_trait, None), + ItemDefaultImpl(unsafety, opt_trait.unwrap()), None) + } else { + if opt_trait.is_some() { + ty = self.parse_ty_sum(); + } + self.parse_where_clause(&mut generics); + let (impl_items, attrs) = self.parse_impl_items(); - (ident, - ItemImpl(unsafety, polarity, generics, opt_trait, ty, impl_items), - Some(attrs)) + (ast_util::impl_pretty_name(&opt_trait, Some(&*ty)), + ItemImpl(unsafety, polarity, generics, opt_trait, ty, impl_items), + Some(attrs)) + } } /// Parse a::B<String,i32> diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 92e7f4d2870..869dad867eb 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -926,6 +926,18 @@ impl<'a> State<'a> { try!(self.print_struct(&**struct_def, generics, item.ident, item.span)); } + ast::ItemDefaultImpl(unsafety, ref trait_ref) => { + try!(self.head("")); + try!(self.print_visibility(item.vis)); + try!(self.print_unsafety(unsafety)); + try!(self.word_nbsp("impl")); + try!(self.print_trait_ref(trait_ref)); + try!(space(&mut self.s)); + try!(self.word_space("for")); + try!(self.word_space("..")); + try!(self.bopen()); + try!(self.bclose(item.span)); + } ast::ItemImpl(unsafety, polarity, ref generics, diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 21cb62b0a0c..412bf0fa22a 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -282,6 +282,9 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_generics(type_parameters); walk_enum_def(visitor, enum_definition, type_parameters) } + ItemDefaultImpl(_, ref trait_ref) => { + visitor.visit_trait_ref(trait_ref) + } ItemImpl(_, _, ref type_parameters, ref trait_reference, diff --git a/src/libtest/stats.rs b/src/libtest/stats.rs index 4e94be59ade..7cc07e926b2 100644 --- a/src/libtest/stats.rs +++ b/src/libtest/stats.rs @@ -332,6 +332,7 @@ pub fn winsorize<T: Float + FromPrimitive>(samples: &mut [T], pct: T) { /// Returns a HashMap with the number of occurrences of every element in the /// sequence that the iterator exposes. +#[cfg(not(stage0))] pub fn freq_count<T, U>(iter: T) -> hash_map::HashMap<U, uint> where T: Iterator<Item=U>, U: Eq + Clone + Hash { diff --git a/src/test/compile-fail/coherence-default-trait-impl.rs b/src/test/compile-fail/coherence-default-trait-impl.rs new file mode 100644 index 00000000000..6bcbefb904d --- /dev/null +++ b/src/test/compile-fail/coherence-default-trait-impl.rs @@ -0,0 +1,24 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-linelength + +#![feature(optin_builtin_traits)] + +use std::marker::MarkerTrait; + +trait MyTrait: MarkerTrait {} + +impl MyTrait for .. {} + +impl MyTrait for .. {} +//~^ ERROR conflicting implementations for trait `MyTrait` + +fn main() {} diff --git a/src/test/compile-fail/coherence-impls-builtin.rs b/src/test/compile-fail/coherence-impls-builtin.rs index 38730d241f6..3e132dcb11f 100644 --- a/src/test/compile-fail/coherence-impls-builtin.rs +++ b/src/test/compile-fail/coherence-impls-builtin.rs @@ -34,6 +34,7 @@ unsafe impl Send for [MyType] {} unsafe impl Send for &'static [NotSync] {} //~^ ERROR builtin traits can only be implemented on structs or enums +//~^^ ERROR conflicting implementations for trait `core::marker::Send` fn is_send<T: Send>() {} diff --git a/src/test/compile-fail/recursion_limit.rs b/src/test/compile-fail/recursion_limit.rs index 6cd984c071a..e8bc11317f2 100644 --- a/src/test/compile-fail/recursion_limit.rs +++ b/src/test/compile-fail/recursion_limit.rs @@ -47,4 +47,7 @@ fn main() { //~^^^^ ERROR overflow evaluating //~^^^^^ NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate //~^^^^^^ NOTE required by `is_send` + //~^^^^^^^ ERROR overflow evaluating + //~^^^^^^^^ NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate + //~^^^^^^^^^ NOTE required by `is_send` } diff --git a/src/test/compile-fail/syntaxt-default-trait-impls.rs b/src/test/compile-fail/syntaxt-default-trait-impls.rs new file mode 100644 index 00000000000..a33cd0edca5 --- /dev/null +++ b/src/test/compile-fail/syntaxt-default-trait-impls.rs @@ -0,0 +1,18 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(optin_builtin_traits)] + +trait MyDefaultImpl {} + +impl<T> MyDefaultImpl for .. {} +//~^ ERROR default trait implementations are not allowed to have genercis + +fn main() {} diff --git a/src/test/compile-fail/typeck-default-trait-impl-assoc-type.rs b/src/test/compile-fail/typeck-default-trait-impl-assoc-type.rs new file mode 100644 index 00000000000..8a9d53731c5 --- /dev/null +++ b/src/test/compile-fail/typeck-default-trait-impl-assoc-type.rs @@ -0,0 +1,25 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we do not consider associated types to be sendable without +// some applicable trait bound (and we don't ICE). + +trait Trait { + type AssocType; + fn dummy(&self) { } +} +fn bar<T:Trait+Send>() { + is_send::<T::AssocType>(); //~ ERROR not implemented +} + +fn is_send<T:Send>() { +} + +fn main() { } diff --git a/src/test/compile-fail/typeck-default-trait-impl-constituent-types-2.rs b/src/test/compile-fail/typeck-default-trait-impl-constituent-types-2.rs new file mode 100644 index 00000000000..0f3453da431 --- /dev/null +++ b/src/test/compile-fail/typeck-default-trait-impl-constituent-types-2.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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(optin_builtin_traits)] + +use std::marker::MarkerTrait; + +trait MyTrait: MarkerTrait {} + +impl MyTrait for .. {} + +struct MyS; + +struct MyS2; + +impl !MyTrait for MyS2 {} + +fn is_mytrait<T: MyTrait>() {} + +fn main() { + is_mytrait::<MyS>(); + + is_mytrait::<(MyS2, MyS)>(); + //~^ ERROR the trait `MyTrait` is not implemented for the type `MyS2` +} diff --git a/src/test/compile-fail/typeck-default-trait-impl-constituent-types.rs b/src/test/compile-fail/typeck-default-trait-impl-constituent-types.rs new file mode 100644 index 00000000000..524f467e017 --- /dev/null +++ b/src/test/compile-fail/typeck-default-trait-impl-constituent-types.rs @@ -0,0 +1,35 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(optin_builtin_traits)] + +use std::marker::MarkerTrait; + +trait MyTrait: MarkerTrait {} + +impl MyTrait for .. {} +impl<T> !MyTrait for *mut T {} + +struct MyS; + +struct MyS2; + +impl !MyTrait for MyS2 {} + +struct MyS3; + +fn is_mytrait<T: MyTrait>() {} + +fn main() { + is_mytrait::<MyS>(); + + is_mytrait::<MyS2>(); + //~^ ERROR the trait `MyTrait` is not implemented for the type `MyS2` +} diff --git a/src/test/compile-fail/typeck-default-trait-impl-negation-send.rs b/src/test/compile-fail/typeck-default-trait-impl-negation-send.rs new file mode 100644 index 00000000000..db4d1fe485b --- /dev/null +++ b/src/test/compile-fail/typeck-default-trait-impl-negation-send.rs @@ -0,0 +1,31 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(optin_builtin_traits)] + +struct MySendable { + t: *mut u8 +} + +unsafe impl Send for MySendable {} + +struct MyNotSendable { + t: *mut u8 +} + +impl !Send for MyNotSendable {} + +fn is_send<T: Send>() {} + +fn main() { + is_send::<MySendable>(); + is_send::<MyNotSendable>(); + //~^ ERROR the trait `core::marker::Send` is not implemented for the type `MyNotSendable` +} diff --git a/src/test/compile-fail/typeck-default-trait-impl-negation-sync.rs b/src/test/compile-fail/typeck-default-trait-impl-negation-sync.rs new file mode 100644 index 00000000000..d613589e7d7 --- /dev/null +++ b/src/test/compile-fail/typeck-default-trait-impl-negation-sync.rs @@ -0,0 +1,50 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-linelength + +#![feature(optin_builtin_traits)] + +use std::marker::Managed; +use std::cell::UnsafeCell; + +struct MySync { + t: *mut u8 +} + +unsafe impl Sync for MySync {} + +struct MyNotSync { + t: *mut u8 +} + +impl !Sync for MyNotSync {} + +struct MyTypeWUnsafe { + t: UnsafeCell<u8> +} + +struct MyTypeManaged { + t: Managed +} + +fn is_sync<T: Sync>() {} + +fn main() { + is_sync::<MySync>(); + is_sync::<MyNotSync>(); + //~^ ERROR the trait `core::marker::Sync` is not implemented for the type `MyNotSync` + + is_sync::<MyTypeWUnsafe>(); + //~^ ERROR the trait `core::marker::Sync` is not implemented for the type `core::cell::UnsafeCell<u8>` + + is_sync::<MyTypeManaged>(); + //~^ ERROR the trait `core::marker::Sync` is not implemented for the type `core::marker::Managed` +} diff --git a/src/test/compile-fail/typeck-default-trait-impl-negation.rs b/src/test/compile-fail/typeck-default-trait-impl-negation.rs new file mode 100644 index 00000000000..a1ca0e3e0fa --- /dev/null +++ b/src/test/compile-fail/typeck-default-trait-impl-negation.rs @@ -0,0 +1,44 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(optin_builtin_traits)] + +use std::marker::MarkerTrait; + +trait MyTrait: MarkerTrait {} + +impl MyTrait for .. {} + +unsafe trait MyUnsafeTrait: MarkerTrait {} + +unsafe impl MyUnsafeTrait for .. {} + +struct ThisImplsTrait; + +impl !MyUnsafeTrait for ThisImplsTrait {} + + +struct ThisImplsUnsafeTrait; + +impl !MyTrait for ThisImplsUnsafeTrait {} + +fn is_my_trait<T: MyTrait>() {} +fn is_my_unsafe_trait<T: MyUnsafeTrait>() {} + +fn main() { + is_my_trait::<ThisImplsTrait>(); + is_my_trait::<ThisImplsUnsafeTrait>(); + //~^ ERROR the trait `MyTrait` is not implemented for the type `ThisImplsUnsafeTrait` + + is_my_unsafe_trait::<ThisImplsTrait>(); + //~^ ERROR the trait `MyUnsafeTrait` is not implemented for the type `ThisImplsTrait` + + is_my_unsafe_trait::<ThisImplsUnsafeTrait>(); +} diff --git a/src/test/compile-fail/typeck-default-trait-impl-outside-crate.rs b/src/test/compile-fail/typeck-default-trait-impl-outside-crate.rs new file mode 100644 index 00000000000..10ba8c74164 --- /dev/null +++ b/src/test/compile-fail/typeck-default-trait-impl-outside-crate.rs @@ -0,0 +1,18 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-linelength + +#![feature(optin_builtin_traits)] + +impl Copy for .. {} +//~^ ERROR cannot create default implementations for traits outside the crate they're defined in; define a new trait instead. + +fn main() {} diff --git a/src/test/compile-fail/typeck-default-trait-impl-precedence.rs b/src/test/compile-fail/typeck-default-trait-impl-precedence.rs new file mode 100644 index 00000000000..4006eb2e83e --- /dev/null +++ b/src/test/compile-fail/typeck-default-trait-impl-precedence.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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that declaring that `&T` is `Defaulted` if `T:Signed` implies +// that other `&T` is NOT `Defaulted` if `T:Signed` does not hold. In +// other words, the `..` impl only applies if there are no existing +// impls whose types unify. + +#![feature(optin_builtin_traits)] + +use std::marker::MarkerTrait; + +trait Defaulted : MarkerTrait { } +impl Defaulted for .. { } +impl<'a,T:Signed> Defaulted for &'a T { } +impl<'a,T:Signed> Defaulted for &'a mut T { } +fn is_defaulted<T:Defaulted>() { } + +trait Signed : MarkerTrait { } +impl Signed for i32 { } + +fn main() { + is_defaulted::<&'static i32>(); + is_defaulted::<&'static u32>(); + //~^ ERROR the trait `Signed` is not implemented for the type `u32` +} diff --git a/src/test/compile-fail/typeck-default-trait-impl-send-param.rs b/src/test/compile-fail/typeck-default-trait-impl-send-param.rs new file mode 100644 index 00000000000..185e9dcb3bd --- /dev/null +++ b/src/test/compile-fail/typeck-default-trait-impl-send-param.rs @@ -0,0 +1,21 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we do not consider parameter types to be sendable without +// an explicit trait bound. + +fn foo<T>() { + is_send::<T>() //~ ERROR not implemented +} + +fn is_send<T:Send>() { +} + +fn main() { } diff --git a/src/test/compile-fail/typeck-default-trait-impl-superregion.rs b/src/test/compile-fail/typeck-default-trait-impl-superregion.rs new file mode 100644 index 00000000000..4a6a77ac7b4 --- /dev/null +++ b/src/test/compile-fail/typeck-default-trait-impl-superregion.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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that when a `..` impl applies, we also check that any +// supertrait conditions are met. + +#![feature(optin_builtin_traits)] + +use std::marker::MarkerTrait; + +trait MyTrait : 'static {} + +impl MyTrait for .. {} + +fn foo<T:MyTrait>() { } + +fn bar<'a>() { + foo::<&'a ()>(); //~ ERROR does not fulfill the required lifetime +} + +fn main() { +} diff --git a/src/test/compile-fail/typeck-default-trait-impl-supertrait.rs b/src/test/compile-fail/typeck-default-trait-impl-supertrait.rs new file mode 100644 index 00000000000..7f24058e475 --- /dev/null +++ b/src/test/compile-fail/typeck-default-trait-impl-supertrait.rs @@ -0,0 +1,31 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that when a `..` impl applies, we also check that any +// supertrait conditions are met. + +#![feature(optin_builtin_traits)] + +use std::marker::MarkerTrait; + +trait NotImplemented: MarkerTrait { } + +trait MyTrait : NotImplemented {} + +impl MyTrait for .. {} + +fn foo<T:MyTrait>() { bar::<T>() } + +fn bar<T:NotImplemented>() { } + +fn main() { + foo::<i32>(); //~ ERROR the trait `NotImplemented` is not implemented for the type `i32` + bar::<i64>(); //~ ERROR the trait `NotImplemented` is not implemented for the type `i64` +} diff --git a/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause.rs b/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause.rs new file mode 100644 index 00000000000..c970aaaf5d4 --- /dev/null +++ b/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause.rs @@ -0,0 +1,47 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-linelength + +// Test that when a `..` impl applies, we also check that any +// supertrait conditions are met. + +#![feature(optin_builtin_traits)] + +use std::marker::MarkerTrait; + +trait NotImplemented: MarkerTrait { } + +trait MyTrait: MarkerTrait + where Option<Self> : NotImplemented +{} + +impl NotImplemented for i32 {} + +impl MyTrait for .. {} + +fn foo<T:MyTrait>() { + bar::<Option<T>>() + //~^ ERROR the trait `NotImplemented` is not implemented for the type `core::option::Option<T>` + // + // This should probably typecheck. This is #20671. +} + +fn bar<T:NotImplemented>() { } + +fn test() { + bar::<Option<i32>>(); + //~^ ERROR the trait `NotImplemented` is not implemented for the type `core::option::Option<i32>` +} + +fn main() { + foo::<i32>(); + //~^ ERROR the trait `NotImplemented` is not implemented for the type `core::option::Option<i32>` +} diff --git a/src/test/compile-fail/typeck-negative-impls-builtin.rs b/src/test/compile-fail/typeck-negative-impls-builtin.rs index 557fb2f4f88..57a394dc7f1 100644 --- a/src/test/compile-fail/typeck-negative-impls-builtin.rs +++ b/src/test/compile-fail/typeck-negative-impls-builtin.rs @@ -17,6 +17,6 @@ trait TestTrait { } impl !TestTrait for TestType {} -//~^ ERROR negative impls are currently allowed just for `Send` and `Sync` +//~^ ERROR negative impls are only allowed for traits with default impls (e.g., `Send` and `Sync`) fn main() {} diff --git a/src/test/parse-fail/empty-impl-semicolon.rs b/src/test/parse-fail/empty-impl-semicolon.rs index 70c7d42feb5..a2e780d49b8 100644 --- a/src/test/parse-fail/empty-impl-semicolon.rs +++ b/src/test/parse-fail/empty-impl-semicolon.rs @@ -8,4 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -impl Foo; //~ ERROR expected one of `(`, `+`, `::`, `<`, `for`, `where`, or `{`, found `;` +impl Foo; //~ ERROR expected one of `(`, `+`, `..`, `::`, `<`, `for`, `where`, or `{`, found `;` diff --git a/src/test/parse-fail/multitrait.rs b/src/test/parse-fail/multitrait.rs index f182eb8fa5b..a8b2fa4e115 100644 --- a/src/test/parse-fail/multitrait.rs +++ b/src/test/parse-fail/multitrait.rs @@ -13,7 +13,7 @@ struct S { } impl Cmp, ToString for S { -//~^ ERROR: expected one of `(`, `+`, `::`, `<`, `for`, `where`, or `{`, found `,` +//~^ ERROR: expected one of `(`, `+`, `..`, `::`, `<`, `for`, `where`, or `{`, found `,` fn eq(&&other: S) { false } fn to_string(&self) -> String { "hi".to_string() } } diff --git a/src/test/parse-fail/trait-bounds-not-on-impl.rs b/src/test/parse-fail/trait-bounds-not-on-impl.rs index a034352c4a6..51447b22576 100644 --- a/src/test/parse-fail/trait-bounds-not-on-impl.rs +++ b/src/test/parse-fail/trait-bounds-not-on-impl.rs @@ -13,7 +13,9 @@ trait Foo { struct Bar; -impl Foo + Owned for Bar { //~ ERROR not a trait +impl Foo + Owned for Bar { +//~^ ERROR not a trait +//~^^ ERROR expected one of `..`, `where`, or `{`, found `Bar` } fn main() { } diff --git a/src/test/pretty/default-trait-impl.rs b/src/test/pretty/default-trait-impl.rs new file mode 100644 index 00000000000..d148bb15e99 --- /dev/null +++ b/src/test/pretty/default-trait-impl.rs @@ -0,0 +1,21 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(optin_builtin_traits)] + +// pp-exact + +use std::marker::MarkerTrait; + +trait MyTrait: MarkerTrait { } + +impl MyTrait for .. { } + +pub fn main() { }  | 
