support `default impl` for specialization

this commit implements the first step of the `default impl` feature:
all items in a `default impl` are (implicitly) `default` and hence
specializable.
In order to test this feature I've copied all the tests provided for the
`default` method implementation (in run-pass/specialization and
compile-fail/specialization directories) and moved the `default` keyword
from the item to the impl.
See referenced issue for further info
This commit is contained in:
Gianni Ciccarelli 2016-11-18 17:14:42 +01:00
parent 15ce54096a
commit 116e9831a5
50 changed files with 1078 additions and 41 deletions

2
cargo

@ -1 +1 @@
Subproject commit 8326a3683a9045d825e4fdc4021af340ee3b3755
Subproject commit c416fb60b11ecfd2a1ba0fb8567c9a92590b5d28

2
rls

@ -1 +1 @@
Subproject commit 6ecff95fdc3ee7ceed2b9b0cc1a3a64876860bce
Subproject commit 016cbc514cf44a2bd3fe806e8afa6b9c50287373

@ -1 +1 @@
Subproject commit d30da544a8afc5d78391dee270bdf40e74a215d3
Subproject commit a8fc4c169fac43a5dc204d4fd56ddb1739f8c178

@ -1 +1 @@
Subproject commit ad7de198561b3a12217ea2da76d796d9c7fc0ed3
Subproject commit beea82b9230cd641dd1ca263cf31025ace4aebb5

@ -1 +1 @@
Subproject commit 6b0de90d87dda15e323ef24cdf7ed873ac5cf4d3
Subproject commit b060f732145f2fa16df84c74e511df08a3a47c5d

@ -1 +1 @@
Subproject commit 11bfb0dcf85f7aa92abd30524bb1e42e18d108c6
Subproject commit e058ca661692a8d01f8cf9d35939dfe3105ce968

@ -1 +1 @@
Subproject commit c34a802d1eb037b44c5252078c7270b5472e0f65
Subproject commit 05a2d197356ef253dfd985166576619ac9b6947f

View File

