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 { pub value: T, } +impl !Sync for UnsafeCell {} + impl UnsafeCell { /// 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 !Send for *const T { } +impl !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 !Sync for *const T { } +impl !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), + /// Successful resolution to an obligation provided by the caller /// for some type parameter. The `Vec` represents the /// obligations incurred from normalizing the where-clause (if @@ -259,6 +265,12 @@ pub struct VtableImplData<'tcx, N> { pub nested: subst::VecPerParamSpace } +#[derive(Debug,Clone)] +pub struct VtableDefaultImplData { + pub trait_def_id: ast::DefId, + pub nested: Vec +} + #[derive(Debug,Clone)] pub struct VtableBuiltinData { pub nested: subst::VecPerParamSpace @@ -513,17 +525,18 @@ impl<'tcx, N> Vtable<'tcx, N> { pub fn iter_nested(&self) -> Iter { 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(&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 VtableDefaultImplData { + pub fn iter_nested(&self) -> Iter { + self.nested.iter() + } + + pub fn map_nested(&self, op: F) -> VtableDefaultImplData 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(self, op: F) -> VtableDefaultImplData 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 VtableBuiltinData { pub fn iter_nested(&self) -> Iter { 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 + ty::ty_uniq(_) => { // Box 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>) -> Result,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)), - ty::BoundSync => { - if - Some(def_id) == tcx.lang_items.managed_bound() || - Some(def_id) == tcx.lang_items.unsafe_cell_type() - { - return Err(Unimplemented) - } - } + // Shouldn't be coming through here. + ty::BoundSend | ty::BoundSync => unreachable!(), + } + } + } - ty::BoundSized => { } + /// 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 where struct Bar { x: T, y: u32 } -> [i32, u32] + /// Zed where enum Zed { A(T), B(u32) } -> [i32, u32] + /// ``` + fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Option>> { + 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()) } - Ok(If(types)) + 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 + 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::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::ty_struct(def_id, substs) => { + Some(ty::struct_fields(self.tcx(), def_id, substs).iter() + .map(|f| f.mt.ty) + .collect()) + } + + 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>, + 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>) + -> VtableDefaultImplData> + { + 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::>(); + + 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> + /// 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> { - 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>, + recursion_depth: uint) + -> Result, 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, 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, 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 { } } +impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::VtableDefaultImplData { + 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>>>>, + /// Maps a trait onto a list of *default* trait implementations + default_trait_impls: RefCell>, + /// 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 { || Rc::new(csearch::get_item_variances(&tcx.sess.cstore, item_id))) } +pub fn trait_default_impl(tcx: &ctxt, trait_def_id: DefId) -> Option { + 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 { + fn fold_with>(&self, folder: &mut F) -> traits::VtableDefaultImplData { + 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 { fn fold_with>(&self, folder: &mut F) -> traits::VtableBuiltinData { traits::VtableBuiltinData { @@ -519,6 +528,7 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> fn fold_with>(&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> { 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, pub impls: Vec, + pub def_traits: Vec, pub foreigns: Vec, pub macros: Vec, 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), + + // 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, ty: &Ty) -> Ident { - let mut pretty = pprust::ty_to_string(ty); +pub fn impl_pretty_name(trait_ref: &Option, 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(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(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 Foo { ... } - /// impl ToString for ~[T] { ... } + /// impl 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 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(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(iter: T) -> hash_map::HashMap where T: Iterator, 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 or the MIT license +// , 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() {} 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(optin_builtin_traits)] + +trait MyDefaultImpl {} + +impl 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 or the MIT license +// , 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() { + is_send::(); //~ ERROR not implemented +} + +fn is_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 or the MIT license +// , 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() {} + +fn main() { + is_mytrait::(); + + 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 or the MIT license +// , 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 !MyTrait for *mut T {} + +struct MyS; + +struct MyS2; + +impl !MyTrait for MyS2 {} + +struct MyS3; + +fn is_mytrait() {} + +fn main() { + is_mytrait::(); + + is_mytrait::(); + //~^ 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 or the MIT license +// , 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() {} + +fn main() { + is_send::(); + is_send::(); + //~^ 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 or the MIT license +// , 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 +} + +struct MyTypeManaged { + t: Managed +} + +fn is_sync() {} + +fn main() { + is_sync::(); + is_sync::(); + //~^ ERROR the trait `core::marker::Sync` is not implemented for the type `MyNotSync` + + is_sync::(); + //~^ ERROR the trait `core::marker::Sync` is not implemented for the type `core::cell::UnsafeCell` + + is_sync::(); + //~^ 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 or the MIT license +// , 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() {} +fn is_my_unsafe_trait() {} + +fn main() { + is_my_trait::(); + is_my_trait::(); + //~^ ERROR the trait `MyTrait` is not implemented for the type `ThisImplsUnsafeTrait` + + is_my_unsafe_trait::(); + //~^ ERROR the trait `MyUnsafeTrait` is not implemented for the type `ThisImplsTrait` + + is_my_unsafe_trait::(); +} 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 or the MIT license +// , 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 or the MIT license +// , 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() { } + +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 or the MIT license +// , 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() { + is_send::() //~ ERROR not implemented +} + +fn is_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 or the MIT license +// , 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() { } + +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 or the MIT license +// , 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() { bar::() } + +fn bar() { } + +fn main() { + foo::(); //~ ERROR the trait `NotImplemented` is not implemented for the type `i32` + bar::(); //~ 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 or the MIT license +// , 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 : NotImplemented +{} + +impl NotImplemented for i32 {} + +impl MyTrait for .. {} + +fn foo() { + bar::>() + //~^ ERROR the trait `NotImplemented` is not implemented for the type `core::option::Option` + // + // This should probably typecheck. This is #20671. +} + +fn bar() { } + +fn test() { + bar::>(); + //~^ ERROR the trait `NotImplemented` is not implemented for the type `core::option::Option` +} + +fn main() { + foo::(); + //~^ ERROR the trait `NotImplemented` is not implemented for the type `core::option::Option` +} 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 or the MIT license +// , 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() { }