Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Support unsized types with the type keyword
  • Loading branch information
nrc committed Apr 23, 2014
1 parent c3b2f2b commit f78add1
Show file tree
Hide file tree
Showing 39 changed files with 484 additions and 73 deletions.
4 changes: 2 additions & 2 deletions src/librustc/front/config.rs
Expand Up @@ -103,12 +103,12 @@ fn fold_item_underscore(cx: &mut Context, item: &ast::Item_) -> ast::Item_ {
.map(|x| *x).collect();
ast::ItemImpl((*a).clone(), (*b).clone(), c, methods)
}
ast::ItemTrait(ref a, ref b, ref methods) => {
ast::ItemTrait(ref a, b, ref c, ref methods) => {
let methods = methods.iter()
.filter(|m| trait_method_in_cfg(cx, *m) )
.map(|x| (*x).clone())
.collect();
ast::ItemTrait((*a).clone(), (*b).clone(), methods)
ast::ItemTrait((*a).clone(), b, (*c).clone(), methods)
}
ast::ItemStruct(def, ref generics) => {
ast::ItemStruct(fold_struct(cx, def), generics.clone())
Expand Down
1 change: 1 addition & 0 deletions src/librustc/metadata/common.rs
Expand Up @@ -170,6 +170,7 @@ pub static tag_lang_items_item_node_id: uint = 0x73;

pub static tag_item_unnamed_field: uint = 0x74;
pub static tag_items_data_item_visibility: uint = 0x76;
pub static tag_items_data_item_sized: uint = 0x77;

pub static tag_item_method_tps: uint = 0x79;
pub static tag_item_method_fty: uint = 0x7a;
Expand Down
21 changes: 21 additions & 0 deletions src/librustc/metadata/decoder.rs
Expand Up @@ -164,6 +164,19 @@ fn item_visibility(item: ebml::Doc) -> ast::Visibility {
}
}

fn item_sized(item: ebml::Doc) -> ast::Sized {
match reader::maybe_get_doc(item, tag_items_data_item_sized) {
None => ast::StaticSize,
Some(sized_doc) => {
match reader::doc_as_u8(sized_doc) as char {
'd' => ast::DynSize,
's' => ast::StaticSize,
_ => fail!("unknown sized-ness character")
}
}
}
}

fn item_method_sort(item: ebml::Doc) -> char {
let mut ret = 'r';
reader::tagged_docs(item, tag_item_trait_method_sort, |doc| {
Expand Down Expand Up @@ -371,6 +384,7 @@ 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_defs = item_region_param_defs(item_doc, cdata);
let sized = item_sized(item_doc);
let mut bounds = ty::EmptyBuiltinBounds();
// Collect the builtin bounds from the encoded supertraits.
// FIXME(#8559): They should be encoded directly.
Expand All @@ -382,6 +396,13 @@ pub fn get_trait_def(cdata: Cmd,
});
true
});
// Turn sized into a bound, FIXME(#8559).
if sized == ast::StaticSize {
tcx.lang_items.to_builtin_kind(tcx.lang_items.sized_trait().unwrap()).map(|bound| {
bounds.add(bound);
});
}

ty::TraitDef {
generics: ty::Generics {type_param_defs: tp_defs,
region_param_defs: rp_defs},
Expand Down
15 changes: 14 additions & 1 deletion src/librustc/metadata/encoder.rs
Expand Up @@ -832,6 +832,16 @@ fn encode_extension_implementations(ecx: &EncodeContext,
}
}

fn encode_sized(ebml_w: &mut Encoder, sized: Sized) {
ebml_w.start_tag(tag_items_data_item_sized);
let ch = match sized {
DynSize => 'd',
StaticSize => 's',
};
ebml_w.wr_str(str::from_char(ch));
ebml_w.end_tag();
}

fn encode_info_for_item(ecx: &EncodeContext,
ebml_w: &mut Encoder,
item: &Item,
Expand Down Expand Up @@ -1070,7 +1080,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
ast_method)
}
}
ItemTrait(_, ref super_traits, ref ms) => {
ItemTrait(_, sized, ref super_traits, ref ms) => {
add_to_index(item, ebml_w, index);
ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, def_id);
Expand All @@ -1084,6 +1094,9 @@ fn encode_info_for_item(ecx: &EncodeContext,
encode_trait_ref(ebml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref);
encode_name(ebml_w, item.ident.name);
encode_attributes(ebml_w, item.attrs.as_slice());
// When we fix the rest of the supertrait nastiness (FIXME(#8559)), we
// should no longer need this ugly little hack either.
encode_sized(ebml_w, sized);
encode_visibility(ebml_w, vis);
for &method_def_id in ty::trait_method_def_ids(tcx, def_id).iter() {
ebml_w.start_tag(tag_item_trait_method);
Expand Down
8 changes: 4 additions & 4 deletions src/librustc/middle/privacy.rs
Expand Up @@ -79,7 +79,7 @@ impl Visitor<()> for ParentVisitor {
// method to the root. In this case, if the trait is private, then
// parent all the methods to the trait to indicate that they're
// private.
ast::ItemTrait(_, _, ref methods) if item.vis != ast::Public => {
ast::ItemTrait(_, _, _, ref methods) if item.vis != ast::Public => {
for m in methods.iter() {
match *m {
ast::Provided(ref m) => self.parents.insert(m.id, item.id),
Expand Down Expand Up @@ -274,7 +274,7 @@ impl<'a> Visitor<()> for EmbargoVisitor<'a> {

// Default methods on traits are all public so long as the trait
// is public
ast::ItemTrait(_, _, ref methods) if public_first => {
ast::ItemTrait(_, _, _, ref methods) if public_first => {
for method in methods.iter() {
match *method {
ast::Provided(ref m) => {
Expand Down Expand Up @@ -1082,7 +1082,7 @@ impl<'a> SanePrivacyVisitor<'a> {
}
}

ast::ItemTrait(_, _, ref methods) => {
ast::ItemTrait(_, _, _, ref methods) => {
for m in methods.iter() {
match *m {
ast::Provided(ref m) => {
Expand Down Expand Up @@ -1142,7 +1142,7 @@ impl<'a> SanePrivacyVisitor<'a> {

ast::ItemStruct(ref def, _) => check_struct(def),

ast::ItemTrait(_, _, ref methods) => {
ast::ItemTrait(_, _, _, ref methods) => {
for m in methods.iter() {
match *m {
ast::Required(..) => {}
Expand Down
7 changes: 3 additions & 4 deletions src/librustc/middle/resolve.rs
Expand Up @@ -1325,7 +1325,7 @@ impl<'a> Resolver<'a> {

ItemImpl(_, Some(_), _, _) => parent,

ItemTrait(_, _, ref methods) => {
ItemTrait(_, _, _, ref methods) => {
let name_bindings =
self.add_child(ident, parent.clone(), ForbidDuplicateTypes, sp);

Expand Down Expand Up @@ -3578,7 +3578,7 @@ impl<'a> Resolver<'a> {
methods.as_slice());
}

ItemTrait(ref generics, ref traits, ref methods) => {
ItemTrait(ref generics, _, ref traits, ref methods) => {
// Create a new rib for the self type.
let self_type_rib = Rib::new(NormalRibKind);
// plain insert (no renaming)
Expand Down Expand Up @@ -3786,9 +3786,8 @@ impl<'a> Resolver<'a> {
}
Some(declaration) => {
for argument in declaration.inputs.iter() {
let binding_mode = ArgumentIrrefutableMode;
this.resolve_pattern(argument.pat,
binding_mode,
ArgumentIrrefutableMode,
None);

this.resolve_type(argument.ty);
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/resolve_lifetime.rs
Expand Up @@ -84,7 +84,7 @@ impl<'a, 'b> Visitor<Scope<'a>> for LifetimeContext<'b> {
ast::ItemEnum(_, ref generics) |
ast::ItemStruct(_, ref generics) |
ast::ItemImpl(ref generics, _, _, _) |
ast::ItemTrait(ref generics, _, _) => {
ast::ItemTrait(ref generics, _, _, _) => {
self.check_lifetime_names(&generics.lifetimes);
EarlyScope(0, &generics.lifetimes, &root)
}
Expand Down
26 changes: 17 additions & 9 deletions src/librustc/middle/ty.rs
Expand Up @@ -2591,16 +2591,24 @@ pub fn type_is_machine(ty: t) -> bool {
#[allow(dead_code)] // leaving in for DST
pub fn type_is_sized(cx: &ctxt, ty: ty::t) -> bool {
match get(ty).sty {
// FIXME(#6308) add trait, vec, str, etc here.
ty_param(p) => {
ty_param(tp) => {
assert_eq!(tp.def_id.krate, ast::LOCAL_CRATE);

let ty_param_defs = cx.ty_param_defs.borrow();
let param_def = ty_param_defs.get(&p.def_id.node);
if param_def.bounds.builtin_bounds.contains_elem(BoundSized) {
return true;
}
return false;
let param_def = ty_param_defs.get(&tp.def_id.node);
param_def.bounds.builtin_bounds.contains_elem(BoundSized)
},
_ => return true,
ty_self(def_id) => {
let trait_def = lookup_trait_def(cx, def_id);
trait_def.bounds.contains_elem(BoundSized)
},
ty_struct(def_id, ref substs) => {
let flds = lookup_struct_fields(cx, def_id);
let mut tps = flds.iter().map(|f| lookup_field_type(cx, def_id, f.id, substs));
!tps.any(|ty| !type_is_sized(cx, ty))
}
ty_tup(ref ts) => !ts.iter().any(|t| !type_is_sized(cx, *t)),
_ => true
}
}

Expand Down Expand Up @@ -3495,7 +3503,7 @@ pub fn provided_trait_methods(cx: &ctxt, id: ast::DefId) -> Vec<Rc<Method>> {
match cx.map.find(id.node) {
Some(ast_map::NodeItem(item)) => {
match item.node {
ItemTrait(_, _, ref ms) => {
ItemTrait(_, _, _, ref ms) => {
let (_, p) = ast_util::split_trait_methods(ms.as_slice());
p.iter().map(|m| method(cx, ast_util::local_def(m.id))).collect()
}
Expand Down
57 changes: 41 additions & 16 deletions src/librustc/middle/typeck/check/mod.rs
Expand Up @@ -369,21 +369,21 @@ impl<'a> GatherLocalsVisitor<'a> {
}

impl<'a> Visitor<()> for GatherLocalsVisitor<'a> {
// Add explicitly-declared locals.
// Add explicitly-declared locals.
fn visit_local(&mut self, local: &ast::Local, _: ()) {
let o_ty = match local.ty.node {
ast::TyInfer => None,
_ => Some(self.fcx.to_ty(local.ty))
};
self.assign(local.id, o_ty);
debug!("Local variable {} is assigned type {}",
self.fcx.pat_to_str(local.pat),
self.fcx.infcx().ty_to_str(
self.fcx.inh.locals.borrow().get_copy(&local.id)));
visit::walk_local(self, local, ());

let o_ty = match local.ty.node {
ast::TyInfer => None,
_ => Some(self.fcx.to_ty(local.ty))
};
self.assign(local.id, o_ty);
debug!("Local variable {} is assigned type {}",
self.fcx.pat_to_str(local.pat),
self.fcx.infcx().ty_to_str(
self.fcx.inh.locals.borrow().get_copy(&local.id)));
visit::walk_local(self, local, ());
}
// Add pattern bindings.

// Add pattern bindings.
fn visit_pat(&mut self, p: &ast::Pat, _: ()) {
match p.node {
ast::PatIdent(_, ref path, _)
Expand Down Expand Up @@ -561,14 +561,37 @@ fn check_for_field_shadowing(tcx: &ty::ctxt,
}
}

fn check_fields_sized(tcx: &ty::ctxt,
id: ast::NodeId) {
let struct_def = tcx.map.expect_struct(id);
// FIXME(#13121) allow the last field to be DST
for f in struct_def.fields.iter() {
let t = ty::node_id_to_type(tcx, f.node.id);
if !ty::type_is_sized(tcx, t) {
match f.node.kind {
ast::NamedField(ident, _) => {
tcx.sess.span_err(f.span, format!("Dynamically sized type in field {}",
token::get_ident(ident)));
}
ast::UnnamedField(_) => {
tcx.sess.span_err(f.span, "Dynamically sized type in field");
}
}
}
}
}

pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
let tcx = ccx.tcx;

// Check that the struct is representable
check_representable(tcx, span, id, "struct");

// Check that the struct is instantiable
check_instantiable(tcx, span, id);
if check_instantiable(tcx, span, id) {
// This might cause stack overflow if id is not instantiable.
check_fields_sized(tcx, id);
}

// Check there are no overlapping fields in super-structs
check_for_field_shadowing(tcx, local_def(id));
Expand Down Expand Up @@ -630,7 +653,7 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) {
}

}
ast::ItemTrait(_, _, ref trait_methods) => {
ast::ItemTrait(_, _, _, ref trait_methods) => {
let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id));
for trait_method in (*trait_methods).iter() {
match *trait_method {
Expand Down Expand Up @@ -3468,14 +3491,16 @@ pub fn check_representable(tcx: &ty::ctxt,
/// is representable, but not instantiable.
pub fn check_instantiable(tcx: &ty::ctxt,
sp: Span,
item_id: ast::NodeId) {
item_id: ast::NodeId) -> bool {
let item_ty = ty::node_id_to_type(tcx, item_id);
if !ty::is_instantiable(tcx, item_ty) {
tcx.sess.span_err(sp, format!("this type cannot be instantiated \
without an instance of itself; \
consider using `Option<{}>`",
ppaux::ty_to_str(tcx, item_ty)));
return false
}
true
}

pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) {
Expand Down

0 comments on commit f78add1

Please sign in to comment.