@ -1326,7 +1326,13 @@ impl<'a> LoweringContext<'a> {
hir::ItemDefaultImpl(self.lower_unsafety(unsafety),
trait_ref)
}
ItemKind::Impl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => {
ItemKind::Impl(unsafety,
polarity,
defaultness,
ref generics,
ref ifce,
ref ty,
ref impl_items) => {
let new_impl_items = impl_items.iter()
.map(|item| self.lower_impl_item_ref(item))
.collect();
@ -1340,6 +1346,7 @@ impl<'a> LoweringContext<'a> {
hir::ItemImpl(self.lower_unsafety(unsafety),
self.lower_impl_polarity(polarity),
self.lower_defaultness(defaultness),
self.lower_generics(generics),
ifce,
self.lower_ty(ty),

View File

@ -1712,6 +1712,7 @@ pub enum Item_ {
/// An implementation, eg `impl<A> Trait for Foo { .. }`
ItemImpl(Unsafety,
ImplPolarity,
Defaultness,
Generics,
Option<TraitRef>, // (optional) trait this impl implements
P<Ty>, // self

View File

@ -678,12 +678,14 @@ impl<'a> State<'a> {
}
hir::ItemImpl(unsafety,
polarity,
defaultness,
ref generics,
ref opt_trait,
ref ty,
ref impl_items) => {
self.head("")?;
self.print_visibility(&item.vis)?;
self.print_defaultness(defaultness)?;
self.print_unsafety(unsafety)?;
self.word_nbsp("impl")?;
@ -820,6 +822,13 @@ impl<'a> State<'a> {
}
}
pub fn print_defaultness(&mut self, defaultness: hir::Defaultness) -> io::Result<()> {
if let hir::Defaultness::Default = defaultness {
self.word_nbsp("default")?;
}
Ok(())
}
pub fn print_struct(&mut self,
struct_def: &hir::VariantData,
generics: &hir::Generics,
@ -931,11 +940,7 @@ impl<'a> State<'a> {
self.hardbreak_if_not_bol()?;
self.maybe_print_comment(ii.span.lo)?;
self.print_outer_attributes(&ii.attrs)?;
match ii.defaultness {
hir::Defaultness::Default { .. } => self.word_nbsp("default")?,
hir::Defaultness::Final => (),
}
self.print_defaultness(ii.defaultness)?;
match ii.node {
hir::ImplItemKind::Const(ref ty, expr) => {

View File

@ -50,7 +50,7 @@ fn item_might_be_inlined(item: &hir::Item) -> bool {
}
match item.node {
hir::ItemImpl(_, _, ref generics, ..) |
hir::ItemImpl(_, _, _, ref generics, ..) |
hir::ItemFn(.., ref generics, _) => {
generics_require_inlining(generics)
}
@ -186,7 +186,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
// does too.
let impl_node_id = self.tcx.hir.as_local_node_id(impl_did).unwrap();
match self.tcx.hir.expect_item(impl_node_id).node {
hir::ItemImpl(_, _, ref generics, ..) => {
hir::ItemImpl(_, _, _, ref generics, ..) => {
generics_require_inlining(generics)
}
_ => false

View File

@ -331,7 +331,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
hir::ItemStruct(_, ref generics) |
hir::ItemUnion(_, ref generics) |
hir::ItemTrait(_, ref generics, ..) |
hir::ItemImpl(_, _, ref generics, ..) => {
hir::ItemImpl(_, _, _, ref generics, ..) => {
// These kinds of items have only early bound lifetime parameters.
let mut index = if let hir::ItemTrait(..) = item.node {
1 // Self comes before lifetimes
@ -834,7 +834,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}
match parent.node {
hir::ItemTrait(_, ref generics, ..) |
hir::ItemImpl(_, _, ref generics, ..) => {
hir::ItemImpl(_, _, _, ref generics, ..) => {
index += (generics.lifetimes.len() + generics.ty_params.len()) as u32;
}
_ => {}

View File

@ -33,6 +33,7 @@ use ty::subst::Subst;
use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt};
use ty::fold::{TypeFoldable, TypeFolder};
use util::common::FN_OUTPUT_NAME;
use hir::{self};
/// Depending on the stage of compilation, we want projection to be
/// more or less conservative.
@ -923,7 +924,28 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
// being invoked).
node_item.item.defaultness.has_value()
} else {
node_item.item.defaultness.is_default()
let is_default = match selcx.tcx()
.map
.as_local_node_id(node_item.node.def_id()) {
Some(node_id) => {
let item = selcx.tcx().map.expect_item(node_id);
if let hir::ItemImpl(_, _, defaultness, ..) = item.node {
defaultness.is_default()
} else {
false
}
}
None => {
selcx.tcx()
.global_tcx()
.sess
.cstore
.impl_defaultness(node_item.node.def_id())
.is_default()
}
};
node_item.item.defaultness.is_default() || is_default
};
// Only reveal a specializable default if we're past type-checking

View File

@ -90,6 +90,7 @@ provide! { <'tcx> tcx, def_id, cdata
associated_item => { cdata.get_associated_item(def_id.index) }
impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) }
impl_polarity => { cdata.get_impl_polarity(def_id.index) }
impl_defaultness => { cdata.get_impl_defaultness(def_id.index) }
coerce_unsized_info => {
cdata.get_coerce_unsized_info(def_id.index).unwrap_or_else(|| {
bug!("coerce_unsized_info: `{:?}` is missing its info", def_id);

View File

@ -629,6 +629,10 @@ impl<'a, 'tcx> CrateMetadata {
self.get_impl_data(id).polarity
}
pub fn get_impl_defaultness(&self, id: DefIndex) -> hir::Defaultness {
self.get_impl_data(id).defaultness
}
pub fn get_coerce_unsized_info(&self,
id: DefIndex)
-> Option<ty::adjustment::CoerceUnsizedInfo> {

View File

@ -706,6 +706,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
hir::ItemDefaultImpl(..) => {
let data = ImplData {
polarity: hir::ImplPolarity::Positive,
defaultness: hir::Defaultness::Final,
parent_impl: None,
coerce_unsized_info: None,
trait_ref: tcx.impl_trait_ref(def_id).map(|trait_ref| self.lazy(&trait_ref)),
@ -713,7 +714,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
EntryKind::DefaultImpl(self.lazy(&data))
}
hir::ItemImpl(_, polarity, ..) => {
hir::ItemImpl(_, polarity, defaultness, ..) => {
let trait_ref = tcx.impl_trait_ref(def_id);
let parent = if let Some(trait_ref) = trait_ref {
let trait_def = tcx.lookup_trait_def(trait_ref.def_id);
@ -740,6 +741,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
let data = ImplData {
polarity: polarity,
defaultness: defaultness,
parent_impl: parent,
coerce_unsized_info: coerce_unsized_info,
trait_ref: trait_ref.map(|trait_ref| self.lazy(&trait_ref)),

View File

@ -406,6 +406,7 @@ impl_stable_hash_for!(struct TraitData<'tcx> {
#[derive(RustcEncodable, RustcDecodable)]
pub struct ImplData<'tcx> {
pub polarity: hir::ImplPolarity,
pub defaultness: hir::Defaultness,
pub parent_impl: Option<DefId>,
/// This is `Some` only for impls of `CoerceUnsized`.

View File

@ -429,8 +429,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
}
}
None => {
if let Some(NodeItem(item)) = self.tcx.hir.get_if_local(id) {
if let hir::ItemImpl(_, _, _, _, ref ty, _) = item.node {
if let Some(NodeItem(item)) = self.tcx.map.get_if_local(id) {
if let hir::ItemImpl(_, _, _, _, _, ref ty, _) = item.node {
trait_id = self.lookup_def_id(ty.id);
}
}

View File

@ -880,7 +880,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> {
let parent_node_id = hir_map.get_parent_node(ii.id);
let is_impl_generic = match hir_map.expect_item(parent_node_id) {
&hir::Item {
node: hir::ItemImpl(_, _, ref generics, ..),
node: hir::ItemImpl(_, _, _, ref generics, ..),
..
} => {
generics.is_type_parameterized()
@ -911,6 +911,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, '
let tcx = scx.tcx();
match item.node {
hir::ItemImpl(_,
_,
_,
ref generics,
..,

View File

@ -1142,7 +1142,23 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
if let Some(parent) = parent {
if parent.item.is_final() {
report_forbidden_specialization(tcx, impl_item, parent.node.def_id());
let is_final = match tcx.map.as_local_node_id(parent.node.def_id()) {
Some(node_id) => {
let item = tcx.map.expect_item(node_id);
if let hir::ItemImpl(_, _, defaultness, ..) = item.node {
defaultness.is_final()
} else {
true
}
}
None => {
tcx.global_tcx().sess.cstore.impl_defaultness(parent.node.def_id()).is_final()
}
};
if is_final {
report_forbidden_specialization(tcx, impl_item, parent.node.def_id());
}
}
}

View File

@ -105,11 +105,11 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
///
/// won't be allowed unless there's an *explicit* implementation of `Send`
/// for `T`
hir::ItemImpl(_, hir::ImplPolarity::Positive, _,
hir::ItemImpl(_, hir::ImplPolarity::Positive, _, _,
ref trait_ref, ref self_ty, _) => {
self.check_impl(item, self_ty, trait_ref);
}
hir::ItemImpl(_, hir::ImplPolarity::Negative, _, Some(_), ..) => {
hir::ItemImpl(_, hir::ImplPolarity::Negative, _, _, Some(_), ..) => {
// FIXME(#27579) what amount of WF checking do we need for neg impls?
let trait_ref = tcx.impl_trait_ref(tcx.hir.local_def_id(item.id)).unwrap();

View File

@ -87,7 +87,7 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for UnsafetyChecker<'cx, 'tcx> {
hir::ItemDefaultImpl(unsafety, _) => {
self.check_unsafety_coherence(item, None, unsafety, hir::ImplPolarity::Positive);
}
hir::ItemImpl(unsafety, polarity, ref generics, Some(_), _, _) => {
hir::ItemImpl(unsafety, polarity, _, ref generics, ..) => {
self.check_unsafety_coherence(item, Some(generics), unsafety, polarity);
}
_ => {}

View File

@ -214,6 +214,7 @@ pub struct Trait {
pub struct Impl {
pub unsafety: hir::Unsafety,
pub polarity: hir::ImplPolarity,
pub defaultness: hir::Defaultness,
pub generics: hir::Generics,
pub trait_: Option<hir::TraitRef>,
pub for_: P<hir::Ty>,

View File

@ -502,7 +502,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
om.traits.push(t);
},
hir::ItemImpl(unsafety, polarity, ref gen, ref tr, ref ty, ref item_ids) => {
hir::ItemImpl(unsafety, polarity, defaultness, ref gen, ref tr, ref ty, ref item_ids) => {
// Don't duplicate impls when inlining, we'll pick them up
// regardless of where they're located.
if !self.inlining {
@ -512,6 +512,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
let i = Impl {
unsafety: unsafety,
polarity: polarity,
defaultness: defaultness,
generics: gen.clone(),
trait_: tr.clone(),
for_: ty.clone(),

View File

@ -1852,6 +1852,7 @@ pub enum ItemKind {
/// E.g. `impl<A> Foo<A> { .. }` or `impl<A> Trait for Foo<A> { .. }`
Impl(Unsafety,
ImplPolarity,
Defaultness,
Generics,
Option<TraitRef>, // (optional) trait this impl implements
P<Ty>, // self

View File

@ -1215,7 +1215,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
and possibly buggy");
}
ast::ItemKind::Impl(_, polarity, _, _, _, _) => {
ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => {
match polarity {
ast::ImplPolarity::Negative => {
gate_feature_post!(&self, optin_builtin_traits,
@ -1225,6 +1225,15 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
},
_ => {}
}
match defaultness {
ast::Defaultness::Default => {
gate_feature_post!(&self, specialization,
i.span,
"specialization is unstable");
}
_ => {}
}
}
_ => {}

View File

@ -897,9 +897,16 @@ pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind {
ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
ItemKind::DefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone()))
}
ItemKind::Impl(unsafety, polarity, generics, ifce, ty, impl_items) => ItemKind::Impl(
ItemKind::Impl(unsafety,
polarity,
defaultness,
generics,
ifce,
ty,
impl_items) => ItemKind::Impl(
unsafety,
polarity,
defaultness,
folder.fold_generics(generics),
ifce.map(|trait_ref| folder.fold_trait_ref(trait_ref.clone())),
folder.fold_ty(ty),

View File

@ -4863,7 +4863,9 @@ impl<'a> Parser<'a> {
/// impl<T> Foo { ... }
/// impl<T> ToString for &'static T { ... }
/// impl Send for .. {}
fn parse_item_impl(&mut self, unsafety: ast::Unsafety) -> PResult<'a, ItemInfo> {
fn parse_item_impl(&mut self,
unsafety: ast::Unsafety,
defaultness: Defaultness) -> PResult<'a, ItemInfo> {
let impl_span = self.span;
// First, parse type parameters if necessary.
@ -4944,7 +4946,7 @@ impl<'a> Parser<'a> {
}
Ok((keywords::Invalid.ident(),
ItemKind::Impl(unsafety, polarity, generics, opt_trait, ty, impl_items),
ItemKind::Impl(unsafety, polarity, defaultness, generics, opt_trait, ty, impl_items),
Some(attrs)))
}
}
@ -5756,13 +5758,19 @@ impl<'a> Parser<'a> {
maybe_append(attrs, extra_attrs));
return Ok(Some(item));
}
if self.check_keyword(keywords::Unsafe) &&
self.look_ahead(1, |t| t.is_keyword(keywords::Impl))
if (self.check_keyword(keywords::Unsafe) &&
self.look_ahead(1, |t| t.is_keyword(keywords::Impl))) ||
(self.check_keyword(keywords::Default) &&
self.look_ahead(1, |t| t.is_keyword(keywords::Unsafe)) &&
self.look_ahead(2, |t| t.is_keyword(keywords::Impl)))
{
// IMPL ITEM
let defaultness = self.parse_defaultness()?;
self.expect_keyword(keywords::Unsafe)?;
self.expect_keyword(keywords::Impl)?;
let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Unsafe)?;
let (ident,
item_,
extra_attrs) = self.parse_item_impl(ast::Unsafety::Unsafe, defaultness)?;
let prev_span = self.prev_span;
let item = self.mk_item(lo.to(prev_span),
ident,
@ -5856,9 +5864,16 @@ impl<'a> Parser<'a> {
maybe_append(attrs, extra_attrs));
return Ok(Some(item));
}
if self.eat_keyword(keywords::Impl) {
if (self.check_keyword(keywords::Impl)) ||
(self.check_keyword(keywords::Default) &&
self.look_ahead(1, |t| t.is_keyword(keywords::Impl)))
{
// IMPL ITEM
let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Normal)?;
let defaultness = self.parse_defaultness()?;
self.expect_keyword(keywords::Impl)?;
let (ident,
item_,
extra_attrs) = self.parse_item_impl(ast::Unsafety::Normal, defaultness)?;
let prev_span = self.prev_span;
let item = self.mk_item(lo.to(prev_span),
ident,

View File

@ -1317,12 +1317,14 @@ impl<'a> State<'a> {
}
ast::ItemKind::Impl(unsafety,
polarity,
defaultness,
ref generics,
ref opt_trait,
ref ty,
ref impl_items) => {
self.head("")?;
self.print_visibility(&item.vis)?;
self.print_defaultness(defaultness)?;
self.print_unsafety(unsafety)?;
self.word_nbsp("impl")?;
@ -1477,6 +1479,13 @@ impl<'a> State<'a> {
}
}
pub fn print_defaultness(&mut self, defatulness: ast::Defaultness) -> io::Result<()> {
if let ast::Defaultness::Default = defatulness {
try!(self.word_nbsp("default"));
}
Ok(())
}
pub fn print_struct(&mut self,
struct_def: &ast::VariantData,
generics: &ast::Generics,
@ -1602,9 +1611,7 @@ impl<'a> State<'a> {
self.hardbreak_if_not_bol()?;
self.maybe_print_comment(ii.span.lo)?;
self.print_outer_attributes(&ii.attrs)?;
if let ast::Defaultness::Default = ii.defaultness {
self.word_nbsp("default")?;
}
self.print_defaultness(ii.defaultness)?;
match ii.node {
ast::ImplItemKind::Const(ref ty, ref expr) => {
self.print_associated_const(ii.ident, &ty, Some(&expr), &ii.vis)?;

View File

@ -266,7 +266,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
ItemKind::DefaultImpl(_, ref trait_ref) => {
visitor.visit_trait_ref(trait_ref)
}
ItemKind::Impl(_, _,
ItemKind::Impl(_, _, _,
ref type_parameters,
ref opt_trait_reference,
ref typ,

View File

@ -658,6 +658,7 @@ impl<'a> TraitDef<'a> {
a,
ast::ItemKind::Impl(unsafety,
ast::ImplPolarity::Positive,
ast::Defaultness::Final,
trait_generics,
opt_trait_ref,
self_type,

@ -1 +0,0 @@
Subproject commit da282f1bb7277b4d30fa1599ee29ad8eb4dd2a92

View File

@ -0,0 +1,46 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(specialization)]
// Make sure we can't project defaulted associated types
trait Foo {
type Assoc;
}
default impl<T> Foo for T {
type Assoc = ();
}
impl Foo for u8 {
type Assoc = String;
}
fn generic<T>() -> <T as Foo>::Assoc {
// `T` could be some downstream crate type that specializes (or,
// for that matter, `u8`).
() //~ ERROR mismatched types
}
fn monomorphic() -> () {
// Even though we know that `()` is not specialized in a
// downstream crate, typeck refuses to project here.
generic::<()>() //~ ERROR mismatched types
}
fn main() {
// No error here, we CAN project from `u8`, as there is no `default`
// in that impl.
let s: String = generic::<u8>();
println!("{}", s); // bad news if this all compiles
}

View File

@ -0,0 +1,45 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// It should not be possible to use the concrete value of a defaulted
// associated type in the impl defining it -- otherwise, what happens
// if it's overridden?
#![feature(specialization)]
trait Example {
type Output;
fn generate(self) -> Self::Output;
}
default impl<T> Example for T {
type Output = Box<T>;
fn generate(self) -> Self::Output {
Box::new(self) //~ ERROR mismatched types
}
}
impl Example for bool {
type Output = bool;
fn generate(self) -> bool { self }
}
fn trouble<T>(t: T) -> Box<T> {
Example::generate(t) //~ ERROR mismatched types
}
fn weaponize() -> bool {
let b: Box<bool> = trouble(true);
*b
}
fn main() {
weaponize();
}

View File

@ -0,0 +1,21 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Check that specialization must be ungated to use the `default` keyword
trait Foo {
fn foo(&self);
}
default impl<T> Foo for T { //~ ERROR specialization is unstable
fn foo(&self) {}
}
fn main() {}

View File

@ -0,0 +1,95 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(specialization)]
// Check a number of scenarios in which one impl tries to override another,
// without correctly using `default`.
////////////////////////////////////////////////////////////////////////////////
// Test 1: one layer of specialization, multiple methods, missing `default`
////////////////////////////////////////////////////////////////////////////////
trait Foo {
fn foo(&self);
fn bar(&self);
}
impl<T> Foo for T {
fn foo(&self) {}
fn bar(&self) {}
}
impl Foo for u8 {}
impl Foo for u16 {
fn foo(&self) {} //~ ERROR E0520
}
impl Foo for u32 {
fn bar(&self) {} //~ ERROR E0520
}
////////////////////////////////////////////////////////////////////////////////
// Test 2: one layer of specialization, missing `default` on associated type
////////////////////////////////////////////////////////////////////////////////
trait Bar {
type T;
}
impl<T> Bar for T {
type T = u8;
}
impl Bar for u8 {
type T = (); //~ ERROR E0520
}
////////////////////////////////////////////////////////////////////////////////
// Test 3a: multiple layers of specialization, missing interior `default`
////////////////////////////////////////////////////////////////////////////////
trait Baz {
fn baz(&self);
}
default impl<T> Baz for T {
fn baz(&self) {}
}
impl<T: Clone> Baz for T {
fn baz(&self) {}
}
impl Baz for i32 {
fn baz(&self) {} //~ ERROR E0520
}
////////////////////////////////////////////////////////////////////////////////
// Test 3b: multiple layers of specialization, missing interior `default`,
// redundant `default` in bottom layer.
////////////////////////////////////////////////////////////////////////////////
trait Redundant {
fn redundant(&self);
}
default impl<T> Redundant for T {
fn redundant(&self) {}
}
impl<T: Clone> Redundant for T {
fn redundant(&self) {}
}
default impl Redundant for i32 {
fn redundant(&self) {} //~ ERROR E0520
}
fn main() {}

View File

@ -0,0 +1,53 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(specialization)]
// Common code used for tests that model the Fn/FnMut/FnOnce hierarchy.
pub trait Go {
fn go(&self, arg: isize);
}
pub fn go<G:Go>(this: &G, arg: isize) {
this.go(arg)
}
pub trait GoMut {
fn go_mut(&mut self, arg: isize);
}
pub fn go_mut<G:GoMut>(this: &mut G, arg: isize) {
this.go_mut(arg)
}
pub trait GoOnce {
fn go_once(self, arg: isize);
}
pub fn go_once<G:GoOnce>(this: G, arg: isize) {
this.go_once(arg)
}
default impl<G> GoMut for G
where G : Go
{
fn go_mut(&mut self, arg: isize) {
go(&*self, arg)
}
}
default impl<G> GoOnce for G
where G : GoMut
{
fn go_once(mut self, arg: isize) {
go_mut(&mut self, arg)
}
}

View File

@ -0,0 +1,82 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(specialization)]
pub trait Foo {
fn foo(&self) -> &'static str;
}
default impl<T> Foo for T {
fn foo(&self) -> &'static str {
"generic"
}
}
default impl<T: Clone> Foo for T {
fn foo(&self) -> &'static str {
"generic Clone"
}
}
default impl<T, U> Foo for (T, U) where T: Clone, U: Clone {
fn foo(&self) -> &'static str {
"generic pair"
}
}
default impl<T: Clone> Foo for (T, T) {
fn foo(&self) -> &'static str {
"generic uniform pair"
}
}
default impl Foo for (u8, u32) {
fn foo(&self) -> &'static str {
"(u8, u32)"
}
}
default impl Foo for (u8, u8) {
fn foo(&self) -> &'static str {
"(u8, u8)"
}
}
default impl<T: Clone> Foo for Vec<T> {
fn foo(&self) -> &'static str {
"generic Vec"
}
}
impl Foo for Vec<i32> {
fn foo(&self) -> &'static str {
"Vec<i32>"
}
}
impl Foo for String {
fn foo(&self) -> &'static str {
"String"
}
}
impl Foo for i32 {
fn foo(&self) -> &'static str {
"i32"
}
}
pub trait MyMarker {}
default impl<T: Clone + MyMarker> Foo for T {
fn foo(&self) -> &'static str {
"generic Clone + MyMarker"
}
}

View File

@ -0,0 +1,49 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(specialization)]
// First, test only use of explicit `default` items:
pub trait Foo {
fn foo(&self) -> bool;
}
default impl<T> Foo for T {
fn foo(&self) -> bool { false }
}
impl Foo for i32 {}
impl Foo for i64 {
fn foo(&self) -> bool { true }
}
// Next, test mixture of explicit `default` and provided methods:
pub trait Bar {
fn bar(&self) -> i32 { 0 }
}
impl<T> Bar for T {} // use the provided method
impl Bar for i32 {
fn bar(&self) -> i32 { 1 }
}
impl<'a> Bar for &'a str {}
default impl<T> Bar for Vec<T> {
fn bar(&self) -> i32 { 2 }
}
impl Bar for Vec<i32> {}
impl Bar for Vec<i64> {
fn bar(&self) -> i32 { 3 }
}

View File

@ -0,0 +1,31 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// aux-build:go_trait.rs
#![feature(specialization)]
extern crate go_trait;
use go_trait::{Go,GoMut};
use std::fmt::Debug;
use std::default::Default;
struct MyThingy;
impl Go for MyThingy {
fn go(&self, arg: isize) { }
}
impl GoMut for MyThingy {
fn go_mut(&mut self, arg: isize) { }
}
fn main() { }

View File

@ -0,0 +1,37 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that non-method associated functions can be specialized
#![feature(specialization)]
trait Foo {
fn mk() -> Self;
}
default impl<T: Default> Foo for T {
fn mk() -> T {
T::default()
}
}
impl Foo for Vec<u8> {
fn mk() -> Vec<u8> {
vec![0]
}
}
fn main() {
let v1: Vec<i32> = Foo::mk();
let v2: Vec<u8> = Foo::mk();
assert!(v1.len() == 0);
assert!(v2.len() == 1);
}

View File

@ -0,0 +1,106 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(specialization)]
// Tests a variety of basic specialization scenarios and method
// dispatch for them.
trait Foo {
fn foo(&self) -> &'static str;
}
default impl<T> Foo for T {
fn foo(&self) -> &'static str {
"generic"
}
}
default impl<T: Clone> Foo for T {
fn foo(&self) -> &'static str {
"generic Clone"
}
}
default impl<T, U> Foo for (T, U) where T: Clone, U: Clone {
fn foo(&self) -> &'static str {
"generic pair"
}
}
default impl<T: Clone> Foo for (T, T) {
fn foo(&self) -> &'static str {
"generic uniform pair"
}
}
default impl Foo for (u8, u32) {
fn foo(&self) -> &'static str {
"(u8, u32)"
}
}
default impl Foo for (u8, u8) {
fn foo(&self) -> &'static str {
"(u8, u8)"
}
}
default impl<T: Clone> Foo for Vec<T> {
fn foo(&self) -> &'static str {
"generic Vec"
}
}
impl Foo for Vec<i32> {
fn foo(&self) -> &'static str {
"Vec<i32>"
}
}
impl Foo for String {
fn foo(&self) -> &'static str {
"String"
}
}
impl Foo for i32 {
fn foo(&self) -> &'static str {
"i32"
}
}
struct NotClone;
trait MyMarker {}
default impl<T: Clone + MyMarker> Foo for T {
fn foo(&self) -> &'static str {
"generic Clone + MyMarker"
}
}
#[derive(Clone)]
struct MarkedAndClone;
impl MyMarker for MarkedAndClone {}
fn main() {
assert!(NotClone.foo() == "generic");
assert!(0u8.foo() == "generic Clone");
assert!(vec![NotClone].foo() == "generic");
assert!(vec![0u8].foo() == "generic Vec");
assert!(vec![0i32].foo() == "Vec<i32>");
assert!(0i32.foo() == "i32");
assert!(String::new().foo() == "String");
assert!(((), 0).foo() == "generic pair");
assert!(((), ()).foo() == "generic uniform pair");
assert!((0u8, 0u32).foo() == "(u8, u32)");
assert!((0u8, 0u8).foo() == "(u8, u8)");
assert!(MarkedAndClone.foo() == "generic Clone + MyMarker");
}

View File

@ -0,0 +1,49 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// aux-build:specialization_cross_crate_defaults.rs
#![feature(specialization)]
extern crate specialization_cross_crate_defaults;
use specialization_cross_crate_defaults::*;
struct LocalDefault;
struct LocalOverride;
impl Foo for LocalDefault {}
impl Foo for LocalOverride {
fn foo(&self) -> bool { true }
}
fn test_foo() {
assert!(!0i8.foo());
assert!(!0i32.foo());
assert!(0i64.foo());
assert!(!LocalDefault.foo());
assert!(LocalOverride.foo());
}
fn test_bar() {
assert!(0u8.bar() == 0);
assert!(0i32.bar() == 1);
assert!("hello".bar() == 0);
assert!(vec![()].bar() == 2);
assert!(vec![0i32].bar() == 2);
assert!(vec![0i64].bar() == 3);
}
fn main() {
test_foo();
test_bar();
}

View File

@ -0,0 +1,29 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that specialization works even if only the upstream crate enables it
// aux-build:specialization_cross_crate.rs
extern crate specialization_cross_crate;
use specialization_cross_crate::*;
fn main() {
assert!(0u8.foo() == "generic Clone");
assert!(vec![0u8].foo() == "generic Vec");
assert!(vec![0i32].foo() == "Vec<i32>");
assert!(0i32.foo() == "i32");
assert!(String::new().foo() == "String");
assert!(((), 0).foo() == "generic pair");
assert!(((), ()).foo() == "generic uniform pair");
assert!((0u8, 0u32).foo() == "(u8, u32)");
assert!((0u8, 0u8).foo() == "(u8, u8)");
}

View File

@ -0,0 +1,58 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// aux-build:specialization_cross_crate.rs
#![feature(specialization)]
extern crate specialization_cross_crate;
use specialization_cross_crate::*;
struct NotClone;
#[derive(Clone)]
struct MarkedAndClone;
impl MyMarker for MarkedAndClone {}
struct MyType<T>(T);
default impl<T> Foo for MyType<T> {
fn foo(&self) -> &'static str {
"generic MyType"
}
}
impl Foo for MyType<u8> {
fn foo(&self) -> &'static str {
"MyType<u8>"
}
}
struct MyOtherType;
impl Foo for MyOtherType {}
fn main() {
assert!(NotClone.foo() == "generic");
assert!(0u8.foo() == "generic Clone");
assert!(vec![NotClone].foo() == "generic");
assert!(vec![0u8].foo() == "generic Vec");
assert!(vec![0i32].foo() == "Vec<i32>");
assert!(0i32.foo() == "i32");
assert!(String::new().foo() == "String");
assert!(((), 0).foo() == "generic pair");
assert!(((), ()).foo() == "generic uniform pair");
assert!((0u8, 0u32).foo() == "(u8, u32)");
assert!((0u8, 0u8).foo() == "(u8, u8)");
assert!(MarkedAndClone.foo() == "generic Clone + MyMarker");
assert!(MyType(()).foo() == "generic MyType");
assert!(MyType(0u8).foo() == "MyType<u8>");
assert!(MyOtherType.foo() == "generic");
}

View File

@ -0,0 +1,94 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(specialization)]
// Test that default methods are cascaded correctly
// First, test only use of explicit `default` items:
trait Foo {
fn foo(&self) -> bool;
}
// Specialization tree for Foo:
//
// T
// / \
// i32 i64
default impl<T> Foo for T {
fn foo(&self) -> bool { false }
}
impl Foo for i32 {}
impl Foo for i64 {
fn foo(&self) -> bool { true }
}
fn test_foo() {
assert!(!0i8.foo());
assert!(!0i32.foo());
assert!(0i64.foo());
}
// Next, test mixture of explicit `default` and provided methods:
trait Bar {
fn bar(&self) -> i32 { 0 }
}
// Specialization tree for Bar.
// Uses of $ designate that method is provided
//
// $Bar (the trait)
// |
// T
// /|\
// / | \
// / | \
// / | \
// / | \
// / | \
// $i32 &str $Vec<T>
// /\
// / \
// Vec<i32> $Vec<i64>
// use the provided method
impl<T> Bar for T {}
impl Bar for i32 {
fn bar(&self) -> i32 { 1 }
}
impl<'a> Bar for &'a str {}
default impl<T> Bar for Vec<T> {
fn bar(&self) -> i32 { 2 }
}
impl Bar for Vec<i32> {}
impl Bar for Vec<i64> {
fn bar(&self) -> i32 { 3 }
}
fn test_bar() {
assert!(0u8.bar() == 0);
assert!(0i32.bar() == 1);
assert!("hello".bar() == 0);
assert!(vec![()].bar() == 2);
assert!(vec![0i32].bar() == 2);
assert!(vec![0i64].bar() == 3);
}
fn main() {
test_foo();
test_bar();
}

View File

@ -0,0 +1,27 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that you can list the more specific impl before the more general one.
#![feature(specialization)]
trait Foo {
type Out;
}
impl Foo for bool {
type Out = ();
}
default impl<T> Foo for T {
type Out = bool;
}
fn main() {}

View File

@ -0,0 +1,33 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that impls on projected self types can resolve overlap, even when the
// projections involve specialization, so long as the associated type is
// provided by the most specialized impl.
#![feature(specialization)]
trait Assoc {
type Output;
}
default impl<T> Assoc for T {
type Output = bool;
}
impl Assoc for u8 { type Output = u8; }
impl Assoc for u16 { type Output = u16; }
trait Foo {}
impl Foo for u32 {}
impl Foo for <u8 as Assoc>::Output {}
impl Foo for <u16 as Assoc>::Output {}
fn main() {}

View File

@ -0,0 +1,32 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(specialization)]
// Regression test for ICE when combining specialized associated types and type
// aliases
trait Id_ {
type Out;
}
type Id<T> = <T as Id_>::Out;
default impl<T> Id_ for T {
type Out = T;
}
fn test_proection() {
let x: Id<bool> = panic!();
}
fn main() {
}

View File

@ -0,0 +1,49 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(specialization)]
// Make sure we *can* project non-defaulted associated types
// cf compile-fail/specialization-default-projection.rs
// First, do so without any use of specialization
trait Foo {
type Assoc;
}
impl<T> Foo for T {
type Assoc = ();
}
fn generic_foo<T>() -> <T as Foo>::Assoc {
()
}
// Next, allow for one layer of specialization
trait Bar {
type Assoc;
}
default impl<T> Bar for T {
type Assoc = ();
}
impl<T: Clone> Bar for T {
type Assoc = u8;
}
fn generic_bar_clone<T: Clone>() -> <T as Bar>::Assoc {
0u8
}
fn main() {
}