提交 116e9831 编写于 作者: G Gianni Ciccarelli

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
上级 15ce5409
Subproject commit 8326a3683a9045d825e4fdc4021af340ee3b3755
Subproject commit c416fb60b11ecfd2a1ba0fb8567c9a92590b5d28
Subproject commit 6ecff95fdc3ee7ceed2b9b0cc1a3a64876860bce
Subproject commit 016cbc514cf44a2bd3fe806e8afa6b9c50287373
Subproject commit d30da544a8afc5d78391dee270bdf40e74a215d3
Subproject commit a8fc4c169fac43a5dc204d4fd56ddb1739f8c178
Subproject commit ad7de198561b3a12217ea2da76d796d9c7fc0ed3
Subproject commit beea82b9230cd641dd1ca263cf31025ace4aebb5
Subproject commit 6b0de90d87dda15e323ef24cdf7ed873ac5cf4d3
Subproject commit b060f732145f2fa16df84c74e511df08a3a47c5d
Subproject commit 11bfb0dcf85f7aa92abd30524bb1e42e18d108c6
Subproject commit e058ca661692a8d01f8cf9d35939dfe3105ce968
Subproject commit c34a802d1eb037b44c5252078c7270b5472e0f65
Subproject commit 05a2d197356ef253dfd985166576619ac9b6947f
......@@ -1326,7 +1326,13 @@ fn lower_item_kind(&mut self,
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 @@ fn lower_item_kind(&mut self,
hir::ItemImpl(self.lower_unsafety(unsafety),
self.lower_impl_polarity(polarity),
self.lower_defaultness(defaultness),
self.lower_generics(generics),
ifce,
self.lower_ty(ty),
......
......@@ -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
......
......@@ -678,12 +678,14 @@ pub fn print_item(&mut self, item: &hir::Item) -> io::Result<()> {
}
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 @@ pub fn print_visibility(&mut self, vis: &hir::Visibility) -> io::Result<()> {
}
}
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 @@ pub fn print_impl_item(&mut self, ii: &hir::ImplItem) -> io::Result<()> {
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) => {
......
......@@ -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 @@ fn def_id_represents_local_inlined_item(&self, def_id: DefId) -> bool {
// 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
......
......@@ -331,7 +331,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
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 @@ fn visit_early_late<F>(&mut self,
}
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;
}
_ => {}
......
......@@ -33,6 +33,7 @@
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
......
......@@ -90,6 +90,7 @@ pub fn provide<$lt>(providers: &mut Providers<$lt>) {
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);
......
......@@ -629,6 +629,10 @@ pub fn get_impl_polarity(&self, id: DefIndex) -> hir::ImplPolarity {
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> {
......
......@@ -706,6 +706,7 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) ->
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 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) ->
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 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) ->
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)),
......
......@@ -406,6 +406,7 @@ pub 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`.
......
......@@ -429,8 +429,8 @@ fn process_method(&mut self,
}
}
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);
}
}
......
......@@ -880,7 +880,7 @@ fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) {
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,
..,
......
......@@ -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());
}
}
}
......
......@@ -105,11 +105,11 @@ fn check_item_well_formed(&mut self, item: &hir::Item) {
///
/// 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();
......
......@@ -87,7 +87,7 @@ fn visit_item(&mut self, item: &'v hir::Item) {
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);
}
_ => {}
......
......@@ -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>,
......
......@@ -502,7 +502,7 @@ pub fn visit_item(&mut self, item: &hir::Item,
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 @@ pub fn visit_item(&mut self, item: &hir::Item,
let i = Impl {
unsafety: unsafety,
polarity: polarity,
defaultness: defaultness,
generics: gen.clone(),
trait_: tr.clone(),
for_: ty.clone(),
......
......@@ -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
......
......@@ -1215,7 +1215,7 @@ fn visit_item(&mut self, i: &'a ast::Item) {
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 @@ fn visit_item(&mut self, i: &'a ast::Item) {
},
_ => {}
}
match defaultness {
ast::Defaultness::Default => {
gate_feature_post!(&self, specialization,
i.span,
"specialization is unstable");
}
_ => {}
}
}
_ => {}
......
......@@ -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),
......
......@@ -4863,7 +4863,9 @@ fn parse_item_trait(&mut self, unsafety: Unsafety) -> PResult<'a, ItemInfo> {
/// 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 @@ fn parse_item_impl(&mut self, unsafety: ast::Unsafety) -> PResult<'a, ItemInfo>
}
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 @@ fn parse_item_(&mut self, attrs: Vec<Attribute>,
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 @@ fn parse_item_(&mut self, attrs: Vec<Attribute>,
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,
......
......@@ -1317,12 +1317,14 @@ pub fn print_item(&mut self, item: &ast::Item) -> io::Result<()> {
}
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 @@ pub fn print_visibility(&mut self, vis: &ast::Visibility) -> io::Result<()> {
}
}
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 @@ pub fn print_impl_item(&mut self, ii: &ast::ImplItem) -> io::Result<()> {
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)?;
......
......@@ -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,
......
......@@ -658,6 +658,7 @@ fn create_derived_impl(&self,
a,
ast::ItemKind::Impl(unsafety,
ast::ImplPolarity::Positive,
ast::Defaultness::Final,
trait_generics,
opt_trait_ref,
self_type,
......
Subproject commit da282f1bb7277b4d30fa1599ee29ad8eb4dd2a92
// 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
}
// 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();
}
// 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() {}
// 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() {}
// 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)
}
}
// 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"
}
}
// 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 }
}
// 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() { }
// 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);
}
// 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");
}
// 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();
}
// 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)");
}
// 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");
}
// 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();
}
// 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() {}
// 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() {}
// 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() {
}
// 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() {
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册