Skip to content

Commit 69322d9

Browse files
committed
Allow traits to use builtin kinds as supertraits for rust-lang#7083.
1 parent 369f7fa commit 69322d9

File tree

7 files changed

+119
-92
lines changed

7 files changed

+119
-92
lines changed

src/librustc/metadata/decoder.rs

+19-1
Original file line numberDiff line numberDiff line change
@@ -375,9 +375,21 @@ pub fn get_trait_def(cdata: cmd,
375375
let tp_defs = item_ty_param_defs(item_doc, tcx, cdata,
376376
tag_items_data_item_ty_param_bounds);
377377
let rp = item_ty_region_param(item_doc);
378+
let mut bounds = ty::EmptyBuiltinBounds();
379+
// Collect the builtin bounds from the encoded supertraits.
380+
// FIXME(#8559): They should be encoded directly.
381+
do reader::tagged_docs(item_doc, tag_item_super_trait_ref) |trait_doc| {
382+
// NB. Bypasses real supertraits. See get_supertraits() if you wanted them.
383+
let trait_ref = doc_trait_ref(trait_doc, tcx, cdata);
384+
do tcx.lang_items.to_builtin_kind(trait_ref.def_id).map_move |bound| {
385+
bounds.add(bound);
386+
};
387+
true
388+
};
378389
ty::TraitDef {
379390
generics: ty::Generics {type_param_defs: tp_defs,
380391
region_param: rp},
392+
bounds: bounds,
381393
trait_ref: @item_trait_ref(item_doc, tcx, cdata)
382394
}
383395
}
@@ -929,7 +941,13 @@ pub fn get_supertraits(cdata: cmd, id: ast::NodeId, tcx: ty::ctxt)
929941
let mut results = ~[];
930942
let item_doc = lookup_item(id, cdata.data);
931943
do reader::tagged_docs(item_doc, tag_item_super_trait_ref) |trait_doc| {
932-
results.push(@doc_trait_ref(trait_doc, tcx, cdata));
944+
// NB. Only reads the ones that *aren't* builtin-bounds. See also
945+
// get_trait_def() for collecting the builtin bounds.
946+
// FIXME(#8559): The builtin bounds shouldn't be encoded in the first place.
947+
let trait_ref = doc_trait_ref(trait_doc, tcx, cdata);
948+
if tcx.lang_items.to_builtin_kind(trait_ref.def_id).is_none() {
949+
results.push(@trait_ref);
950+
}
933951
true
934952
};
935953
return results;

