Skip to content

Commit 653f027

Browse files
committed
auto merge of #8562 : bblum/rust/superkinds, r=nikomatsakis
For #7083. The metadata issue with the old version is now fixed. Ready for review. This is also not the full solution to #7083, because this is not supported yet: ``` trait Foo : Send { } impl <T: Send> Foo for T { } fn foo<T: Foo>(val: T, chan: std::comm::Chan<T>) { chan.send(val); } ``` cc @nikomatsakis
2 parents 18144b1 + 22ad36d commit 653f027

22 files changed

+510
-96
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
@@ -1066,6 +1066,9 @@ fn encode_info_for_item(ecx: &EncodeContext,
10661066
ebml_w.end_tag();
10671067
}
10681068
encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
1069+
// FIXME(#8559): This should use the tcx's supertrait cache instead of
1070+
// reading the AST's list, because the former has already filtered out
1071+
// the builtin-kinds-as-supertraits. See corresponding fixme in decoder.
10691072
for ast_trait_ref in super_traits.iter() {
10701073
let trait_ref = ty::node_id_to_trait_ref(ecx.tcx, ast_trait_ref.ref_id);
10711074
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

+13
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,6 +159,18 @@ impl LanguageItems {
158159
}
159160
}
160161

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+
}
172+
}
173+
161174
pub fn freeze_trait(&self) -> Option<def_id> {
162175
self.items[FreezeTraitLangItem as uint]
163176
}

src/librustc/middle/ty.rs

+50-13
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

@@ -2160,17 +2161,19 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
21602161
// def-id.
21612162
assert_eq!(p.def_id.crate, ast::LOCAL_CRATE);
21622163

2163-
type_param_def_to_contents(
2164-
cx, cx.ty_param_defs.get(&p.def_id.node))
2164+
let tp_def = cx.ty_param_defs.get(&p.def_id.node);
2165+
kind_bounds_to_contents(cx, &tp_def.bounds.builtin_bounds,
2166+
tp_def.bounds.trait_bounds)
21652167
}
21662168

2167-
ty_self(_) => {
2168-
// Currently, self is not bounded, so we must assume the
2169-
// worst. But in the future we should examine the super
2170-
// traits.
2171-
//
2169+
ty_self(def_id) => {
21722170
// FIXME(#4678)---self should just be a ty param
2173-
TC_ALL
2171+
2172+
// Self may be bounded if the associated trait has builtin kinds
2173+
// for supertraits. If so we can use those bounds.
2174+
let trait_def = lookup_trait_def(cx, def_id);
2175+
let traits = [trait_def.trait_ref];
2176+
kind_bounds_to_contents(cx, &trait_def.bounds, traits)
21742177
}
21752178

21762179
ty_infer(_) => {
@@ -2314,14 +2317,12 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
23142317
st + mt + bt
23152318
}
23162319

2317-
fn type_param_def_to_contents(cx: ctxt,
2318-
type_param_def: &TypeParameterDef) -> TypeContents
2319-
{
2320-
debug!("type_param_def_to_contents(%s)", type_param_def.repr(cx));
2320+
fn kind_bounds_to_contents(cx: ctxt, bounds: &BuiltinBounds, traits: &[@TraitRef])
2321+
-> TypeContents {
23212322
let _i = indenter();
23222323

23232324
let mut tc = TC_ALL;
2324-
for bound in type_param_def.bounds.builtin_bounds.iter() {
2325+
do each_inherited_builtin_bound(cx, bounds, traits) |bound| {
23252326
debug!("tc = %s, bound = %?", tc.to_str(), bound);
23262327
tc = tc - match bound {
23272328
BoundStatic => TypeContents::nonstatic(cx),
@@ -2334,6 +2335,23 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
23342335

23352336
debug!("result = %s", tc.to_str());
23362337
return tc;
2338+
2339+
// Iterates over all builtin bounds on the type parameter def, including
2340+
// those inherited from traits with builtin-kind-supertraits.
2341+
fn each_inherited_builtin_bound(cx: ctxt, bounds: &BuiltinBounds,
2342+
traits: &[@TraitRef], f: &fn(BuiltinBound)) {
2343+
for bound in bounds.iter() {
2344+
f(bound);
2345+
}
2346+
2347+
do each_bound_trait_and_supertraits(cx, traits) |trait_ref| {
2348+
let trait_def = lookup_trait_def(cx, trait_ref.def_id);
2349+
for bound in trait_def.bounds.iter() {
2350+
f(bound);
2351+
}
2352+
true
2353+
};
2354+
}
23372355
}
23382356
}
23392357

@@ -3727,6 +3745,25 @@ pub fn impl_trait_ref(cx: ctxt, id: ast::def_id) -> Option<@TraitRef> {
37273745
return ret;
37283746
}
37293747

3748+
pub fn trait_ref_to_def_id(tcx: ctxt, tr: &ast::trait_ref) -> ast::def_id {
3749+
let def = tcx.def_map.find(&tr.ref_id).expect("no def-map entry for trait");
3750+
ast_util::def_id_of_def(*def)
3751+
}
3752+
3753+
pub fn try_add_builtin_trait(tcx: ctxt,
3754+
trait_def_id: ast::def_id,
3755+
builtin_bounds: &mut BuiltinBounds) -> bool {
3756+
//! Checks whether `trait_ref` refers to one of the builtin
3757+
//! traits, like `Send`, and adds the corresponding
3758+
//! bound to the set `builtin_bounds` if so. Returns true if `trait_ref`
3759+
//! is a builtin trait.
3760+
3761+
match tcx.lang_items.to_builtin_kind(trait_def_id) {
3762+
Some(bound) => { builtin_bounds.add(bound); true }
3763+
None => false
3764+
}
3765+
}
3766+
37303767
pub fn ty_to_def_id(ty: t) -> Option<ast::def_id> {
37313768
match get(ty).sty {
37323769
ty_trait(id, _, _, _, _) | ty_struct(id, _) | ty_enum(id, _) => Some(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-
}

0 commit comments

Comments
 (0)