Skip to content

Commit 54ef800

Browse files
committed
Auto merge of #37860 - giannicic:defaultimpl, r=nagisa
#37653 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](#37653) issue for further info r? @aturon
2 parents 6e0c5af + b48eb5e commit 54ef800

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1222
-43
lines changed

Diff for: src/grammar/parser-lalr.y

+14-7
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ extern char *yytext;
8989
%token TRAIT
9090
%token TYPE
9191
%token UNSAFE
92+
%token DEFAULT
9293
%token USE
9394
%token WHILE
9495
%token CONTINUE
@@ -534,6 +535,12 @@ maybe_unsafe
534535
| %empty { $$ = mk_none(); }
535536
;
536537

538+
maybe_default_maybe_unsafe
539+
: DEFAULT UNSAFE { $$ = mk_atom("DefaultUnsafe"); }
540+
| DEFAULT { $$ = mk_atom("Default"); }
541+
| UNSAFE { $$ = mk_atom("Unsafe"); }
542+
| %empty { $$ = mk_none(); }
543+
537544
trait_method
538545
: type_method { $$ = mk_node("Required", 1, $1); }
539546
| method { $$ = mk_node("Provided", 1, $1); }
@@ -588,27 +595,27 @@ impl_method
588595
// they are ambiguous with traits. We do the same here, regrettably,
589596
// by splitting ty into ty and ty_prim.
590597
item_impl
591-
: maybe_unsafe IMPL generic_params ty_prim_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
598+
: maybe_default_maybe_unsafe IMPL generic_params ty_prim_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
592599
{
593600
$$ = mk_node("ItemImpl", 6, $1, $3, $4, $5, $7, $8);
594601
}
595-
| maybe_unsafe IMPL generic_params '(' ty ')' maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
602+
| maybe_default_maybe_unsafe IMPL generic_params '(' ty ')' maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
596603
{
597604
$$ = mk_node("ItemImpl", 6, $1, $3, 5, $6, $9, $10);
598605
}
599-
| maybe_unsafe IMPL generic_params trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
606+
| maybe_default_maybe_unsafe IMPL generic_params trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
600607
{
601608
$$ = mk_node("ItemImpl", 6, $3, $4, $6, $7, $9, $10);
602609
}
603-
| maybe_unsafe IMPL generic_params '!' trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
610+
| maybe_default_maybe_unsafe IMPL generic_params '!' trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
604611
{
605612
$$ = mk_node("ItemImplNeg", 7, $1, $3, $5, $7, $8, $10, $11);
606613
}
607-
| maybe_unsafe IMPL generic_params trait_ref FOR DOTDOT '{' '}'
614+
| maybe_default_maybe_unsafe IMPL generic_params trait_ref FOR DOTDOT '{' '}'
608615
{
609616
$$ = mk_node("ItemImplDefault", 3, $1, $3, $4);
610617
}
611-
| maybe_unsafe IMPL generic_params '!' trait_ref FOR DOTDOT '{' '}'
618+
| maybe_default_maybe_unsafe IMPL generic_params '!' trait_ref FOR DOTDOT '{' '}'
612619
{
613620
$$ = mk_node("ItemImplDefaultNeg", 3, $1, $3, $4);
614621
}
@@ -1935,4 +1942,4 @@ brackets_delimited_token_trees
19351942
$2,
19361943
mk_node("TTTok", 1, mk_atom("]")));
19371944
}
1938-
;
1945+
;

