Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for default trait implementations #21689

Merged
merged 32 commits into from
Feb 24, 2015
Merged
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
6a2f16e
Add support for default trait impls in libsyntax
flaper87 Jan 22, 2015
4148d53
Fix fallout from libsyntax implementation
flaper87 Jan 22, 2015
a962d47
look for default trait candidates
flaper87 Jan 24, 2015
839a9de
Prefer other implementations over default ones
flaper87 Jan 24, 2015
ad3e748
Don't allow default impls for traits outside their crate
flaper87 Jan 26, 2015
bd511f7
Add negative impls for `*const T` and `*mut T`
flaper87 Jan 26, 2015
7ae8889
Add negative impls for Sync
flaper87 Jan 26, 2015
58a8103
Fix rustdoc fallout
flaper87 Jan 26, 2015
4b09209
Ensure default trait impls hold
flaper87 Feb 2, 2015
d523acb
Use a Vec<N> instead of VecPerParamSpace<N>
flaper87 Feb 4, 2015
7e38213
Make default_trait_impls private and add accessor
flaper87 Feb 7, 2015
d38aab3
Rename DefTrait to DefaultImpl
flaper87 Feb 7, 2015
f0e9bd9
address nits
flaper87 Feb 7, 2015
1e3ed61
Coherence for default trait implementations
flaper87 Feb 13, 2015
d215411
Make Send/Sync go through the default implementation path
flaper87 Feb 18, 2015
40fffc9
Some nits and cleanup
nikomatsakis Feb 18, 2015
0be1e43
Fix error codes
flaper87 Feb 18, 2015
7213ef1
Test all the things
flaper87 Jan 27, 2015
f7a75e0
Add new test case showing that supertraits are not enough
nikomatsakis Feb 19, 2015
64d33d8
check supertraits
flaper87 Feb 18, 2015
24bdce4
some comments and nits
nikomatsakis Feb 19, 2015
e8df95d
mark candidate set ambig for defaulted traits where self-type is not …
nikomatsakis Feb 19, 2015
38ef5ee
Check constituent types are known
flaper87 Feb 19, 2015
1cc5a87
Don't report bug for IntVar and FloatVar
flaper87 Feb 20, 2015
640000a
fix treatment of parameters and associated types
nikomatsakis Feb 20, 2015
3ebc2ab
tweak exhaustive matching of ty_infer
nikomatsakis Feb 20, 2015
6d1844c
Record default implementations in a separate step
flaper87 Feb 20, 2015
3343e9c
Add new test for impl precedence and remove unnecessary coherence rul…
nikomatsakis Feb 20, 2015
d021c55
Restore the coherence visitor and fix fallouts
flaper87 Feb 20, 2015
753db88
allow negative impls for traits that have a default impl
flaper87 Feb 21, 2015
038d7e6
Fix test fallouts
flaper87 Feb 21, 2015
3dcc631
Add additional test case for superregion
nikomatsakis Feb 22, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/libcore/cell.rs
Original file line number Diff line number Diff line change
@@ -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.
1 change: 1 addition & 0 deletions src/libcore/lib.rs
Original file line number Diff line number Diff line change
@@ -68,6 +68,7 @@
#![feature(staged_api)]
#![feature(unboxed_closures)]
#![feature(rustc_attrs)]
#![feature(optin_builtin_traits)]

#[macro_use]
mod macros;
8 changes: 8 additions & 0 deletions src/libcore/marker.rs
Original file line number Diff line number Diff line change
@@ -49,6 +49,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"]
@@ -214,6 +218,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.
4 changes: 4 additions & 0 deletions src/librustc/metadata/csearch.rs
Original file line number Diff line number Diff line change
@@ -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)
}
19 changes: 15 additions & 4 deletions src/librustc/metadata/decoder.rs
Original file line number Diff line number Diff line change
@@ -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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a comment explaining what this is checking for? I haven't finished reading yet but i'm definitely a bit confused as to what a "default trait" is -- the name says trait, but it's treated like an impl.

let item_doc = lookup_item(id, cdata.data());
match item_family(item_doc) {
Family::DefaultImpl => true,
_ => false
}
}
12 changes: 12 additions & 0 deletions src/librustc/metadata/encoder.rs
Original file line number Diff line number Diff line change
@@ -1201,6 +1201,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.
2 changes: 1 addition & 1 deletion src/librustc/middle/astencode.rs
Original file line number Diff line number Diff line change
@@ -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) =>
4 changes: 2 additions & 2 deletions src/librustc/middle/def.rs
Original file line number Diff line number Diff line change
@@ -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), _) => {
2 changes: 1 addition & 1 deletion src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
@@ -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(..)=> {
3 changes: 2 additions & 1 deletion src/librustc/middle/reachable.rs
Original file line number Diff line number Diff line change
@@ -301,7 +301,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,
3 changes: 2 additions & 1 deletion src/librustc/middle/resolve_lifetime.rs
Original file line number Diff line number Diff line change
@@ -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);
});
45 changes: 42 additions & 3 deletions src/librustc/middle/traits/mod.rs
Original file line number Diff line number Diff line change
@@ -221,6 +221,12 @@ pub enum Vtable<'tcx, N> {
/// Vtable identifying a particular impl.
VtableImpl(VtableImplData<'tcx, N>),

/// Vtable for default trait implementations
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's expand this comment a bit more. I think this corresponds to what happens when a impl Foo for .. impl is matched, right? I also suspect it should carry some nested obligations, which would will correspond to the supertraits of the defaulted trait.

/// 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
@@ -259,6 +265,12 @@ pub struct VtableImplData<'tcx, N> {
pub nested: subst::VecPerParamSpace<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()
1 change: 1 addition & 0 deletions src/librustc/middle/traits/project.rs
Original file line number Diff line number Diff line change
@@ -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(
Loading