support default impl
for specialization
pr review
This commit is contained in:
parent
b0fca5f790
commit
715811d0be
22 changed files with 202 additions and 65 deletions
2
cargo
2
cargo
|
@ -1 +1 @@
|
|||
Subproject commit c416fb60b11ecfd2a1ba0fb8567c9a92590b5d28
|
||||
Subproject commit 8326a3683a9045d825e4fdc4021af340ee3b3755
|
2
rls
2
rls
|
@ -1 +1 @@
|
|||
Subproject commit 016cbc514cf44a2bd3fe806e8afa6b9c50287373
|
||||
Subproject commit 6ecff95fdc3ee7ceed2b9b0cc1a3a64876860bce
|
|
@ -1 +1 @@
|
|||
Subproject commit a8fc4c169fac43a5dc204d4fd56ddb1739f8c178
|
||||
Subproject commit d30da544a8afc5d78391dee270bdf40e74a215d3
|
|
@ -1 +1 @@
|
|||
Subproject commit beea82b9230cd641dd1ca263cf31025ace4aebb5
|
||||
Subproject commit ad7de198561b3a12217ea2da76d796d9c7fc0ed3
|
|
@ -1 +1 @@
|
|||
Subproject commit b060f732145f2fa16df84c74e511df08a3a47c5d
|
||||
Subproject commit 6b0de90d87dda15e323ef24cdf7ed873ac5cf4d3
|
|
@ -89,6 +89,7 @@ extern char *yytext;
|
|||
%token TRAIT
|
||||
%token TYPE
|
||||
%token UNSAFE
|
||||
%token DEFAULT
|
||||
%token USE
|
||||
%token WHILE
|
||||
%token CONTINUE
|
||||
|
@ -534,6 +535,11 @@ maybe_unsafe
|
|||
| %empty { $$ = mk_none(); }
|
||||
;
|
||||
|
||||
maybe_default_impl
|
||||
: IMPL { $$ = mk_none(); }
|
||||
| DEFAULT IMPL { $$ = $1 }
|
||||
;
|
||||
|
||||
trait_method
|
||||
: type_method { $$ = mk_node("Required", 1, $1); }
|
||||
| method { $$ = mk_node("Provided", 1, $1); }
|
||||
|
@ -588,27 +594,27 @@ impl_method
|
|||
// they are ambiguous with traits. We do the same here, regrettably,
|
||||
// by splitting ty into ty and ty_prim.
|
||||
item_impl
|
||||
: maybe_unsafe IMPL generic_params ty_prim_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
|
||||
: maybe_unsafe maybe_default_impl generic_params ty_prim_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
|
||||
{
|
||||
$$ = mk_node("ItemImpl", 6, $1, $3, $4, $5, $7, $8);
|
||||
$$ = mk_node("ItemImpl", 6, $1, $3, $4, $5, $7, $8, $2);
|
||||
}
|
||||
| maybe_unsafe IMPL generic_params '(' ty ')' maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
|
||||
| maybe_unsafe maybe_default_impl generic_params '(' ty ')' maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
|
||||
{
|
||||
$$ = mk_node("ItemImpl", 6, $1, $3, 5, $6, $9, $10);
|
||||
$$ = mk_node("ItemImpl", 6, $1, $3, 5, $6, $9, $10, $2);
|
||||
}
|
||||
| maybe_unsafe IMPL generic_params trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
|
||||
| maybe_unsafe maybe_default_impl generic_params trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
|
||||
{
|
||||
$$ = mk_node("ItemImpl", 6, $3, $4, $6, $7, $9, $10);
|
||||
$$ = mk_node("ItemImpl", 6, $3, $4, $6, $7, $9, $10, $2);
|
||||
}
|
||||
| maybe_unsafe IMPL generic_params '!' trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
|
||||
| maybe_unsafe maybe_default_impl generic_params '!' trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
|
||||
{
|
||||
$$ = mk_node("ItemImplNeg", 7, $1, $3, $5, $7, $8, $10, $11);
|
||||
$$ = mk_node("ItemImplNeg", 7, $1, $3, $5, $7, $8, $10, $11, $2);
|
||||
}
|
||||
| maybe_unsafe IMPL generic_params trait_ref FOR DOTDOT '{' '}'
|
||||
| maybe_unsafe maybe_default_impl generic_params trait_ref FOR DOTDOT '{' '}'
|
||||
{
|
||||
$$ = mk_node("ItemImplDefault", 3, $1, $3, $4);
|
||||
}
|
||||
| maybe_unsafe IMPL generic_params '!' trait_ref FOR DOTDOT '{' '}'
|
||||
| maybe_unsafe maybe_default_impl generic_params '!' trait_ref FOR DOTDOT '{' '}'
|
||||
{
|
||||
$$ = mk_node("ItemImplDefaultNeg", 3, $1, $3, $4);
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit e058ca661692a8d01f8cf9d35939dfe3105ce968
|
||||
Subproject commit 11bfb0dcf85f7aa92abd30524bb1e42e18d108c6
|
|
@ -1 +1 @@
|
|||
Subproject commit 05a2d197356ef253dfd985166576619ac9b6947f
|
||||
Subproject commit c34a802d1eb037b44c5252078c7270b5472e0f65
|
|
@ -1362,6 +1362,9 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
ItemKind::MacroDef(..) | ItemKind::Mac(..) => panic!("Shouldn't still be around"),
|
||||
}
|
||||
|
||||
// [1] `defaultness.has_value()` is necer called for an `impl`, always `true` in order to
|
||||
// not cause an assertion failure inside the `lower_defaultness` function
|
||||
}
|
||||
|
||||
fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem {
|
||||
|
|
|
@ -933,7 +933,7 @@ impl_stable_hash_for!(enum hir::Item_ {
|
|||
ItemUnion(variant_data, generics),
|
||||
ItemTrait(unsafety, generics, bounds, item_refs),
|
||||
ItemDefaultImpl(unsafety, trait_ref),
|
||||
ItemImpl(unsafety, impl_polarity, generics, trait_ref, ty, impl_item_refs)
|
||||
ItemImpl(unsafety, impl_polarity, impl_defaultness, generics, trait_ref, ty, impl_item_refs)
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(struct hir::TraitItemRef {
|
||||
|
|
|
@ -195,6 +195,7 @@ pub trait CrateStore {
|
|||
fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId>;
|
||||
|
||||
// impl info
|
||||
fn impl_defaultness(&self, def: DefId) -> hir::Defaultness;
|
||||
fn impl_parent(&self, impl_def_id: DefId) -> Option<DefId>;
|
||||
|
||||
// trait/impl-item info
|
||||
|
@ -329,6 +330,7 @@ impl CrateStore for DummyCrateStore {
|
|||
fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId> { vec![] }
|
||||
|
||||
// impl info
|
||||
fn impl_defaultness(&self, def: DefId) -> hir::Defaultness { bug!("impl_defaultness") }
|
||||
fn impl_parent(&self, def: DefId) -> Option<DefId> { bug!("impl_parent") }
|
||||
|
||||
// trait/impl-item info
|
||||
|
|
|
@ -33,7 +33,6 @@ 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.
|
||||
|
@ -924,28 +923,8 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
|
|||
// being invoked).
|
||||
node_item.item.defaultness.has_value()
|
||||
} else {
|
||||
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
|
||||
node_item.item.defaultness.is_default() ||
|
||||
selcx.tcx().impl_is_default(node_item.node.def_id())
|
||||
};
|
||||
|
||||
// Only reveal a specializable default if we're past type-checking
|
||||
|
|
|
@ -13,6 +13,7 @@ use ty::subst::{Subst, Substs};
|
|||
use ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef};
|
||||
use ty::outlives::Component;
|
||||
use util::nodemap::FxHashSet;
|
||||
use hir::{self};
|
||||
|
||||
use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext, Normalized};
|
||||
|
||||
|
@ -504,6 +505,26 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
};
|
||||
ty::Binder((trait_ref, sig.skip_binder().output()))
|
||||
}
|
||||
|
||||
pub fn impl_is_default(self, node_item_def_id: DefId) -> bool {
|
||||
match self.hir.as_local_node_id(node_item_def_id) {
|
||||
Some(node_id) => {
|
||||
let item = self.hir.expect_item(node_id);
|
||||
if let hir::ItemImpl(_, _, defaultness, ..) = item.node {
|
||||
defaultness.is_default()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
None => {
|
||||
self.global_tcx()
|
||||
.sess
|
||||
.cstore
|
||||
.impl_defaultness(node_item_def_id)
|
||||
.is_default()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum TupleArgumentsFlag { Yes, No }
|
||||
|
|
|
@ -90,7 +90,6 @@ 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);
|
||||
|
@ -179,6 +178,12 @@ impl CrateStore for cstore::CStore {
|
|||
result
|
||||
}
|
||||
|
||||
fn impl_defaultness(&self, def: DefId) -> hir::Defaultness
|
||||
{
|
||||
self.dep_graph.read(DepNode::MetaData(def));
|
||||
self.get_crate_data(def.krate).get_impl_defaultness(def.index)
|
||||
}
|
||||
|
||||
fn impl_parent(&self, impl_def: DefId) -> Option<DefId> {
|
||||
self.dep_graph.read(DepNode::MetaData(impl_def));
|
||||
self.get_crate_data(impl_def.krate).get_parent_impl(impl_def.index)
|
||||
|
|
|
@ -416,6 +416,7 @@ pub struct ImplData<'tcx> {
|
|||
|
||||
impl_stable_hash_for!(struct ImplData<'tcx> {
|
||||
polarity,
|
||||
defaultness,
|
||||
parent_impl,
|
||||
coerce_unsized_info,
|
||||
trait_ref
|
||||
|
|
|
@ -429,7 +429,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
|
|||
}
|
||||
}
|
||||
None => {
|
||||
if let Some(NodeItem(item)) = self.tcx.map.get_if_local(id) {
|
||||
if let Some(NodeItem(item)) = self.tcx.hir.get_if_local(id) {
|
||||
if let hir::ItemImpl(_, _, _, _, _, ref ty, _) = item.node {
|
||||
trait_id = self.lookup_def_id(ty.id);
|
||||
}
|
||||
|
|
|
@ -1142,21 +1142,7 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
|
||||
if let Some(parent) = parent {
|
||||
if parent.item.is_final() {
|
||||
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 {
|
||||
if !tcx.impl_is_default(parent.node.def_id()) {
|
||||
report_forbidden_specialization(tcx, impl_item, parent.node.def_id());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -309,7 +309,7 @@ fn type_param_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
NodeItem(item) => {
|
||||
match item.node {
|
||||
ItemFn(.., ref generics, _) |
|
||||
ItemImpl(_, _, ref generics, ..) |
|
||||
ItemImpl(_, _, _, ref generics, ..) |
|
||||
ItemTy(_, ref generics) |
|
||||
ItemEnum(_, ref generics) |
|
||||
ItemStruct(_, ref generics) |
|
||||
|
@ -825,7 +825,7 @@ fn generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
NodeItem(item) => {
|
||||
match item.node {
|
||||
ItemFn(.., ref generics, _) |
|
||||
ItemImpl(_, _, ref generics, ..) => generics,
|
||||
ItemImpl(_, _, _, ref generics, ..) => generics,
|
||||
|
||||
ItemTy(_, ref generics) |
|
||||
ItemEnum(_, ref generics) |
|
||||
|
@ -1236,7 +1236,7 @@ fn predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
NodeItem(item) => {
|
||||
match item.node {
|
||||
ItemFn(.., ref generics, _) |
|
||||
ItemImpl(_, _, ref generics, ..) |
|
||||
ItemImpl(_, _, _, ref generics, ..) |
|
||||
ItemTy(_, ref generics) |
|
||||
ItemEnum(_, ref generics) |
|
||||
ItemStruct(_, ref generics) |
|
||||
|
|
|
@ -4918,6 +4918,14 @@ impl<'a> Parser<'a> {
|
|||
allowed to have generics");
|
||||
}
|
||||
|
||||
match defaultness {
|
||||
ast::Defaultness::Default => {
|
||||
self.span_err(impl_span, "`default impl` is not allowed for \
|
||||
default trait implementations");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.expect(&token::OpenDelim(token::Brace))?;
|
||||
self.expect(&token::CloseDelim(token::Brace))?;
|
||||
Ok((keywords::Invalid.ident(),
|
||||
|
@ -5760,13 +5768,13 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
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.check_keyword(keywords::Unsafe) &&
|
||||
self.look_ahead(1, |t| t.is_keyword(keywords::Default)) &&
|
||||
self.look_ahead(2, |t| t.is_keyword(keywords::Impl)))
|
||||
{
|
||||
// IMPL ITEM
|
||||
let defaultness = self.parse_defaultness()?;
|
||||
self.expect_keyword(keywords::Unsafe)?;
|
||||
let defaultness = self.parse_defaultness()?;
|
||||
self.expect_keyword(keywords::Impl)?;
|
||||
let (ident,
|
||||
item_,
|
||||
|
|
1
src/rt/hoedown
Submodule
1
src/rt/hoedown
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit da282f1bb7277b4d30fa1599ee29ad8eb4dd2a92
|
|
@ -0,0 +1,19 @@
|
|||
// 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)]
|
||||
#![feature(optin_builtin_traits)]
|
||||
|
||||
trait Foo {}
|
||||
|
||||
default impl Foo for .. {}
|
||||
//~^ ERROR `default impl` is not allowed for default trait implementations
|
||||
|
||||
fn main() {}
|
|
@ -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.
|
||||
|
||||
unsafe trait Foo {
|
||||
fn foo(&self) -> &'static str;
|
||||
}
|
||||
|
||||
unsafe default impl<T> Foo for T {
|
||||
fn foo(&self) -> &'static str {
|
||||
"generic"
|
||||
}
|
||||
}
|
||||
|
||||
unsafe default impl<T: Clone> Foo for T {
|
||||
fn foo(&self) -> &'static str {
|
||||
"generic Clone"
|
||||
}
|
||||
}
|
||||
|
||||
unsafe default impl<T, U> Foo for (T, U) where T: Clone, U: Clone {
|
||||
fn foo(&self) -> &'static str {
|
||||
"generic pair"
|
||||
}
|
||||
}
|
||||
|
||||
unsafe default impl<T: Clone> Foo for (T, T) {
|
||||
fn foo(&self) -> &'static str {
|
||||
"generic uniform pair"
|
||||
}
|
||||
}
|
||||
|
||||
unsafe default impl Foo for (u8, u32) {
|
||||
fn foo(&self) -> &'static str {
|
||||
"(u8, u32)"
|
||||
}
|
||||
}
|
||||
|
||||
unsafe default impl Foo for (u8, u8) {
|
||||
fn foo(&self) -> &'static str {
|
||||
"(u8, u8)"
|
||||
}
|
||||
}
|
||||
|
||||
unsafe default impl<T: Clone> Foo for Vec<T> {
|
||||
fn foo(&self) -> &'static str {
|
||||
"generic Vec"
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Foo for Vec<i32> {
|
||||
fn foo(&self) -> &'static str {
|
||||
"Vec<i32>"
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Foo for String {
|
||||
fn foo(&self) -> &'static str {
|
||||
"String"
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Foo for i32 {
|
||||
fn foo(&self) -> &'static str {
|
||||
"i32"
|
||||
}
|
||||
}
|
||||
|
||||
struct NotClone;
|
||||
|
||||
unsafe trait MyMarker {}
|
||||
unsafe default impl<T: Clone + MyMarker> Foo for T {
|
||||
fn foo(&self) -> &'static str {
|
||||
"generic Clone + MyMarker"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct MarkedAndClone;
|
||||
unsafe 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");
|
||||
}
|
Loading…
Add table
Reference in a new issue