Diff for: src/librustc/hir/lowering.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -1326,7 +1326,13 @@ impl<'a> LoweringContext<'a> {
13261326
hir::ItemDefaultImpl(self.lower_unsafety(unsafety),
13271327
trait_ref)
13281328
}
1329-
ItemKind::Impl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => {
1329+
ItemKind::Impl(unsafety,
1330+
polarity,
1331+
defaultness,
1332+
ref generics,
1333+
ref ifce,
1334+
ref ty,
1335+
ref impl_items) => {
13301336
let new_impl_items = impl_items.iter()
13311337
.map(|item| self.lower_impl_item_ref(item))
13321338
.collect();
@@ -1340,6 +1346,7 @@ impl<'a> LoweringContext<'a> {
13401346

13411347
hir::ItemImpl(self.lower_unsafety(unsafety),
13421348
self.lower_impl_polarity(polarity),
1349+
self.lower_defaultness(defaultness, true /* [1] */),
13431350
self.lower_generics(generics),
13441351
ifce,
13451352
self.lower_ty(ty),
@@ -1355,6 +1362,9 @@ impl<'a> LoweringContext<'a> {
13551362
}
13561363
ItemKind::MacroDef(..) | ItemKind::Mac(..) => panic!("Shouldn't still be around"),
13571364
}
1365+
1366+
// [1] `defaultness.has_value()` is never called for an `impl`, always `true` in order to
1367+
// not cause an assertion failure inside the `lower_defaultness` function
13581368
}
13591369

13601370
fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem {

Diff for: src/librustc/hir/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1712,6 +1712,7 @@ pub enum Item_ {
17121712
/// An implementation, eg `impl<A> Trait for Foo { .. }`
17131713
ItemImpl(Unsafety,
17141714
ImplPolarity,
1715+
Defaultness,
17151716
Generics,
17161717
Option<TraitRef>, // (optional) trait this impl implements
17171718
P<Ty>, // self

Diff for: src/librustc/hir/print.rs

+11-5
Original file line numberDiff line numberDiff line change
@@ -678,12 +678,14 @@ impl<'a> State<'a> {
678678
}
679679
hir::ItemImpl(unsafety,
680680
polarity,
681+
defaultness,
681682
ref generics,
682683
ref opt_trait,
683684
ref ty,
684685
ref impl_items) => {
685686
self.head("")?;
686687
self.print_visibility(&item.vis)?;
688+
self.print_defaultness(defaultness)?;
687689
self.print_unsafety(unsafety)?;
688690
self.word_nbsp("impl")?;
689691

@@ -820,6 +822,14 @@ impl<'a> State<'a> {
820822
}
821823
}
822824

825+
pub fn print_defaultness(&mut self, defaultness: hir::Defaultness) -> io::Result<()> {
826+
match defaultness {
827+
hir::Defaultness::Default { .. } => self.word_nbsp("default")?,
828+
hir::Defaultness::Final => (),
829+
}
830+
Ok(())
831+
}
832+
823833
pub fn print_struct(&mut self,
824834
struct_def: &hir::VariantData,
825835
generics: &hir::Generics,
@@ -931,11 +941,7 @@ impl<'a> State<'a> {
931941
self.hardbreak_if_not_bol()?;
932942
self.maybe_print_comment(ii.span.lo)?;
933943
self.print_outer_attributes(&ii.attrs)?;
934-
935-
match ii.defaultness {
936-
hir::Defaultness::Default { .. } => self.word_nbsp("default")?,
937-
hir::Defaultness::Final => (),
938-
}
944+
self.print_defaultness(ii.defaultness)?;
939945

940946
match ii.node {
941947
hir::ImplItemKind::Const(ref ty, expr) => {

Diff for: src/librustc/ich/impls_hir.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -933,7 +933,7 @@ impl_stable_hash_for!(enum hir::Item_ {
933933
ItemUnion(variant_data, generics),
934934
ItemTrait(unsafety, generics, bounds, item_refs),
935935
ItemDefaultImpl(unsafety, trait_ref),
936-
ItemImpl(unsafety, impl_polarity, generics, trait_ref, ty, impl_item_refs)
936+
ItemImpl(unsafety, impl_polarity, impl_defaultness, generics, trait_ref, ty, impl_item_refs)
937937
});
938938

939939
impl_stable_hash_for!(struct hir::TraitItemRef {

Diff for: src/librustc/middle/cstore.rs

+2
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ pub trait CrateStore {
195195
fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId>;
196196

197197
// impl info
198+
fn impl_defaultness(&self, def: DefId) -> hir::Defaultness;
198199
fn impl_parent(&self, impl_def_id: DefId) -> Option<DefId>;
199200

200201
// trait/impl-item info
@@ -329,6 +330,7 @@ impl CrateStore for DummyCrateStore {
329330
fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId> { vec![] }
330331

331332
// impl info
333+
fn impl_defaultness(&self, def: DefId) -> hir::Defaultness { bug!("impl_defaultness") }
332334
fn impl_parent(&self, def: DefId) -> Option<DefId> { bug!("impl_parent") }
333335

334336
// trait/impl-item info

Diff for: src/librustc/middle/reachable.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ fn item_might_be_inlined(item: &hir::Item) -> bool {
4949
}
5050

5151
match item.node {
52-
hir::ItemImpl(_, _, ref generics, ..) |
52+
hir::ItemImpl(_, _, _, ref generics, ..) |
5353
hir::ItemFn(.., ref generics, _) => {
5454
generics_require_inlining(generics)
5555
}
@@ -185,7 +185,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
185185
// does too.
186186
let impl_node_id = self.tcx.hir.as_local_node_id(impl_did).unwrap();
187187
match self.tcx.hir.expect_item(impl_node_id).node {
188-
hir::ItemImpl(_, _, ref generics, ..) => {
188+
hir::ItemImpl(_, _, _, ref generics, ..) => {
189189
generics_require_inlining(generics)
190190
}
191191
_ => false

Diff for: src/librustc/middle/resolve_lifetime.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
331331
hir::ItemStruct(_, ref generics) |
332332
hir::ItemUnion(_, ref generics) |
333333
hir::ItemTrait(_, ref generics, ..) |
334-
hir::ItemImpl(_, _, ref generics, ..) => {
334+
hir::ItemImpl(_, _, _, ref generics, ..) => {
335335
// These kinds of items have only early bound lifetime parameters.
336336
let mut index = if let hir::ItemTrait(..) = item.node {
337337
1 // Self comes before lifetimes
@@ -834,7 +834,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
834834
}
835835
match parent.node {
836836
hir::ItemTrait(_, ref generics, ..) |
837-
hir::ItemImpl(_, _, ref generics, ..) => {
837+
hir::ItemImpl(_, _, _, ref generics, ..) => {
838838
index += (generics.lifetimes.len() + generics.ty_params.len()) as u32;
839839
}
840840
_ => {}

Diff for: src/librustc/traits/project.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -923,7 +923,8 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
923923
// being invoked).
924924
node_item.item.defaultness.has_value()
925925
} else {
926-
node_item.item.defaultness.is_default()
926+
node_item.item.defaultness.is_default() ||
927+
selcx.tcx().impl_is_default(node_item.node.def_id())
927928
};
928929

929930
// Only reveal a specializable default if we're past type-checking

Diff for: src/librustc/traits/util.rs

+26
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ use ty::subst::{Subst, Substs};
1313
use ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef};
1414
use ty::outlives::Component;
1515
use util::nodemap::FxHashSet;
16+
use hir::{self};
17+
use traits::specialize::specialization_graph::NodeItem;
1618

1719
use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext, Normalized};
1820

@@ -504,6 +506,30 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
504506
};
505507
ty::Binder((trait_ref, sig.skip_binder().output()))
506508
}
509+
510+
pub fn impl_is_default(self, node_item_def_id: DefId) -> bool {
511+
match self.hir.as_local_node_id(node_item_def_id) {
512+
Some(node_id) => {
513+
let item = self.hir.expect_item(node_id);
514+
if let hir::ItemImpl(_, _, defaultness, ..) = item.node {
515+
defaultness.is_default()
516+
} else {
517+
false
518+
}
519+
}
520+
None => {
521+
self.global_tcx()
522+
.sess
523+
.cstore
524+
.impl_defaultness(node_item_def_id)
525+
.is_default()
526+
}
527+
}
528+
}
529+
530+
pub fn impl_item_is_final(self, node_item: &NodeItem<hir::Defaultness>) -> bool {
531+
node_item.item.is_final() && !self.impl_is_default(node_item.node.def_id())
532+
}
507533
}
508534

509535
pub enum TupleArgumentsFlag { Yes, No }

Diff for: src/librustc_metadata/cstore_impl.rs

+6
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,12 @@ impl CrateStore for cstore::CStore {
178178
result
179179
}
180180

181+
fn impl_defaultness(&self, def: DefId) -> hir::Defaultness
182+
{
183+
self.dep_graph.read(DepNode::MetaData(def));
184+
self.get_crate_data(def.krate).get_impl_defaultness(def.index)
185+
}
186+
181187
fn impl_parent(&self, impl_def: DefId) -> Option<DefId> {
182188
self.dep_graph.read(DepNode::MetaData(impl_def));
183189
self.get_crate_data(impl_def.krate).get_parent_impl(impl_def.index)

Diff for: src/librustc_metadata/decoder.rs

+4
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,10 @@ impl<'a, 'tcx> CrateMetadata {
629629
self.get_impl_data(id).polarity
630630
}
631631

632+
pub fn get_impl_defaultness(&self, id: DefIndex) -> hir::Defaultness {
633+
self.get_impl_data(id).defaultness
634+
}
635+
632636
pub fn get_coerce_unsized_info(&self,
633637
id: DefIndex)
634638
-> Option<ty::adjustment::CoerceUnsizedInfo> {

Diff for: src/librustc_metadata/encoder.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -706,14 +706,15 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
706706
hir::ItemDefaultImpl(..) => {
707707
let data = ImplData {
708708
polarity: hir::ImplPolarity::Positive,
709+
defaultness: hir::Defaultness::Final,
709710
parent_impl: None,
710711
coerce_unsized_info: None,
711712
trait_ref: tcx.impl_trait_ref(def_id).map(|trait_ref| self.lazy(&trait_ref)),
712713
};
713714

714715
EntryKind::DefaultImpl(self.lazy(&data))
715716
}
716-
hir::ItemImpl(_, polarity, ..) => {
717+
hir::ItemImpl(_, polarity, defaultness, ..) => {
717718
let trait_ref = tcx.impl_trait_ref(def_id);
718719
let parent = if let Some(trait_ref) = trait_ref {
719720
let trait_def = tcx.trait_def(trait_ref.def_id);
@@ -740,6 +741,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
740741

741742
let data = ImplData {
742743
polarity: polarity,
744+
defaultness: defaultness,
743745
parent_impl: parent,
744746
coerce_unsized_info: coerce_unsized_info,
745747
trait_ref: trait_ref.map(|trait_ref| self.lazy(&trait_ref)),

Diff for: src/librustc_metadata/schema.rs

+2
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,7 @@ impl_stable_hash_for!(struct TraitData<'tcx> {
406406
#[derive(RustcEncodable, RustcDecodable)]
407407
pub struct ImplData<'tcx> {
408408
pub polarity: hir::ImplPolarity,
409+
pub defaultness: hir::Defaultness,
409410
pub parent_impl: Option<DefId>,
410411

411412
/// This is `Some` only for impls of `CoerceUnsized`.
@@ -415,6 +416,7 @@ pub struct ImplData<'tcx> {
415416

416417
impl_stable_hash_for!(struct ImplData<'tcx> {
417418
polarity,
419+
defaultness,
418420
parent_impl,
419421
coerce_unsized_info,
420422
trait_ref

Diff for: src/librustc_save_analysis/dump_visitor.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
430430
}
431431
None => {
432432
if let Some(NodeItem(item)) = self.tcx.hir.get_if_local(id) {
433-
if let hir::ItemImpl(_, _, _, _, ref ty, _) = item.node {
433+
if let hir::ItemImpl(_, _, _, _, _, ref ty, _) = item.node {
434434
trait_id = self.lookup_def_id(ty.id);
435435
}
436436
}

Diff for: src/librustc_trans/collector.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -880,7 +880,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> {
880880
let parent_node_id = hir_map.get_parent_node(ii.id);
881881
let is_impl_generic = match hir_map.expect_item(parent_node_id) {
882882
&hir::Item {
883-
node: hir::ItemImpl(_, _, ref generics, ..),
883+
node: hir::ItemImpl(_, _, _, ref generics, ..),
884884
..
885885
} => {
886886
generics.is_type_parameterized()
@@ -911,6 +911,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, '
911911
let tcx = scx.tcx();
912912
match item.node {
913913
hir::ItemImpl(_,
914+
_,
914915
_,
915916
ref generics,
916917
..,

Diff for: src/librustc_typeck/check/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1141,7 +1141,7 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
11411141
.map(|node_item| node_item.map(|parent| parent.defaultness));
11421142

11431143
if let Some(parent) = parent {
1144-
if parent.item.is_final() {
1144+
if tcx.impl_item_is_final(&parent) {
11451145
report_forbidden_specialization(tcx, impl_item, parent.node.def_id());
11461146
}
11471147
}

Diff for: src/librustc_typeck/check/wfcheck.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,11 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
105105
///
106106
/// won't be allowed unless there's an *explicit* implementation of `Send`
107107
/// for `T`
108-
hir::ItemImpl(_, hir::ImplPolarity::Positive, _,
108+
hir::ItemImpl(_, hir::ImplPolarity::Positive, _, _,
109109
ref trait_ref, ref self_ty, _) => {
110110
self.check_impl(item, self_ty, trait_ref);
111111
}
112-
hir::ItemImpl(_, hir::ImplPolarity::Negative, _, Some(_), ..) => {
112+
hir::ItemImpl(_, hir::ImplPolarity::Negative, _, _, Some(_), ..) => {
113113
// FIXME(#27579) what amount of WF checking do we need for neg impls?
114114

115115
let trait_ref = tcx.impl_trait_ref(tcx.hir.local_def_id(item.id)).unwrap();

Diff for: src/librustc_typeck/coherence/unsafety.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for UnsafetyChecker<'cx, 'tcx> {
8787
hir::ItemDefaultImpl(unsafety, _) => {
8888
self.check_unsafety_coherence(item, None, unsafety, hir::ImplPolarity::Positive);
8989
}
90-
hir::ItemImpl(unsafety, polarity, ref generics, Some(_), _, _) => {
90+
hir::ItemImpl(unsafety, polarity, _, ref generics, ..) => {
9191
self.check_unsafety_coherence(item, Some(generics), unsafety, polarity);
9292
}
9393
_ => {}

0 commit comments

Comments
 (0)