src/librustc/metadata/encoder.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1076,6 +1076,9 @@ fn encode_info_for_item(ecx: &EncodeContext,
10761076
ebml_w.end_tag();
10771077
}
10781078
encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
1079+
// FIXME(#8559): This should use the tcx's supertrait cache instead of
1080+
// reading the AST's list, because the former has already filtered out
1081+
// the builtin-kinds-as-supertraits. See corresponding fixme in decoder.
10791082
for ast_trait_ref in super_traits.iter() {
10801083
let trait_ref = ty::node_id_to_trait_ref(ecx.tcx, ast_trait_ref.ref_id);
10811084
encode_trait_ref(ebml_w, ecx, trait_ref, tag_item_super_trait_ref);

src/librustc/middle/kind.rs

+35-39
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ use syntax::visit::Visitor;
5050
// primitives in the stdlib are explicitly annotated to only take sendable
5151
// types.
5252

53-
pub static try_adding: &'static str = "Try adding a move";
54-
5553
#[deriving(Clone)]
5654
pub struct Context {
5755
tcx: ty::ctxt,
@@ -77,9 +75,6 @@ impl Visitor<Context> for KindAnalysisVisitor {
7775
fn visit_item(&mut self, i:@item, e:Context) {
7876
check_item(self, i, e);
7977
}
80-
fn visit_block(&mut self, b:&Block, e:Context) {
81-
check_block(self, b, e);
82-
}
8378
}
8479

8580
pub fn check_crate(tcx: ty::ctxt,
@@ -125,46 +120,47 @@ fn check_struct_safe_for_destructor(cx: Context,
125120
}
126121
}
127122

128-
fn check_block(visitor: &mut KindAnalysisVisitor,
129-
block: &Block,
130-
cx: Context) {
131-
visit::walk_block(visitor, block, cx);
123+
fn check_impl_of_trait(cx: Context, it: @item, trait_ref: &trait_ref, self_type: &Ty) {
124+
let ast_trait_def = cx.tcx.def_map.find(&trait_ref.ref_id)
125+
.expect("trait ref not in def map!");
126+
let trait_def_id = ast_util::def_id_of_def(*ast_trait_def);
127+
let trait_def = cx.tcx.trait_defs.find(&trait_def_id)
128+
.expect("trait def not in trait-defs map!");
129+
130+
// If this trait has builtin-kind supertraits, meet them.
131+
let self_ty: ty::t = ty::node_id_to_type(cx.tcx, it.id);
132+
error!("checking impl with self type %?", ty::get(self_ty).sty);
133+
do check_builtin_bounds(cx, self_ty, trait_def.bounds) |missing| {
134+
cx.tcx.sess.span_err(self_type.span,
135+
fmt!("the type `%s', which does not fulfill `%s`, cannot implement this \
136+
trait", ty_to_str(cx.tcx, self_ty), missing.user_string(cx.tcx)));
137+
cx.tcx.sess.span_note(self_type.span,
138+
fmt!("types implementing this trait must fulfill `%s`",
139+
trait_def.bounds.user_string(cx.tcx)));
140+
}
141+
142+
// If this is a destructor, check kinds.
143+
if cx.tcx.lang_items.drop_trait() == Some(trait_def_id) {
144+
match self_type.node {
145+
ty_path(_, ref bounds, path_node_id) => {
146+
assert!(bounds.is_none());
147+
let struct_def = cx.tcx.def_map.get_copy(&path_node_id);
148+
let struct_did = ast_util::def_id_of_def(struct_def);
149+
check_struct_safe_for_destructor(cx, self_type.span, struct_did);
150+
}
151+
_ => {
152+
cx.tcx.sess.span_bug(self_type.span,
153+
"the self type for the Drop trait impl is not a path");
154+
}
155+
}
156+
}
132157
}
133158

134159
fn check_item(visitor: &mut KindAnalysisVisitor, item: @item, cx: Context) {
135-
// If this is a destructor, check kinds.
136160
if !attr::contains_name(item.attrs, "unsafe_destructor") {
137161
match item.node {
138162
item_impl(_, Some(ref trait_ref), ref self_type, _) => {
139-
match cx.tcx.def_map.find(&trait_ref.ref_id) {
140-
None => cx.tcx.sess.bug("trait ref not in def map!"),
141-
Some(&trait_def) => {
142-
let trait_def_id = ast_util::def_id_of_def(trait_def);
143-
if cx.tcx.lang_items.drop_trait() == Some(trait_def_id) {
144-
// Yes, it's a destructor.
145-
match self_type.node {
146-
ty_path(_, ref bounds, path_node_id) => {
147-
assert!(bounds.is_none());
148-
let struct_def = cx.tcx.def_map.get_copy(
149-
&path_node_id);
150-
let struct_did =
151-
ast_util::def_id_of_def(struct_def);
152-
check_struct_safe_for_destructor(
153-
cx,
154-
self_type.span,
155-
struct_did);
156-
}
157-
_ => {
158-
cx.tcx.sess.span_bug(self_type.span,
159-
"the self type for \
160-
the Drop trait \
161-
impl is not a \
162-
path");
163-
}
164-
}
165-
}
166-
}
167-
}
163+
check_impl_of_trait(cx, item, trait_ref, self_type);
168164
}
169165
_ => {}
170166
}

src/librustc/middle/lang_items.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use driver::session::Session;
2424
use metadata::csearch::each_lang_item;
2525
use metadata::cstore::iter_crate_data;
26+
use middle::ty::{BuiltinBound, BoundFreeze, BoundSend, BoundSized};
2627
use syntax::ast::{Crate, def_id, MetaItem};
2728
use syntax::ast_util::local_def;
2829
use syntax::attr::AttrMetaMethods;
@@ -158,10 +159,16 @@ impl LanguageItems {
158159
}
159160
}
160161

161-
pub fn is_builtin_kind(&self, id: def_id) -> bool {
162-
Some(id) == self.freeze_trait() ||
163-
Some(id) == self.send_trait() ||
164-
Some(id) == self.sized_trait()
162+
pub fn to_builtin_kind(&self, id: def_id) -> Option<BuiltinBound> {
163+
if Some(id) == self.freeze_trait() {
164+
Some(BoundFreeze)
165+
} else if Some(id) == self.send_trait() {
166+
Some(BoundSend)
167+
} else if Some(id) == self.sized_trait() {
168+
Some(BoundSized)
169+
} else {
170+
None
171+
}
165172
}
166173

167174
pub fn freeze_trait(&self) -> Option<def_id> {

src/librustc/middle/ty.rs

+17-3
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,7 @@ pub struct ty_param_bounds_and_ty {
863863
/// As `ty_param_bounds_and_ty` but for a trait ref.
864864
pub struct TraitDef {
865865
generics: Generics,
866+
bounds: BuiltinBounds,
866867
trait_ref: @ty::TraitRef,
867868
}
868869

@@ -3725,10 +3726,23 @@ pub fn impl_trait_ref(cx: ctxt, id: ast::def_id) -> Option<@TraitRef> {
37253726
return ret;
37263727
}
37273728

3728-
pub fn trait_ref_is_builtin_kind(tcx: ctxt, tr: &ast::trait_ref) -> bool {
3729+
pub fn trait_ref_to_def_id(tcx: ctxt, tr: &ast::trait_ref) -> ast::def_id {
37293730
let def = tcx.def_map.find(&tr.ref_id).expect("no def-map entry for trait");
3730-
let def_id = ast_util::def_id_of_def(*def);
3731-
tcx.lang_items.is_builtin_kind(def_id)
3731+
ast_util::def_id_of_def(*def)
3732+
}
3733+
3734+
pub fn try_add_builtin_trait(tcx: ctxt,
3735+
trait_def_id: ast::def_id,
3736+
builtin_bounds: &mut BuiltinBounds) -> bool {
3737+
//! Checks whether `trait_ref` refers to one of the builtin
3738+
//! traits, like `Send`, and adds the corresponding
3739+
//! bound to the set `builtin_bounds` if so. Returns true if `trait_ref`
3740+
//! is a builtin trait.
3741+
3742+
match tcx.lang_items.to_builtin_kind(trait_def_id) {
3743+
Some(bound) => { builtin_bounds.add(bound); true }
3744+
None => false
3745+
}
37323746
}
37333747

37343748
pub fn ty_to_def_id(ty: t) -> Option<ast::def_id> {

src/librustc/middle/typeck/astconv.rs

+2-26
Original file line numberDiff line numberDiff line change
@@ -773,9 +773,8 @@ fn conv_builtin_bounds(tcx: ty::ctxt, ast_bounds: &Option<OptVec<ast::TyParamBou
773773
ast::TraitTyParamBound(ref b) => {
774774
match lookup_def_tcx(tcx, b.path.span, b.ref_id) {
775775
ast::def_trait(trait_did) => {
776-
if try_add_builtin_trait(tcx,
777-
trait_did,
778-
&mut builtin_bounds) {
776+
if ty::try_add_builtin_trait(tcx, trait_did,
777+
&mut builtin_bounds) {
779778
loop; // success
780779
}
781780
}
@@ -807,26 +806,3 @@ fn conv_builtin_bounds(tcx: ty::ctxt, ast_bounds: &Option<OptVec<ast::TyParamBou
807806
(&None, ty::RegionTraitStore(*)) => ty::EmptyBuiltinBounds(),
808807
}
809808
}
810-
811-
pub fn try_add_builtin_trait(tcx: ty::ctxt,
812-
trait_def_id: ast::def_id,
813-
builtin_bounds: &mut ty::BuiltinBounds) -> bool {
814-
//! Checks whether `trait_ref` refers to one of the builtin
815-
//! traits, like `Send`, and adds the corresponding
816-
//! bound to the set `builtin_bounds` if so. Returns true if `trait_ref`
817-
//! is a builtin trait.
818-
819-
let li = &tcx.lang_items;
820-
if Some(trait_def_id) == li.send_trait() {
821-
builtin_bounds.add(ty::BoundSend);
822-
true
823-
} else if Some(trait_def_id) == li.freeze_trait() {
824-
builtin_bounds.add(ty::BoundFreeze);
825-
true
826-
} else if Some(trait_def_id) == li.sized_trait() {
827-
builtin_bounds.add(ty::BoundSized);
828-
true
829-
} else {
830-
false
831-
}
832-
}

src/librustc/middle/typeck/collect.rs

+32-19
Original file line numberDiff line numberDiff line change
@@ -398,28 +398,39 @@ pub fn ensure_supertraits(ccx: &CrateCtxt,
398398
sp: codemap::span,
399399
rp: Option<ty::region_variance>,
400400
ast_trait_refs: &[ast::trait_ref],
401-
generics: &ast::Generics)
401+
generics: &ast::Generics) -> ty::BuiltinBounds
402402
{
403403
let tcx = ccx.tcx;
404-
if tcx.supertraits.contains_key(&local_def(id)) { return; }
404+
405+
// Called only the first time trait_def_of_item is called.
406+
// Supertraits are ensured at the same time.
407+
assert!(!tcx.supertraits.contains_key(&local_def(id)));
405408

406409
let self_ty = ty::mk_self(ccx.tcx, local_def(id));
407410
let mut ty_trait_refs: ~[@ty::TraitRef] = ~[];
411+
let mut bounds = ty::EmptyBuiltinBounds();
408412
for ast_trait_ref in ast_trait_refs.iter() {
413+
let trait_def_id = ty::trait_ref_to_def_id(ccx.tcx, ast_trait_ref);
414+
// FIXME(#8559): Need to instantiate the trait_ref whether or not it's a
415+
// builtin trait, so that the trait's node id appears in the tcx trait_ref
416+
// map. This is only needed for metadata; see the similar fixme in encoder.rs.
409417
let trait_ref = instantiate_trait_ref(ccx, ast_trait_ref, rp,
410418
generics, self_ty);
411-
412-
// FIXME(#5527) Could have same trait multiple times
413-
if ty_trait_refs.iter().any(|other_trait| other_trait.def_id == trait_ref.def_id) {
414-
// This means a trait inherited from the same supertrait more
415-
// than once.
416-
tcx.sess.span_err(sp, "Duplicate supertrait in trait declaration");
417-
break;
418-
} else {
419-
ty_trait_refs.push(trait_ref);
419+
if !ty::try_add_builtin_trait(ccx.tcx, trait_def_id, &mut bounds) {
420+
421+
// FIXME(#5527) Could have same trait multiple times
422+
if ty_trait_refs.iter().any(|other_trait| other_trait.def_id == trait_ref.def_id) {
423+
// This means a trait inherited from the same supertrait more
424+
// than once.
425+
tcx.sess.span_err(sp, "Duplicate supertrait in trait declaration");
426+
break;
427+
} else {
428+
ty_trait_refs.push(trait_ref);
429+
}
420430
}
421431
}
422432
tcx.supertraits.insert(local_def(id), @ty_trait_refs);
433+
bounds
423434
}
424435

425436
/**
@@ -870,20 +881,19 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::item) {
870881
parent_visibility);
871882
for t in opt_trait_ref.iter() {
872883
// Prevent the builtin kind traits from being manually implemented.
873-
if ty::trait_ref_is_builtin_kind(ccx.tcx, t) {
874-
ccx.tcx.sess.span_err(it.span,
884+
let trait_def_id = ty::trait_ref_to_def_id(tcx, t);
885+
if tcx.lang_items.to_builtin_kind(trait_def_id).is_some() {
886+
tcx.sess.span_err(it.span,
875887
"cannot provide an explicit implementation \
876888
for a builtin kind");
877889
}
878890

879891
check_methods_against_trait(ccx, generics, rp, selfty, t, cms);
880892
}
881893
}
882-
ast::item_trait(ref generics, ref supertraits, ref trait_methods) => {
883-
let trait_def = trait_def_of_item(ccx, it);
884-
tcx.trait_defs.insert(local_def(it.id), trait_def);
894+
ast::item_trait(ref generics, _, ref trait_methods) => {
895+
let _trait_def = trait_def_of_item(ccx, it);
885896
ensure_trait_methods(ccx, it.id);
886-
ensure_supertraits(ccx, it.id, it.span, rp, *supertraits, generics);
887897

888898
let (_, provided_methods) =
889899
split_trait_methods(*trait_methods);
@@ -1039,13 +1049,16 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::item) -> @ty::TraitDef {
10391049
}
10401050
let rp = tcx.region_paramd_items.find(&it.id).map_move(|x| *x);
10411051
match it.node {
1042-
ast::item_trait(ref generics, _, _) => {
1052+
ast::item_trait(ref generics, ref supertraits, _) => {
10431053
let self_ty = ty::mk_self(tcx, def_id);
10441054
let (ty_generics, substs) = mk_item_substs(ccx, generics, rp,
10451055
Some(self_ty));
1056+
let bounds = ensure_supertraits(ccx, it.id, it.span, rp,
1057+
*supertraits, generics);
10461058
let trait_ref = @ty::TraitRef {def_id: def_id,
10471059
substs: substs};
10481060
let trait_def = @ty::TraitDef {generics: ty_generics,
1061+
bounds: bounds,
10491062
trait_ref: trait_ref};
10501063
tcx.trait_defs.insert(def_id, trait_def);
10511064
return trait_def;
@@ -1225,7 +1238,7 @@ pub fn ty_generics(ccx: &CrateCtxt,
12251238
TraitTyParamBound(ref b) => {
12261239
let ty = ty::mk_param(ccx.tcx, param_ty.idx, param_ty.def_id);
12271240
let trait_ref = instantiate_trait_ref(ccx, b, rp, generics, ty);
1228-
if !astconv::try_add_builtin_trait(
1241+
if !ty::try_add_builtin_trait(
12291242
ccx.tcx, trait_ref.def_id,
12301243
&mut param_bounds.builtin_bounds)
12311244
{

0 commit comments

Comments
 (0)