Support unsized types with the type
keyword
This commit is contained in:
parent
c3b2f2b0c6
commit
f78add10cd
@ -103,12 +103,12 @@ fn fold_item_underscore(cx: &mut Context, item: &ast::Item_) -> ast::Item_ {
|
|||||||
.map(|x| *x).collect();
|
.map(|x| *x).collect();
|
||||||
ast::ItemImpl((*a).clone(), (*b).clone(), c, methods)
|
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()
|
let methods = methods.iter()
|
||||||
.filter(|m| trait_method_in_cfg(cx, *m) )
|
.filter(|m| trait_method_in_cfg(cx, *m) )
|
||||||
.map(|x| (*x).clone())
|
.map(|x| (*x).clone())
|
||||||
.collect();
|
.collect();
|
||||||
ast::ItemTrait((*a).clone(), (*b).clone(), methods)
|
ast::ItemTrait((*a).clone(), b, (*c).clone(), methods)
|
||||||
}
|
}
|
||||||
ast::ItemStruct(def, ref generics) => {
|
ast::ItemStruct(def, ref generics) => {
|
||||||
ast::ItemStruct(fold_struct(cx, def), generics.clone())
|
ast::ItemStruct(fold_struct(cx, def), generics.clone())
|
||||||
|
@ -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_item_unnamed_field: uint = 0x74;
|
||||||
pub static tag_items_data_item_visibility: uint = 0x76;
|
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_tps: uint = 0x79;
|
||||||
pub static tag_item_method_fty: uint = 0x7a;
|
pub static tag_item_method_fty: uint = 0x7a;
|
||||||
|
@ -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 {
|
fn item_method_sort(item: ebml::Doc) -> char {
|
||||||
let mut ret = 'r';
|
let mut ret = 'r';
|
||||||
reader::tagged_docs(item, tag_item_trait_method_sort, |doc| {
|
reader::tagged_docs(item, tag_item_trait_method_sort, |doc| {
|
||||||
@ -371,6 +384,7 @@ pub fn get_trait_def(cdata: Cmd,
|
|||||||
let tp_defs = item_ty_param_defs(item_doc, tcx, cdata,
|
let tp_defs = item_ty_param_defs(item_doc, tcx, cdata,
|
||||||
tag_items_data_item_ty_param_bounds);
|
tag_items_data_item_ty_param_bounds);
|
||||||
let rp_defs = item_region_param_defs(item_doc, cdata);
|
let rp_defs = item_region_param_defs(item_doc, cdata);
|
||||||
|
let sized = item_sized(item_doc);
|
||||||
let mut bounds = ty::EmptyBuiltinBounds();
|
let mut bounds = ty::EmptyBuiltinBounds();
|
||||||
// Collect the builtin bounds from the encoded supertraits.
|
// Collect the builtin bounds from the encoded supertraits.
|
||||||
// FIXME(#8559): They should be encoded directly.
|
// FIXME(#8559): They should be encoded directly.
|
||||||
@ -382,6 +396,13 @@ pub fn get_trait_def(cdata: Cmd,
|
|||||||
});
|
});
|
||||||
true
|
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 {
|
ty::TraitDef {
|
||||||
generics: ty::Generics {type_param_defs: tp_defs,
|
generics: ty::Generics {type_param_defs: tp_defs,
|
||||||
region_param_defs: rp_defs},
|
region_param_defs: rp_defs},
|
||||||
|
@ -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,
|
fn encode_info_for_item(ecx: &EncodeContext,
|
||||||
ebml_w: &mut Encoder,
|
ebml_w: &mut Encoder,
|
||||||
item: &Item,
|
item: &Item,
|
||||||
@ -1070,7 +1080,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||||||
ast_method)
|
ast_method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ItemTrait(_, ref super_traits, ref ms) => {
|
ItemTrait(_, sized, ref super_traits, ref ms) => {
|
||||||
add_to_index(item, ebml_w, index);
|
add_to_index(item, ebml_w, index);
|
||||||
ebml_w.start_tag(tag_items_data_item);
|
ebml_w.start_tag(tag_items_data_item);
|
||||||
encode_def_id(ebml_w, def_id);
|
encode_def_id(ebml_w, def_id);
|
||||||
@ -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_trait_ref(ebml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref);
|
||||||
encode_name(ebml_w, item.ident.name);
|
encode_name(ebml_w, item.ident.name);
|
||||||
encode_attributes(ebml_w, item.attrs.as_slice());
|
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);
|
encode_visibility(ebml_w, vis);
|
||||||
for &method_def_id in ty::trait_method_def_ids(tcx, def_id).iter() {
|
for &method_def_id in ty::trait_method_def_ids(tcx, def_id).iter() {
|
||||||
ebml_w.start_tag(tag_item_trait_method);
|
ebml_w.start_tag(tag_item_trait_method);
|
||||||
|
@ -79,7 +79,7 @@ impl Visitor<()> for ParentVisitor {
|
|||||||
// method to the root. In this case, if the trait is private, then
|
// 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
|
// parent all the methods to the trait to indicate that they're
|
||||||
// private.
|
// private.
|
||||||
ast::ItemTrait(_, _, ref methods) if item.vis != ast::Public => {
|
ast::ItemTrait(_, _, _, ref methods) if item.vis != ast::Public => {
|
||||||
for m in methods.iter() {
|
for m in methods.iter() {
|
||||||
match *m {
|
match *m {
|
||||||
ast::Provided(ref m) => self.parents.insert(m.id, item.id),
|
ast::Provided(ref m) => self.parents.insert(m.id, item.id),
|
||||||
@ -274,7 +274,7 @@ impl<'a> Visitor<()> for EmbargoVisitor<'a> {
|
|||||||
|
|
||||||
// Default methods on traits are all public so long as the trait
|
// Default methods on traits are all public so long as the trait
|
||||||
// is public
|
// is public
|
||||||
ast::ItemTrait(_, _, ref methods) if public_first => {
|
ast::ItemTrait(_, _, _, ref methods) if public_first => {
|
||||||
for method in methods.iter() {
|
for method in methods.iter() {
|
||||||
match *method {
|
match *method {
|
||||||
ast::Provided(ref m) => {
|
ast::Provided(ref m) => {
|
||||||
@ -1082,7 +1082,7 @@ impl<'a> SanePrivacyVisitor<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::ItemTrait(_, _, ref methods) => {
|
ast::ItemTrait(_, _, _, ref methods) => {
|
||||||
for m in methods.iter() {
|
for m in methods.iter() {
|
||||||
match *m {
|
match *m {
|
||||||
ast::Provided(ref m) => {
|
ast::Provided(ref m) => {
|
||||||
@ -1142,7 +1142,7 @@ impl<'a> SanePrivacyVisitor<'a> {
|
|||||||
|
|
||||||
ast::ItemStruct(ref def, _) => check_struct(def),
|
ast::ItemStruct(ref def, _) => check_struct(def),
|
||||||
|
|
||||||
ast::ItemTrait(_, _, ref methods) => {
|
ast::ItemTrait(_, _, _, ref methods) => {
|
||||||
for m in methods.iter() {
|
for m in methods.iter() {
|
||||||
match *m {
|
match *m {
|
||||||
ast::Required(..) => {}
|
ast::Required(..) => {}
|
||||||
|
@ -1325,7 +1325,7 @@ impl<'a> Resolver<'a> {
|
|||||||
|
|
||||||
ItemImpl(_, Some(_), _, _) => parent,
|
ItemImpl(_, Some(_), _, _) => parent,
|
||||||
|
|
||||||
ItemTrait(_, _, ref methods) => {
|
ItemTrait(_, _, _, ref methods) => {
|
||||||
let name_bindings =
|
let name_bindings =
|
||||||
self.add_child(ident, parent.clone(), ForbidDuplicateTypes, sp);
|
self.add_child(ident, parent.clone(), ForbidDuplicateTypes, sp);
|
||||||
|
|
||||||
@ -3578,7 +3578,7 @@ impl<'a> Resolver<'a> {
|
|||||||
methods.as_slice());
|
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.
|
// Create a new rib for the self type.
|
||||||
let self_type_rib = Rib::new(NormalRibKind);
|
let self_type_rib = Rib::new(NormalRibKind);
|
||||||
// plain insert (no renaming)
|
// plain insert (no renaming)
|
||||||
@ -3786,9 +3786,8 @@ impl<'a> Resolver<'a> {
|
|||||||
}
|
}
|
||||||
Some(declaration) => {
|
Some(declaration) => {
|
||||||
for argument in declaration.inputs.iter() {
|
for argument in declaration.inputs.iter() {
|
||||||
let binding_mode = ArgumentIrrefutableMode;
|
|
||||||
this.resolve_pattern(argument.pat,
|
this.resolve_pattern(argument.pat,
|
||||||
binding_mode,
|
ArgumentIrrefutableMode,
|
||||||
None);
|
None);
|
||||||
|
|
||||||
this.resolve_type(argument.ty);
|
this.resolve_type(argument.ty);
|
||||||
|
@ -84,7 +84,7 @@ impl<'a, 'b> Visitor<Scope<'a>> for LifetimeContext<'b> {
|
|||||||
ast::ItemEnum(_, ref generics) |
|
ast::ItemEnum(_, ref generics) |
|
||||||
ast::ItemStruct(_, ref generics) |
|
ast::ItemStruct(_, ref generics) |
|
||||||
ast::ItemImpl(ref generics, _, _, _) |
|
ast::ItemImpl(ref generics, _, _, _) |
|
||||||
ast::ItemTrait(ref generics, _, _) => {
|
ast::ItemTrait(ref generics, _, _, _) => {
|
||||||
self.check_lifetime_names(&generics.lifetimes);
|
self.check_lifetime_names(&generics.lifetimes);
|
||||||
EarlyScope(0, &generics.lifetimes, &root)
|
EarlyScope(0, &generics.lifetimes, &root)
|
||||||
}
|
}
|
||||||
|
@ -2591,16 +2591,24 @@ pub fn type_is_machine(ty: t) -> bool {
|
|||||||
#[allow(dead_code)] // leaving in for DST
|
#[allow(dead_code)] // leaving in for DST
|
||||||
pub fn type_is_sized(cx: &ctxt, ty: ty::t) -> bool {
|
pub fn type_is_sized(cx: &ctxt, ty: ty::t) -> bool {
|
||||||
match get(ty).sty {
|
match get(ty).sty {
|
||||||
// FIXME(#6308) add trait, vec, str, etc here.
|
ty_param(tp) => {
|
||||||
ty_param(p) => {
|
assert_eq!(tp.def_id.krate, ast::LOCAL_CRATE);
|
||||||
|
|
||||||
let ty_param_defs = cx.ty_param_defs.borrow();
|
let ty_param_defs = cx.ty_param_defs.borrow();
|
||||||
let param_def = ty_param_defs.get(&p.def_id.node);
|
let param_def = ty_param_defs.get(&tp.def_id.node);
|
||||||
if param_def.bounds.builtin_bounds.contains_elem(BoundSized) {
|
param_def.bounds.builtin_bounds.contains_elem(BoundSized)
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
},
|
||||||
_ => 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3495,7 +3503,7 @@ pub fn provided_trait_methods(cx: &ctxt, id: ast::DefId) -> Vec<Rc<Method>> {
|
|||||||
match cx.map.find(id.node) {
|
match cx.map.find(id.node) {
|
||||||
Some(ast_map::NodeItem(item)) => {
|
Some(ast_map::NodeItem(item)) => {
|
||||||
match item.node {
|
match item.node {
|
||||||
ItemTrait(_, _, ref ms) => {
|
ItemTrait(_, _, _, ref ms) => {
|
||||||
let (_, p) = ast_util::split_trait_methods(ms.as_slice());
|
let (_, p) = ast_util::split_trait_methods(ms.as_slice());
|
||||||
p.iter().map(|m| method(cx, ast_util::local_def(m.id))).collect()
|
p.iter().map(|m| method(cx, ast_util::local_def(m.id))).collect()
|
||||||
}
|
}
|
||||||
|
@ -381,8 +381,8 @@ impl<'a> Visitor<()> for GatherLocalsVisitor<'a> {
|
|||||||
self.fcx.infcx().ty_to_str(
|
self.fcx.infcx().ty_to_str(
|
||||||
self.fcx.inh.locals.borrow().get_copy(&local.id)));
|
self.fcx.inh.locals.borrow().get_copy(&local.id)));
|
||||||
visit::walk_local(self, local, ());
|
visit::walk_local(self, local, ());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add pattern bindings.
|
// Add pattern bindings.
|
||||||
fn visit_pat(&mut self, p: &ast::Pat, _: ()) {
|
fn visit_pat(&mut self, p: &ast::Pat, _: ()) {
|
||||||
match p.node {
|
match p.node {
|
||||||
@ -561,6 +561,26 @@ 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) {
|
pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
|
||||||
let tcx = ccx.tcx;
|
let tcx = ccx.tcx;
|
||||||
|
|
||||||
@ -568,7 +588,10 @@ pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
|
|||||||
check_representable(tcx, span, id, "struct");
|
check_representable(tcx, span, id, "struct");
|
||||||
|
|
||||||
// Check that the struct is instantiable
|
// 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 there are no overlapping fields in super-structs
|
||||||
check_for_field_shadowing(tcx, local_def(id));
|
check_for_field_shadowing(tcx, local_def(id));
|
||||||
@ -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));
|
let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id));
|
||||||
for trait_method in (*trait_methods).iter() {
|
for trait_method in (*trait_methods).iter() {
|
||||||
match *trait_method {
|
match *trait_method {
|
||||||
@ -3468,14 +3491,16 @@ pub fn check_representable(tcx: &ty::ctxt,
|
|||||||
/// is representable, but not instantiable.
|
/// is representable, but not instantiable.
|
||||||
pub fn check_instantiable(tcx: &ty::ctxt,
|
pub fn check_instantiable(tcx: &ty::ctxt,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
item_id: ast::NodeId) {
|
item_id: ast::NodeId) -> bool {
|
||||||
let item_ty = ty::node_id_to_type(tcx, item_id);
|
let item_ty = ty::node_id_to_type(tcx, item_id);
|
||||||
if !ty::is_instantiable(tcx, item_ty) {
|
if !ty::is_instantiable(tcx, item_ty) {
|
||||||
tcx.sess.span_err(sp, format!("this type cannot be instantiated \
|
tcx.sess.span_err(sp, format!("this type cannot be instantiated \
|
||||||
without an instance of itself; \
|
without an instance of itself; \
|
||||||
consider using `Option<{}>`",
|
consider using `Option<{}>`",
|
||||||
ppaux::ty_to_str(tcx, item_ty)));
|
ppaux::ty_to_str(tcx, item_ty)));
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) {
|
pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) {
|
||||||
|
@ -32,6 +32,7 @@ are represented as `ty_param()` instances.
|
|||||||
|
|
||||||
|
|
||||||
use metadata::csearch;
|
use metadata::csearch;
|
||||||
|
use middle::lang_items::SizedTraitLangItem;
|
||||||
use middle::resolve_lifetime;
|
use middle::resolve_lifetime;
|
||||||
use middle::ty::{ImplContainer, MethodContainer, TraitContainer, substs};
|
use middle::ty::{ImplContainer, MethodContainer, TraitContainer, substs};
|
||||||
use middle::ty::{ty_param_bounds_and_ty};
|
use middle::ty::{ty_param_bounds_and_ty};
|
||||||
@ -189,7 +190,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, trait_id: ast::NodeId) {
|
|||||||
match tcx.map.get(trait_id) {
|
match tcx.map.get(trait_id) {
|
||||||
ast_map::NodeItem(item) => {
|
ast_map::NodeItem(item) => {
|
||||||
match item.node {
|
match item.node {
|
||||||
ast::ItemTrait(ref generics, _, ref ms) => {
|
ast::ItemTrait(ref generics, _, _, ref ms) => {
|
||||||
let trait_ty_generics = ty_generics_for_type(ccx, generics);
|
let trait_ty_generics = ty_generics_for_type(ccx, generics);
|
||||||
|
|
||||||
// For each method, construct a suitable ty::Method and
|
// For each method, construct a suitable ty::Method and
|
||||||
@ -402,7 +403,8 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, trait_id: ast::NodeId) {
|
|||||||
pub fn ensure_supertraits(ccx: &CrateCtxt,
|
pub fn ensure_supertraits(ccx: &CrateCtxt,
|
||||||
id: ast::NodeId,
|
id: ast::NodeId,
|
||||||
sp: codemap::Span,
|
sp: codemap::Span,
|
||||||
ast_trait_refs: &[ast::TraitRef])
|
ast_trait_refs: &[ast::TraitRef],
|
||||||
|
sized: ast::Sized)
|
||||||
-> ty::BuiltinBounds
|
-> ty::BuiltinBounds
|
||||||
{
|
{
|
||||||
let tcx = ccx.tcx;
|
let tcx = ccx.tcx;
|
||||||
@ -433,6 +435,12 @@ pub fn ensure_supertraits(ccx: &CrateCtxt,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if sized == ast::StaticSize {
|
||||||
|
match tcx.lang_items.require(SizedTraitLangItem) {
|
||||||
|
Ok(def_id) => { ty::try_add_builtin_trait(tcx, def_id, &mut bounds); },
|
||||||
|
Err(s) => tcx.sess.err(s),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
tcx.supertraits.borrow_mut().insert(local_def(id), Rc::new(ty_trait_refs));
|
tcx.supertraits.borrow_mut().insert(local_def(id), Rc::new(ty_trait_refs));
|
||||||
bounds
|
bounds
|
||||||
@ -562,8 +570,7 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
|
|||||||
if ty_param.bounds.len() > 0 {
|
if ty_param.bounds.len() > 0 {
|
||||||
ccx.tcx.sess.span_err(
|
ccx.tcx.sess.span_err(
|
||||||
span,
|
span,
|
||||||
format!("trait bounds are not allowed in {} definitions",
|
format!("trait bounds are not allowed in {} definitions", thing));
|
||||||
thing));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -634,7 +641,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ast::ItemTrait(ref generics, _, ref trait_methods) => {
|
ast::ItemTrait(ref generics, _, _, ref trait_methods) => {
|
||||||
let trait_def = trait_def_of_item(ccx, it);
|
let trait_def = trait_def_of_item(ccx, it);
|
||||||
|
|
||||||
// Run convert_methods on the provided methods.
|
// Run convert_methods on the provided methods.
|
||||||
@ -863,14 +870,15 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc<ty::TraitDef> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match it.node {
|
match it.node {
|
||||||
ast::ItemTrait(ref generics, ref supertraits, _) => {
|
ast::ItemTrait(ref generics, sized, ref supertraits, _) => {
|
||||||
let self_ty = ty::mk_self(tcx, def_id);
|
let self_ty = ty::mk_self(tcx, def_id);
|
||||||
let ty_generics = ty_generics_for_type(ccx, generics);
|
let ty_generics = ty_generics_for_type(ccx, generics);
|
||||||
let substs = mk_item_substs(ccx, &ty_generics, Some(self_ty));
|
let substs = mk_item_substs(ccx, &ty_generics, Some(self_ty));
|
||||||
let bounds = ensure_supertraits(ccx,
|
let bounds = ensure_supertraits(ccx,
|
||||||
it.id,
|
it.id,
|
||||||
it.span,
|
it.span,
|
||||||
supertraits.as_slice());
|
supertraits.as_slice(),
|
||||||
|
sized);
|
||||||
let trait_def = Rc::new(ty::TraitDef {
|
let trait_def = Rc::new(ty::TraitDef {
|
||||||
generics: ty_generics,
|
generics: ty_generics,
|
||||||
bounds: bounds,
|
bounds: bounds,
|
||||||
@ -1032,7 +1040,12 @@ fn ty_generics(ccx: &CrateCtxt,
|
|||||||
existing_def_opt.unwrap_or_else(|| {
|
existing_def_opt.unwrap_or_else(|| {
|
||||||
let param_ty = ty::param_ty {idx: base_index + offset,
|
let param_ty = ty::param_ty {idx: base_index + offset,
|
||||||
def_id: local_def(param.id)};
|
def_id: local_def(param.id)};
|
||||||
let bounds = Rc::new(compute_bounds(ccx, param_ty, ¶m.bounds));
|
let bounds = Rc::new(compute_bounds(ccx,
|
||||||
|
param_ty,
|
||||||
|
¶m.bounds,
|
||||||
|
param.sized,
|
||||||
|
param.ident,
|
||||||
|
param.span));
|
||||||
let default = param.default.map(|path| {
|
let default = param.default.map(|path| {
|
||||||
let ty = ast_ty_to_ty(ccx, &ExplicitRscope, path);
|
let ty = ast_ty_to_ty(ccx, &ExplicitRscope, path);
|
||||||
let cur_idx = param_ty.idx;
|
let cur_idx = param_ty.idx;
|
||||||
@ -1067,7 +1080,10 @@ fn ty_generics(ccx: &CrateCtxt,
|
|||||||
fn compute_bounds(
|
fn compute_bounds(
|
||||||
ccx: &CrateCtxt,
|
ccx: &CrateCtxt,
|
||||||
param_ty: ty::param_ty,
|
param_ty: ty::param_ty,
|
||||||
ast_bounds: &OwnedSlice<ast::TyParamBound>) -> ty::ParamBounds
|
ast_bounds: &OwnedSlice<ast::TyParamBound>,
|
||||||
|
sized: ast::Sized,
|
||||||
|
ident: ast::Ident,
|
||||||
|
span: Span) -> ty::ParamBounds
|
||||||
{
|
{
|
||||||
/*!
|
/*!
|
||||||
* Translate the AST's notion of ty param bounds (which are an
|
* Translate the AST's notion of ty param bounds (which are an
|
||||||
@ -1087,8 +1103,7 @@ fn ty_generics(ccx: &CrateCtxt,
|
|||||||
let trait_ref = instantiate_trait_ref(ccx, b, ty);
|
let trait_ref = instantiate_trait_ref(ccx, b, ty);
|
||||||
if !ty::try_add_builtin_trait(
|
if !ty::try_add_builtin_trait(
|
||||||
ccx.tcx, trait_ref.def_id,
|
ccx.tcx, trait_ref.def_id,
|
||||||
&mut param_bounds.builtin_bounds)
|
&mut param_bounds.builtin_bounds) {
|
||||||
{
|
|
||||||
// Must be a user-defined trait
|
// Must be a user-defined trait
|
||||||
param_bounds.trait_bounds.push(trait_ref);
|
param_bounds.trait_bounds.push(trait_ref);
|
||||||
}
|
}
|
||||||
@ -1100,8 +1115,45 @@ fn ty_generics(ccx: &CrateCtxt,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if sized == ast::StaticSize {
|
||||||
|
match ccx.tcx.lang_items.require(SizedTraitLangItem) {
|
||||||
|
Ok(def_id) => { ty::try_add_builtin_trait(ccx.tcx,
|
||||||
|
def_id,
|
||||||
|
&mut param_bounds.builtin_bounds); },
|
||||||
|
// Fixme(13367) after `type` makes it into the snapshot, we can check this properly
|
||||||
|
Err(_s) => {}, //ccx.tcx.sess.err(s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
check_bounds_compatible(ccx.tcx, ¶m_bounds, ident, span);
|
||||||
|
|
||||||
param_bounds
|
param_bounds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_bounds_compatible(tcx: &ty::ctxt,
|
||||||
|
param_bounds: &ty::ParamBounds,
|
||||||
|
ident: ast::Ident,
|
||||||
|
span: Span) {
|
||||||
|
// Currently the only bound which is incompatible with other bounds is
|
||||||
|
// Sized/Unsized.
|
||||||
|
if !param_bounds.builtin_bounds.contains_elem(ty::BoundSized) {
|
||||||
|
ty::each_bound_trait_and_supertraits(tcx,
|
||||||
|
param_bounds.trait_bounds.as_slice(),
|
||||||
|
|trait_ref| {
|
||||||
|
let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id);
|
||||||
|
for bound in trait_def.bounds.iter() {
|
||||||
|
if bound == ty::BoundSized {
|
||||||
|
tcx.sess.span_err(span,
|
||||||
|
format!("incompatible bounds on type parameter {}, \
|
||||||
|
bound {} does not allow unsized type",
|
||||||
|
token::get_ident(ident),
|
||||||
|
ppaux::trait_ref_to_str(tcx, trait_ref)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt,
|
pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt,
|
||||||
|
@ -878,6 +878,8 @@ impl<'a> Rebuilder<'a> {
|
|||||||
id: ty_param.id,
|
id: ty_param.id,
|
||||||
bounds: bounds,
|
bounds: bounds,
|
||||||
default: ty_param.default,
|
default: ty_param.default,
|
||||||
|
span: ty_param.span,
|
||||||
|
sized: ty_param.sized,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -347,7 +347,7 @@ impl<'a> Visitor<()> for TermsContext<'a> {
|
|||||||
match item.node {
|
match item.node {
|
||||||
ast::ItemEnum(_, ref generics) |
|
ast::ItemEnum(_, ref generics) |
|
||||||
ast::ItemStruct(_, ref generics) |
|
ast::ItemStruct(_, ref generics) |
|
||||||
ast::ItemTrait(ref generics, _, _) => {
|
ast::ItemTrait(ref generics, _, _, _) => {
|
||||||
for (i, p) in generics.lifetimes.iter().enumerate() {
|
for (i, p) in generics.lifetimes.iter().enumerate() {
|
||||||
self.add_inferred(item.id, RegionParam, i, p.id);
|
self.add_inferred(item.id, RegionParam, i, p.id);
|
||||||
}
|
}
|
||||||
|
@ -261,7 +261,7 @@ impl<'a> RustdocVisitor<'a> {
|
|||||||
};
|
};
|
||||||
om.statics.push(s);
|
om.statics.push(s);
|
||||||
},
|
},
|
||||||
ast::ItemTrait(ref gen, ref tr, ref met) => {
|
ast::ItemTrait(ref gen, _, ref tr, ref met) => {
|
||||||
let t = Trait {
|
let t = Trait {
|
||||||
name: item.ident,
|
name: item.ident,
|
||||||
methods: met.iter().map(|x| (*x).clone()).collect(),
|
methods: met.iter().map(|x| (*x).clone()).collect(),
|
||||||
|
@ -180,6 +180,7 @@ pub enum TyParamBound {
|
|||||||
pub struct TyParam {
|
pub struct TyParam {
|
||||||
pub ident: Ident,
|
pub ident: Ident,
|
||||||
pub id: NodeId,
|
pub id: NodeId,
|
||||||
|
pub sized: Sized,
|
||||||
pub bounds: OwnedSlice<TyParamBound>,
|
pub bounds: OwnedSlice<TyParamBound>,
|
||||||
pub default: Option<P<Ty>>,
|
pub default: Option<P<Ty>>,
|
||||||
pub span: Span
|
pub span: Span
|
||||||
@ -1051,6 +1052,12 @@ impl Visibility {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[deriving(Clone, Eq, TotalEq, Encodable, Decodable, Hash)]
|
||||||
|
pub enum Sized {
|
||||||
|
DynSize,
|
||||||
|
StaticSize,
|
||||||
|
}
|
||||||
|
|
||||||
#[deriving(Clone, Eq, TotalEq, Encodable, Decodable, Hash)]
|
#[deriving(Clone, Eq, TotalEq, Encodable, Decodable, Hash)]
|
||||||
pub struct StructField_ {
|
pub struct StructField_ {
|
||||||
pub kind: StructFieldKind,
|
pub kind: StructFieldKind,
|
||||||
@ -1109,7 +1116,7 @@ pub enum Item_ {
|
|||||||
ItemTy(P<Ty>, Generics),
|
ItemTy(P<Ty>, Generics),
|
||||||
ItemEnum(EnumDef, Generics),
|
ItemEnum(EnumDef, Generics),
|
||||||
ItemStruct(@StructDef, Generics),
|
ItemStruct(@StructDef, Generics),
|
||||||
ItemTrait(Generics, Vec<TraitRef> , Vec<TraitMethod> ),
|
ItemTrait(Generics, Sized, Vec<TraitRef> , Vec<TraitMethod> ),
|
||||||
ItemImpl(Generics,
|
ItemImpl(Generics,
|
||||||
Option<TraitRef>, // (optional) trait this impl implements
|
Option<TraitRef>, // (optional) trait this impl implements
|
||||||
P<Ty>, // self
|
P<Ty>, // self
|
||||||
|
@ -265,6 +265,24 @@ impl Map {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn expect_struct(&self, id: NodeId) -> @StructDef {
|
||||||
|
match self.find(id) {
|
||||||
|
Some(NodeItem(i)) => {
|
||||||
|
match i.node {
|
||||||
|
ItemStruct(struct_def, _) => struct_def,
|
||||||
|
_ => fail!("struct ID bound to non-struct")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(NodeVariant(ref variant)) => {
|
||||||
|
match (*variant).node.kind {
|
||||||
|
StructVariantKind(struct_def) => struct_def,
|
||||||
|
_ => fail!("struct ID bound to enum variant that isn't struct-like"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => fail!(format!("expected struct, found {}", self.node_to_str(id))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn expect_foreign_item(&self, id: NodeId) -> @ForeignItem {
|
pub fn expect_foreign_item(&self, id: NodeId) -> @ForeignItem {
|
||||||
match self.find(id) {
|
match self.find(id) {
|
||||||
Some(NodeForeignItem(item)) => item,
|
Some(NodeForeignItem(item)) => item,
|
||||||
@ -453,7 +471,7 @@ impl<'a, F: FoldOps> Folder for Ctx<'a, F> {
|
|||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ItemTrait(_, ref traits, ref methods) => {
|
ItemTrait(_, _, ref traits, ref methods) => {
|
||||||
for t in traits.iter() {
|
for t in traits.iter() {
|
||||||
self.insert(t.ref_id, EntryItem(self.parent, i));
|
self.insert(t.ref_id, EntryItem(self.parent, i));
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,7 @@ pub trait AstBuilder {
|
|||||||
fn typaram(&self,
|
fn typaram(&self,
|
||||||
span: Span,
|
span: Span,
|
||||||
id: ast::Ident,
|
id: ast::Ident,
|
||||||
|
sized: ast::Sized,
|
||||||
bounds: OwnedSlice<ast::TyParamBound>,
|
bounds: OwnedSlice<ast::TyParamBound>,
|
||||||
default: Option<P<ast::Ty>>) -> ast::TyParam;
|
default: Option<P<ast::Ty>>) -> ast::TyParam;
|
||||||
|
|
||||||
@ -371,11 +372,13 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
|||||||
fn typaram(&self,
|
fn typaram(&self,
|
||||||
span: Span,
|
span: Span,
|
||||||
id: ast::Ident,
|
id: ast::Ident,
|
||||||
|
sized: ast::Sized,
|
||||||
bounds: OwnedSlice<ast::TyParamBound>,
|
bounds: OwnedSlice<ast::TyParamBound>,
|
||||||
default: Option<P<ast::Ty>>) -> ast::TyParam {
|
default: Option<P<ast::Ty>>) -> ast::TyParam {
|
||||||
ast::TyParam {
|
ast::TyParam {
|
||||||
ident: id,
|
ident: id,
|
||||||
id: ast::DUMMY_NODE_ID,
|
id: ast::DUMMY_NODE_ID,
|
||||||
|
sized: sized,
|
||||||
bounds: bounds,
|
bounds: bounds,
|
||||||
default: default,
|
default: default,
|
||||||
span: span
|
span: span
|
||||||
|
@ -13,6 +13,7 @@ The compiler code necessary for `#[deriving(Decodable)]`. See
|
|||||||
encodable.rs for more.
|
encodable.rs for more.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use ast;
|
||||||
use ast::{MetaItem, Item, Expr, MutMutable, Ident};
|
use ast::{MetaItem, Item, Expr, MutMutable, Ident};
|
||||||
use codemap::Span;
|
use codemap::Span;
|
||||||
use ext::base::ExtCtxt;
|
use ext::base::ExtCtxt;
|
||||||
@ -35,10 +36,10 @@ pub fn expand_deriving_decodable(cx: &mut ExtCtxt,
|
|||||||
additional_bounds: Vec::new(),
|
additional_bounds: Vec::new(),
|
||||||
generics: LifetimeBounds {
|
generics: LifetimeBounds {
|
||||||
lifetimes: Vec::new(),
|
lifetimes: Vec::new(),
|
||||||
bounds: vec!(("__D", vec!(Path::new_(
|
bounds: vec!(("__D", ast::StaticSize, vec!(Path::new_(
|
||||||
vec!("serialize", "Decoder"), None,
|
vec!("serialize", "Decoder"), None,
|
||||||
vec!(~Literal(Path::new_local("__E"))), true))),
|
vec!(~Literal(Path::new_local("__E"))), true))),
|
||||||
("__E", vec!()))
|
("__E", ast::StaticSize, vec!()))
|
||||||
},
|
},
|
||||||
methods: vec!(
|
methods: vec!(
|
||||||
MethodDef {
|
MethodDef {
|
||||||
|
@ -82,6 +82,7 @@ would yield functions like:
|
|||||||
```
|
```
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use ast;
|
||||||
use ast::{MetaItem, Item, Expr, ExprRet, MutMutable, LitNil};
|
use ast::{MetaItem, Item, Expr, ExprRet, MutMutable, LitNil};
|
||||||
use codemap::Span;
|
use codemap::Span;
|
||||||
use ext::base::ExtCtxt;
|
use ext::base::ExtCtxt;
|
||||||
@ -103,10 +104,10 @@ pub fn expand_deriving_encodable(cx: &mut ExtCtxt,
|
|||||||
additional_bounds: Vec::new(),
|
additional_bounds: Vec::new(),
|
||||||
generics: LifetimeBounds {
|
generics: LifetimeBounds {
|
||||||
lifetimes: Vec::new(),
|
lifetimes: Vec::new(),
|
||||||
bounds: vec!(("__S", vec!(Path::new_(
|
bounds: vec!(("__S", ast::StaticSize, vec!(Path::new_(
|
||||||
vec!("serialize", "Encoder"), None,
|
vec!("serialize", "Encoder"), None,
|
||||||
vec!(~Literal(Path::new_local("__E"))), true))),
|
vec!(~Literal(Path::new_local("__E"))), true))),
|
||||||
("__E", vec!()))
|
("__E", ast::StaticSize, vec!()))
|
||||||
},
|
},
|
||||||
methods: vec!(
|
methods: vec!(
|
||||||
MethodDef {
|
MethodDef {
|
||||||
|
@ -380,7 +380,11 @@ impl<'a> TraitDef<'a> {
|
|||||||
// require the current trait
|
// require the current trait
|
||||||
bounds.push(cx.typarambound(trait_path.clone()));
|
bounds.push(cx.typarambound(trait_path.clone()));
|
||||||
|
|
||||||
cx.typaram(self.span, ty_param.ident, OwnedSlice::from_vec(bounds), None)
|
cx.typaram(self.span,
|
||||||
|
ty_param.ident,
|
||||||
|
ty_param.sized,
|
||||||
|
OwnedSlice::from_vec(bounds),
|
||||||
|
None)
|
||||||
}));
|
}));
|
||||||
let trait_generics = Generics {
|
let trait_generics = Generics {
|
||||||
lifetimes: lifetimes,
|
lifetimes: lifetimes,
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
use ast;
|
||||||
use ast::{MetaItem, Item, Expr, MutMutable};
|
use ast::{MetaItem, Item, Expr, MutMutable};
|
||||||
use codemap::Span;
|
use codemap::Span;
|
||||||
use ext::base::ExtCtxt;
|
use ext::base::ExtCtxt;
|
||||||
@ -25,7 +26,7 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt,
|
|||||||
vec!(~Literal(Path::new_local("__S"))), true),
|
vec!(~Literal(Path::new_local("__S"))), true),
|
||||||
LifetimeBounds {
|
LifetimeBounds {
|
||||||
lifetimes: Vec::new(),
|
lifetimes: Vec::new(),
|
||||||
bounds: vec!(("__S", vec!(Path::new(vec!("std", "io", "Writer"))))),
|
bounds: vec!(("__S", ast::StaticSize, vec!(Path::new(vec!("std", "io", "Writer"))))),
|
||||||
},
|
},
|
||||||
Path::new_local("__S"))
|
Path::new_local("__S"))
|
||||||
} else {
|
} else {
|
||||||
|
@ -32,6 +32,7 @@ pub fn expand_deriving_rand(cx: &mut ExtCtxt,
|
|||||||
generics: LifetimeBounds {
|
generics: LifetimeBounds {
|
||||||
lifetimes: Vec::new(),
|
lifetimes: Vec::new(),
|
||||||
bounds: vec!(("R",
|
bounds: vec!(("R",
|
||||||
|
ast::StaticSize,
|
||||||
vec!( Path::new(vec!("rand", "Rng")) )))
|
vec!( Path::new(vec!("rand", "Rng")) )))
|
||||||
},
|
},
|
||||||
explicit_self: None,
|
explicit_self: None,
|
||||||
|
@ -186,14 +186,14 @@ impl<'a> Ty<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn mk_ty_param(cx: &ExtCtxt, span: Span, name: &str, bounds: &[Path],
|
fn mk_ty_param(cx: &ExtCtxt, span: Span, name: &str, sized: ast::Sized, bounds: &[Path],
|
||||||
self_ident: Ident, self_generics: &Generics) -> ast::TyParam {
|
self_ident: Ident, self_generics: &Generics) -> ast::TyParam {
|
||||||
let bounds =
|
let bounds =
|
||||||
bounds.iter().map(|b| {
|
bounds.iter().map(|b| {
|
||||||
let path = b.to_path(cx, span, self_ident, self_generics);
|
let path = b.to_path(cx, span, self_ident, self_generics);
|
||||||
cx.typarambound(path)
|
cx.typarambound(path)
|
||||||
}).collect();
|
}).collect();
|
||||||
cx.typaram(span, cx.ident_of(name), bounds, None)
|
cx.typaram(span, cx.ident_of(name), sized, bounds, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_generics(lifetimes: Vec<ast::Lifetime> , ty_params: Vec<ast::TyParam> ) -> Generics {
|
fn mk_generics(lifetimes: Vec<ast::Lifetime> , ty_params: Vec<ast::TyParam> ) -> Generics {
|
||||||
@ -206,7 +206,7 @@ fn mk_generics(lifetimes: Vec<ast::Lifetime> , ty_params: Vec<ast::TyParam> ) -
|
|||||||
/// Lifetimes and bounds on type parameters
|
/// Lifetimes and bounds on type parameters
|
||||||
pub struct LifetimeBounds<'a> {
|
pub struct LifetimeBounds<'a> {
|
||||||
pub lifetimes: Vec<&'a str>,
|
pub lifetimes: Vec<&'a str>,
|
||||||
pub bounds: Vec<(&'a str, Vec<Path<'a>>)>,
|
pub bounds: Vec<(&'a str, ast::Sized, Vec<Path<'a>>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> LifetimeBounds<'a> {
|
impl<'a> LifetimeBounds<'a> {
|
||||||
@ -226,10 +226,11 @@ impl<'a> LifetimeBounds<'a> {
|
|||||||
}).collect();
|
}).collect();
|
||||||
let ty_params = self.bounds.iter().map(|t| {
|
let ty_params = self.bounds.iter().map(|t| {
|
||||||
match t {
|
match t {
|
||||||
&(ref name, ref bounds) => {
|
&(ref name, sized, ref bounds) => {
|
||||||
mk_ty_param(cx,
|
mk_ty_param(cx,
|
||||||
span,
|
span,
|
||||||
*name,
|
*name,
|
||||||
|
sized,
|
||||||
bounds.as_slice(),
|
bounds.as_slice(),
|
||||||
self_ty,
|
self_ty,
|
||||||
self_generics)
|
self_generics)
|
||||||
|
@ -447,6 +447,7 @@ pub fn fold_ty_param<T: Folder>(tp: &TyParam, fld: &mut T) -> TyParam {
|
|||||||
TyParam {
|
TyParam {
|
||||||
ident: tp.ident,
|
ident: tp.ident,
|
||||||
id: id,
|
id: id,
|
||||||
|
sized: tp.sized,
|
||||||
bounds: tp.bounds.map(|x| fold_ty_param_bound(x, fld)),
|
bounds: tp.bounds.map(|x| fold_ty_param_bound(x, fld)),
|
||||||
default: tp.default.map(|x| fld.fold_ty(x)),
|
default: tp.default.map(|x| fld.fold_ty(x)),
|
||||||
span: tp.span
|
span: tp.span
|
||||||
@ -620,7 +621,7 @@ pub fn noop_fold_item_underscore<T: Folder>(i: &Item_, folder: &mut T) -> Item_
|
|||||||
methods.iter().map(|x| folder.fold_method(*x)).collect()
|
methods.iter().map(|x| folder.fold_method(*x)).collect()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ItemTrait(ref generics, ref traits, ref methods) => {
|
ItemTrait(ref generics, ref sized, ref traits, ref methods) => {
|
||||||
let methods = methods.iter().map(|method| {
|
let methods = methods.iter().map(|method| {
|
||||||
match *method {
|
match *method {
|
||||||
Required(ref m) => Required(folder.fold_type_method(m)),
|
Required(ref m) => Required(folder.fold_type_method(m)),
|
||||||
@ -628,6 +629,7 @@ pub fn noop_fold_item_underscore<T: Folder>(i: &Item_, folder: &mut T) -> Item_
|
|||||||
}
|
}
|
||||||
}).collect();
|
}).collect();
|
||||||
ItemTrait(fold_generics(generics, folder),
|
ItemTrait(fold_generics(generics, folder),
|
||||||
|
*sized,
|
||||||
traits.iter().map(|p| fold_trait_ref(p, folder)).collect(),
|
traits.iter().map(|p| fold_trait_ref(p, folder)).collect(),
|
||||||
methods)
|
methods)
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,7 @@ use ast::{PatIdent, PatLit, PatRange, PatRegion, PatStruct};
|
|||||||
use ast::{PatTup, PatUniq, PatWild, PatWildMulti};
|
use ast::{PatTup, PatUniq, PatWild, PatWildMulti};
|
||||||
use ast::{BiRem, Required};
|
use ast::{BiRem, Required};
|
||||||
use ast::{RetStyle, Return, BiShl, BiShr, Stmt, StmtDecl};
|
use ast::{RetStyle, Return, BiShl, BiShr, Stmt, StmtDecl};
|
||||||
|
use ast::{Sized, DynSize, StaticSize};
|
||||||
use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField};
|
use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField};
|
||||||
use ast::{StructVariantKind, BiSub};
|
use ast::{StructVariantKind, BiSub};
|
||||||
use ast::StrStyle;
|
use ast::StrStyle;
|
||||||
@ -3390,10 +3391,11 @@ impl<'a> Parser<'a> {
|
|||||||
return (ret_lifetime, Some(OwnedSlice::from_vec(result)));
|
return (ret_lifetime, Some(OwnedSlice::from_vec(result)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// matches typaram = IDENT optbounds ( EQ ty )?
|
// matches typaram = type? IDENT optbounds ( EQ ty )?
|
||||||
fn parse_ty_param(&mut self) -> TyParam {
|
fn parse_ty_param(&mut self) -> TyParam {
|
||||||
let ident = self.parse_ident();
|
let sized = self.parse_sized();
|
||||||
let span = self.span;
|
let span = self.span;
|
||||||
|
let ident = self.parse_ident();
|
||||||
let (_, opt_bounds) = self.parse_optional_ty_param_bounds(false);
|
let (_, opt_bounds) = self.parse_optional_ty_param_bounds(false);
|
||||||
// For typarams we don't care about the difference b/w "<T>" and "<T:>".
|
// For typarams we don't care about the difference b/w "<T>" and "<T:>".
|
||||||
let bounds = opt_bounds.unwrap_or_default();
|
let bounds = opt_bounds.unwrap_or_default();
|
||||||
@ -3407,6 +3409,7 @@ impl<'a> Parser<'a> {
|
|||||||
TyParam {
|
TyParam {
|
||||||
ident: ident,
|
ident: ident,
|
||||||
id: ast::DUMMY_NODE_ID,
|
id: ast::DUMMY_NODE_ID,
|
||||||
|
sized: sized,
|
||||||
bounds: bounds,
|
bounds: bounds,
|
||||||
default: default,
|
default: default,
|
||||||
span: span,
|
span: span,
|
||||||
@ -3797,6 +3800,7 @@ impl<'a> Parser<'a> {
|
|||||||
fn parse_item_trait(&mut self) -> ItemInfo {
|
fn parse_item_trait(&mut self) -> ItemInfo {
|
||||||
let ident = self.parse_ident();
|
let ident = self.parse_ident();
|
||||||
let tps = self.parse_generics();
|
let tps = self.parse_generics();
|
||||||
|
let sized = self.parse_for_sized();
|
||||||
|
|
||||||
// Parse traits, if necessary.
|
// Parse traits, if necessary.
|
||||||
let traits;
|
let traits;
|
||||||
@ -3808,7 +3812,7 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let meths = self.parse_trait_methods();
|
let meths = self.parse_trait_methods();
|
||||||
(ident, ItemTrait(tps, traits, meths), None)
|
(ident, ItemTrait(tps, sized, traits, meths), None)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parses two variants (with the region/type params always optional):
|
// Parses two variants (with the region/type params always optional):
|
||||||
@ -3999,6 +4003,23 @@ impl<'a> Parser<'a> {
|
|||||||
else { Inherited }
|
else { Inherited }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_sized(&mut self) -> Sized {
|
||||||
|
if self.eat_keyword(keywords::Type) { DynSize }
|
||||||
|
else { StaticSize }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_for_sized(&mut self) -> Sized {
|
||||||
|
if self.eat_keyword(keywords::For) {
|
||||||
|
if !self.eat_keyword(keywords::Type) {
|
||||||
|
self.span_err(self.last_span,
|
||||||
|
"expected 'type' after for in trait item");
|
||||||
|
}
|
||||||
|
DynSize
|
||||||
|
} else {
|
||||||
|
StaticSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// given a termination token and a vector of already-parsed
|
// given a termination token and a vector of already-parsed
|
||||||
// attributes (of length 0 or 1), parse all of the items in a module
|
// attributes (of length 0 or 1), parse all of the items in a module
|
||||||
fn parse_mod_items(&mut self,
|
fn parse_mod_items(&mut self,
|
||||||
|
@ -673,10 +673,13 @@ impl<'a> State<'a> {
|
|||||||
}
|
}
|
||||||
try!(self.bclose(item.span));
|
try!(self.bclose(item.span));
|
||||||
}
|
}
|
||||||
ast::ItemTrait(ref generics, ref traits, ref methods) => {
|
ast::ItemTrait(ref generics, ref sized, ref traits, ref methods) => {
|
||||||
try!(self.head(visibility_qualified(item.vis, "trait")));
|
try!(self.head(visibility_qualified(item.vis, "trait")));
|
||||||
try!(self.print_ident(item.ident));
|
try!(self.print_ident(item.ident));
|
||||||
try!(self.print_generics(generics));
|
try!(self.print_generics(generics));
|
||||||
|
if *sized == ast::DynSize {
|
||||||
|
try!(self.word_space("for type"));
|
||||||
|
}
|
||||||
if traits.len() != 0u {
|
if traits.len() != 0u {
|
||||||
try!(word(&mut self.s, ":"));
|
try!(word(&mut self.s, ":"));
|
||||||
for (i, trait_) in traits.iter().enumerate() {
|
for (i, trait_) in traits.iter().enumerate() {
|
||||||
@ -1910,6 +1913,9 @@ impl<'a> State<'a> {
|
|||||||
} else {
|
} else {
|
||||||
let idx = idx - generics.lifetimes.len();
|
let idx = idx - generics.lifetimes.len();
|
||||||
let param = generics.ty_params.get(idx);
|
let param = generics.ty_params.get(idx);
|
||||||
|
if param.sized == ast::DynSize {
|
||||||
|
try!(s.word_space("type"));
|
||||||
|
}
|
||||||
try!(s.print_ident(param.ident));
|
try!(s.print_ident(param.ident));
|
||||||
try!(s.print_bounds(&None, ¶m.bounds, false));
|
try!(s.print_bounds(&None, ¶m.bounds, false));
|
||||||
match param.default {
|
match param.default {
|
||||||
|
@ -257,7 +257,7 @@ pub fn walk_item<E: Clone, V: Visitor<E>>(visitor: &mut V, item: &Item, env: E)
|
|||||||
item.id,
|
item.id,
|
||||||
env)
|
env)
|
||||||
}
|
}
|
||||||
ItemTrait(ref generics, ref trait_paths, ref methods) => {
|
ItemTrait(ref generics, _, ref trait_paths, ref methods) => {
|
||||||
visitor.visit_generics(generics, env.clone());
|
visitor.visit_generics(generics, env.clone());
|
||||||
for trait_path in trait_paths.iter() {
|
for trait_path in trait_paths.iter() {
|
||||||
visitor.visit_path(&trait_path.path,
|
visitor.visit_path(&trait_path.path,
|
||||||
|
@ -12,6 +12,9 @@
|
|||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
#[lang="sized"]
|
||||||
|
pub trait Sized {}
|
||||||
|
|
||||||
struct S<T> {
|
struct S<T> {
|
||||||
contents: T,
|
contents: T,
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,9 @@
|
|||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
#[lang="sized"]
|
||||||
|
pub trait Sized {}
|
||||||
|
|
||||||
struct S {
|
struct S {
|
||||||
x : ~int
|
x : ~int
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,10 @@
|
|||||||
#![crate_type="lib"]
|
#![crate_type="lib"]
|
||||||
|
|
||||||
pub use foo2::Bar2;
|
pub use foo2::Bar2;
|
||||||
|
|
||||||
|
#[lang="sized"]
|
||||||
|
pub trait Sized {}
|
||||||
|
|
||||||
mod foo {
|
mod foo {
|
||||||
pub struct Bar; //~ ERROR: code is never used
|
pub struct Bar; //~ ERROR: code is never used
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,9 @@
|
|||||||
#![feature(globs)]
|
#![feature(globs)]
|
||||||
#![no_std] // makes debugging this test *a lot* easier (during resolve)
|
#![no_std] // makes debugging this test *a lot* easier (during resolve)
|
||||||
|
|
||||||
|
#[lang="sized"]
|
||||||
|
pub trait Sized {}
|
||||||
|
|
||||||
mod bar {
|
mod bar {
|
||||||
// shouln't bring in too much
|
// shouln't bring in too much
|
||||||
pub use self::glob::*;
|
pub use self::glob::*;
|
||||||
|
@ -10,5 +10,5 @@
|
|||||||
|
|
||||||
// error-pattern: instantiating a type parameter with an incompatible type
|
// error-pattern: instantiating a type parameter with an incompatible type
|
||||||
fn bar<T: Sized>() { }
|
fn bar<T: Sized>() { }
|
||||||
fn foo<T>() { bar::<T>() }
|
fn foo<type T>() { bar::<T>() }
|
||||||
fn main() { }
|
fn main() { }
|
||||||
|
@ -10,5 +10,5 @@
|
|||||||
|
|
||||||
// error-pattern: instantiating a type parameter with an incompatible type
|
// error-pattern: instantiating a type parameter with an incompatible type
|
||||||
fn bar<T: Sized>() { }
|
fn bar<T: Sized>() { }
|
||||||
fn foo<T>() { bar::<Option<T>>() }
|
fn foo<type T>() { bar::<Option<T>>() }
|
||||||
fn main() { }
|
fn main() { }
|
||||||
|
@ -13,5 +13,5 @@
|
|||||||
struct Foo<T> { data: T }
|
struct Foo<T> { data: T }
|
||||||
|
|
||||||
fn bar<T: Sized>() { }
|
fn bar<T: Sized>() { }
|
||||||
fn foo<T>() { bar::<Foo<T>>() }
|
fn foo<type T>() { bar::<Foo<T>>() }
|
||||||
fn main() { }
|
fn main() { }
|
||||||
|
16
src/test/compile-fail/unsized.rs
Normal file
16
src/test/compile-fail/unsized.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Test syntax checks for `type` keyword.
|
||||||
|
|
||||||
|
struct S1 for type; //~ ERROR expected `{`, `(`, or `;` after struct name but found `for`
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
}
|
17
src/test/compile-fail/unsized2.rs
Normal file
17
src/test/compile-fail/unsized2.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Test syntax checks for `type` keyword.
|
||||||
|
|
||||||
|
fn f<X>() {}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
f<type>(); //~ ERROR found `type` in ident position
|
||||||
|
}
|
51
src/test/compile-fail/unsized3.rs
Normal file
51
src/test/compile-fail/unsized3.rs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Test sized-ness checking in substitution.
|
||||||
|
|
||||||
|
// Unbounded.
|
||||||
|
fn f1<type X>(x: &X) {
|
||||||
|
f2::<X>(x); //~ ERROR instantiating a type parameter with an incompatible type `X`, which does n
|
||||||
|
}
|
||||||
|
fn f2<X>(x: &X) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bounded.
|
||||||
|
trait T for type {}
|
||||||
|
fn f3<type X: T>(x: &X) {
|
||||||
|
f4::<X>(x); //~ ERROR instantiating a type parameter with an incompatible type `X`, which does n
|
||||||
|
}
|
||||||
|
fn f4<X: T>(x: &X) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// I would like these to fail eventually.
|
||||||
|
/*
|
||||||
|
// impl - bounded
|
||||||
|
trait T1<Z: T> {
|
||||||
|
}
|
||||||
|
struct S3<type Y>;
|
||||||
|
impl<type X: T> T1<X> for S3<X> { //ERROR instantiating a type parameter with an incompatible type
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl - unbounded
|
||||||
|
trait T2<Z> {
|
||||||
|
}
|
||||||
|
impl<type X> T2<X> for S3<X> { //ERROR instantiating a type parameter with an incompatible type `X`
|
||||||
|
|
||||||
|
// impl - struct
|
||||||
|
trait T3<type Z> {
|
||||||
|
}
|
||||||
|
struct S4<Y>;
|
||||||
|
impl<type X> T3<X> for S4<X> { //ERROR instantiating a type parameter with an incompatible type `X`
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
}
|
19
src/test/compile-fail/unsized4.rs
Normal file
19
src/test/compile-fail/unsized4.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Test that bounds are sized-compatible.
|
||||||
|
|
||||||
|
trait T {}
|
||||||
|
fn f<type Y: T>() {
|
||||||
|
//~^ERROR incompatible bounds on type parameter Y, bound T does not allow unsized type
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
}
|
26
src/test/run-pass/unsized.rs
Normal file
26
src/test/run-pass/unsized.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Test syntax checks for `type` keyword.
|
||||||
|
|
||||||
|
trait T1 for type {}
|
||||||
|
pub trait T2 for type {}
|
||||||
|
trait T3<X: T1> for type: T2 {}
|
||||||
|
trait T4<type X> {}
|
||||||
|
trait T5<type X, Y> {}
|
||||||
|
trait T6<Y, type X> {}
|
||||||
|
trait T7<type X, type Y> {}
|
||||||
|
trait T8<type X: T2> {}
|
||||||
|
struct S1<type X>;
|
||||||
|
impl <type X> T1 for S1<X> {}
|
||||||
|
fn f<type X>() {}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
}
|
82
src/test/run-pass/unsized2.rs
Normal file
82
src/test/run-pass/unsized2.rs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Test sized-ness checking in substitution.
|
||||||
|
|
||||||
|
// Unbounded.
|
||||||
|
fn f1<type X>(x: &X) {
|
||||||
|
f1::<X>(x);
|
||||||
|
}
|
||||||
|
fn f2<X>(x: &X) {
|
||||||
|
f1::<X>(x);
|
||||||
|
f2::<X>(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bounded.
|
||||||
|
trait T for type {}
|
||||||
|
fn f3<type X: T>(x: &X) {
|
||||||
|
f3::<X>(x);
|
||||||
|
}
|
||||||
|
fn f4<X: T>(x: &X) {
|
||||||
|
f3::<X>(x);
|
||||||
|
f4::<X>(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Self type.
|
||||||
|
trait T2 for type {
|
||||||
|
fn f() -> ~Self;
|
||||||
|
}
|
||||||
|
struct S;
|
||||||
|
impl T2 for S {
|
||||||
|
fn f() -> ~S {
|
||||||
|
~S
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn f5<type X: T2>(x: &X) {
|
||||||
|
let _: ~X = T2::f();
|
||||||
|
}
|
||||||
|
fn f6<X: T2>(x: &X) {
|
||||||
|
let _: ~X = T2::f();
|
||||||
|
}
|
||||||
|
|
||||||
|
trait T3 for type {
|
||||||
|
fn f() -> ~Self;
|
||||||
|
}
|
||||||
|
impl T3 for S {
|
||||||
|
fn f() -> ~S {
|
||||||
|
~S
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn f7<type X: T3>(x: &X) {
|
||||||
|
// This is valid, but the unsized bound on X is irrelevant because any type
|
||||||
|
// which implements T3 must have statically known size.
|
||||||
|
let _: ~X = T3::f();
|
||||||
|
}
|
||||||
|
|
||||||
|
trait T4<X> {
|
||||||
|
fn m1(x: &T4<X>);
|
||||||
|
fn m2(x: &T5<X>);
|
||||||
|
}
|
||||||
|
trait T5<type X> {
|
||||||
|
fn m1(x: &T4<X>); // not an error (for now)
|
||||||
|
fn m2(x: &T5<X>);
|
||||||
|
}
|
||||||
|
|
||||||
|
trait T6<X: T> {
|
||||||
|
fn m1(x: &T4<X>);
|
||||||
|
fn m2(x: &T5<X>);
|
||||||
|
}
|
||||||
|
trait T7<type X: T> {
|
||||||
|
fn m1(x: &T4<X>); // not an error (for now)
|
||||||
|
fn m2(x: &T5<X>);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user