Skip to content

Superkinds #8562

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
20 changes: 19 additions & 1 deletion src/librustc/metadata/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -375,9 +375,21 @@ pub fn get_trait_def(cdata: cmd,
let tp_defs = item_ty_param_defs(item_doc, tcx, cdata,
tag_items_data_item_ty_param_bounds);
let rp = item_ty_region_param(item_doc);
let mut bounds = ty::EmptyBuiltinBounds();
// Collect the builtin bounds from the encoded supertraits.
// FIXME(#8559): They should be encoded directly.
do reader::tagged_docs(item_doc, tag_item_super_trait_ref) |trait_doc| {
// NB. Bypasses real supertraits. See get_supertraits() if you wanted them.
let trait_ref = doc_trait_ref(trait_doc, tcx, cdata);
do tcx.lang_items.to_builtin_kind(trait_ref.def_id).map_move |bound| {
bounds.add(bound);
};
true
};
ty::TraitDef {
generics: ty::Generics {type_param_defs: tp_defs,
region_param: rp},
bounds: bounds,
trait_ref: @item_trait_ref(item_doc, tcx, cdata)
}
}
Expand Down Expand Up @@ -929,7 +941,13 @@ pub fn get_supertraits(cdata: cmd, id: ast::NodeId, tcx: ty::ctxt)
let mut results = ~[];
let item_doc = lookup_item(id, cdata.data);
do reader::tagged_docs(item_doc, tag_item_super_trait_ref) |trait_doc| {
results.push(@doc_trait_ref(trait_doc, tcx, cdata));
// NB. Only reads the ones that *aren't* builtin-bounds. See also
// get_trait_def() for collecting the builtin bounds.
// FIXME(#8559): The builtin bounds shouldn't be encoded in the first place.
let trait_ref = doc_trait_ref(trait_doc, tcx, cdata);
if tcx.lang_items.to_builtin_kind(trait_ref.def_id).is_none() {
results.push(@trait_ref);
}
true
};
return results;
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1076,6 +1076,9 @@ fn encode_info_for_item(ecx: &EncodeContext,
ebml_w.end_tag();
}
encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
// FIXME(#8559): This should use the tcx's supertrait cache instead of
// reading the AST's list, because the former has already filtered out
// the builtin-kinds-as-supertraits. See corresponding fixme in decoder.
for ast_trait_ref in super_traits.iter() {
let trait_ref = ty::node_id_to_trait_ref(ecx.tcx, ast_trait_ref.ref_id);
encode_trait_ref(ebml_w, ecx, trait_ref, tag_item_super_trait_ref);
Expand Down
74 changes: 35 additions & 39 deletions src/librustc/middle/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,6 @@ use syntax::visit::Visitor;
// primitives in the stdlib are explicitly annotated to only take sendable
// types.

pub static try_adding: &'static str = "Try adding a move";

#[deriving(Clone)]
pub struct Context {
tcx: ty::ctxt,
Expand All @@ -77,9 +75,6 @@ impl Visitor<Context> for KindAnalysisVisitor {
fn visit_item(&mut self, i:@item, e:Context) {
check_item(self, i, e);
}
fn visit_block(&mut self, b:&Block, e:Context) {
check_block(self, b, e);
}
}

pub fn check_crate(tcx: ty::ctxt,
Expand Down Expand Up @@ -125,46 +120,47 @@ fn check_struct_safe_for_destructor(cx: Context,
}
}

fn check_block(visitor: &mut KindAnalysisVisitor,
block: &Block,
cx: Context) {
visit::walk_block(visitor, block, cx);
fn check_impl_of_trait(cx: Context, it: @item, trait_ref: &trait_ref, self_type: &Ty) {
let ast_trait_def = cx.tcx.def_map.find(&trait_ref.ref_id)
.expect("trait ref not in def map!");
let trait_def_id = ast_util::def_id_of_def(*ast_trait_def);
let trait_def = cx.tcx.trait_defs.find(&trait_def_id)
.expect("trait def not in trait-defs map!");

// If this trait has builtin-kind supertraits, meet them.
let self_ty: ty::t = ty::node_id_to_type(cx.tcx, it.id);
error!("checking impl with self type %?", ty::get(self_ty).sty);
do check_builtin_bounds(cx, self_ty, trait_def.bounds) |missing| {
cx.tcx.sess.span_err(self_type.span,
fmt!("the type `%s', which does not fulfill `%s`, cannot implement this \
trait", ty_to_str(cx.tcx, self_ty), missing.user_string(cx.tcx)));
cx.tcx.sess.span_note(self_type.span,
fmt!("types implementing this trait must fulfill `%s`",
trait_def.bounds.user_string(cx.tcx)));
}

// If this is a destructor, check kinds.
if cx.tcx.lang_items.drop_trait() == Some(trait_def_id) {
match self_type.node {
ty_path(_, ref bounds, path_node_id) => {
assert!(bounds.is_none());
let struct_def = cx.tcx.def_map.get_copy(&path_node_id);
let struct_did = ast_util::def_id_of_def(struct_def);
check_struct_safe_for_destructor(cx, self_type.span, struct_did);
}
_ => {
cx.tcx.sess.span_bug(self_type.span,
"the self type for the Drop trait impl is not a path");
}
}
}
}

fn check_item(visitor: &mut KindAnalysisVisitor, item: @item, cx: Context) {
// If this is a destructor, check kinds.
if !attr::contains_name(item.attrs, "unsafe_destructor") {
match item.node {
item_impl(_, Some(ref trait_ref), ref self_type, _) => {
match cx.tcx.def_map.find(&trait_ref.ref_id) {
None => cx.tcx.sess.bug("trait ref not in def map!"),
Some(&trait_def) => {
let trait_def_id = ast_util::def_id_of_def(trait_def);
if cx.tcx.lang_items.drop_trait() == Some(trait_def_id) {
// Yes, it's a destructor.
match self_type.node {
ty_path(_, ref bounds, path_node_id) => {
assert!(bounds.is_none());
let struct_def = cx.tcx.def_map.get_copy(
&path_node_id);
let struct_did =
ast_util::def_id_of_def(struct_def);
check_struct_safe_for_destructor(
cx,
self_type.span,
struct_did);
}
_ => {
cx.tcx.sess.span_bug(self_type.span,
"the self type for \
the Drop trait \
impl is not a \
path");
}
}
}
}
}
check_impl_of_trait(cx, item, trait_ref, self_type);
}
_ => {}
}
Expand Down
13 changes: 13 additions & 0 deletions src/librustc/middle/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
use driver::session::Session;
use metadata::csearch::each_lang_item;
use metadata::cstore::iter_crate_data;
use middle::ty::{BuiltinBound, BoundFreeze, BoundSend, BoundSized};
use syntax::ast::{Crate, def_id, MetaItem};
use syntax::ast_util::local_def;
use syntax::attr::AttrMetaMethods;
Expand Down Expand Up @@ -158,6 +159,18 @@ impl LanguageItems {
}
}

pub fn to_builtin_kind(&self, id: def_id) -> Option<BuiltinBound> {
if Some(id) == self.freeze_trait() {
Some(BoundFreeze)
} else if Some(id) == self.send_trait() {
Some(BoundSend)
} else if Some(id) == self.sized_trait() {
Some(BoundSized)
} else {
None
}
}

pub fn freeze_trait(&self) -> Option<def_id> {
self.items[FreezeTraitLangItem as uint]
}
Expand Down
63 changes: 50 additions & 13 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,7 @@ pub struct ty_param_bounds_and_ty {
/// As `ty_param_bounds_and_ty` but for a trait ref.
pub struct TraitDef {
generics: Generics,
bounds: BuiltinBounds,
trait_ref: @ty::TraitRef,
}

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

type_param_def_to_contents(
cx, cx.ty_param_defs.get(&p.def_id.node))
let tp_def = cx.ty_param_defs.get(&p.def_id.node);
kind_bounds_to_contents(cx, &tp_def.bounds.builtin_bounds,
tp_def.bounds.trait_bounds)
}

ty_self(_) => {
// Currently, self is not bounded, so we must assume the
// worst. But in the future we should examine the super
// traits.
//
ty_self(def_id) => {
// FIXME(#4678)---self should just be a ty param
TC_ALL

// Self may be bounded if the associated trait has builtin kinds
// for supertraits. If so we can use those bounds.
let trait_def = lookup_trait_def(cx, def_id);
let traits = [trait_def.trait_ref];
kind_bounds_to_contents(cx, &trait_def.bounds, traits)
}

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

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

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

debug!("result = %s", tc.to_str());
return tc;

// Iterates over all builtin bounds on the type parameter def, including
// those inherited from traits with builtin-kind-supertraits.
fn each_inherited_builtin_bound(cx: ctxt, bounds: &BuiltinBounds,
traits: &[@TraitRef], f: &fn(BuiltinBound)) {
for bound in bounds.iter() {
f(bound);
}

do each_bound_trait_and_supertraits(cx, traits) |trait_ref| {
let trait_def = lookup_trait_def(cx, trait_ref.def_id);
for bound in trait_def.bounds.iter() {
f(bound);
}
true
};
}
}
}

Expand Down Expand Up @@ -3725,6 +3743,25 @@ pub fn impl_trait_ref(cx: ctxt, id: ast::def_id) -> Option<@TraitRef> {
return ret;
}

pub fn trait_ref_to_def_id(tcx: ctxt, tr: &ast::trait_ref) -> ast::def_id {
let def = tcx.def_map.find(&tr.ref_id).expect("no def-map entry for trait");
ast_util::def_id_of_def(*def)
}

pub fn try_add_builtin_trait(tcx: ctxt,
trait_def_id: ast::def_id,
builtin_bounds: &mut BuiltinBounds) -> bool {
//! Checks whether `trait_ref` refers to one of the builtin
//! traits, like `Send`, and adds the corresponding
//! bound to the set `builtin_bounds` if so. Returns true if `trait_ref`
//! is a builtin trait.

match tcx.lang_items.to_builtin_kind(trait_def_id) {
Some(bound) => { builtin_bounds.add(bound); true }
None => false
}
}

pub fn ty_to_def_id(ty: t) -> Option<ast::def_id> {
match get(ty).sty {
ty_trait(id, _, _, _, _) | ty_struct(id, _) | ty_enum(id, _) => Some(id),
Expand Down
28 changes: 2 additions & 26 deletions src/librustc/middle/typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -773,9 +773,8 @@ fn conv_builtin_bounds(tcx: ty::ctxt, ast_bounds: &Option<OptVec<ast::TyParamBou
ast::TraitTyParamBound(ref b) => {
match lookup_def_tcx(tcx, b.path.span, b.ref_id) {
ast::def_trait(trait_did) => {
if try_add_builtin_trait(tcx,
trait_did,
&mut builtin_bounds) {
if ty::try_add_builtin_trait(tcx, trait_did,
&mut builtin_bounds) {
loop; // success
}
}
Expand Down Expand Up @@ -807,26 +806,3 @@ fn conv_builtin_bounds(tcx: ty::ctxt, ast_bounds: &Option<OptVec<ast::TyParamBou
(&None, ty::RegionTraitStore(*)) => ty::EmptyBuiltinBounds(),
}
}

pub fn try_add_builtin_trait(tcx: ty::ctxt,
trait_def_id: ast::def_id,
builtin_bounds: &mut ty::BuiltinBounds) -> bool {
//! Checks whether `trait_ref` refers to one of the builtin
//! traits, like `Send`, and adds the corresponding
//! bound to the set `builtin_bounds` if so. Returns true if `trait_ref`
//! is a builtin trait.

let li = &tcx.lang_items;
if Some(trait_def_id) == li.send_trait() {
builtin_bounds.add(ty::BoundSend);
true
} else if Some(trait_def_id) == li.freeze_trait() {
builtin_bounds.add(ty::BoundFreeze);
true
} else if Some(trait_def_id) == li.sized_trait() {
builtin_bounds.add(ty::BoundSized);
true
} else {
false
}
}
Loading